From 0a5cacdb9c25d79df02d7b201ab1f2277caceca3 Mon Sep 17 00:00:00 2001 From: Marcelo Lira Date: Sun, 6 Feb 2011 00:41:50 -0300 Subject: The option "avoid protected hack" is now set via command line. Instead of the old ugly way of compiling the behaviour forever using "#define". Reviewed by Hugo Parente Reviewed by Luciano Wolf --- CMakeLists.txt | 9 -- data/ShibokenConfig-spec.cmake.in | 7 -- data/shiboken.pc.in | 1 - generator/cppgenerator.cpp | 252 +++++++++++++++++-------------------- generator/headergenerator.cpp | 77 +++++------- generator/shibokengenerator.cpp | 129 ++++++++++--------- generator/shibokengenerator.h | 11 +- tests/CMakeLists.txt | 7 ++ tests/otherbinding/CMakeLists.txt | 2 +- tests/samplebinding/CMakeLists.txt | 2 +- 10 files changed, 224 insertions(+), 273 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc7a706d6..23a0b41ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,6 @@ set(shiboken_MINOR_VERSION "0") set(shiboken_MICRO_VERSION "0") set(shiboken_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}") -option(AVOID_PROTECTED_HACK "Avoid protected hack on generated bindings." FALSE) option(BUILD_TESTS "Build tests." TRUE) if(MSVC) @@ -48,14 +47,6 @@ else() set(PATH_SEP ":") endif() -if(WIN32 OR AVOID_PROTECTED_HACK) - message(STATUS "Avoiding protected hack!") - add_definitions("-DAVOID_PROTECTED_HACK") - set(AVOID_PROTECTED_HACK ON) -else() - message(STATUS "Using protected hack!") -endif() - # uninstall target configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" diff --git a/data/ShibokenConfig-spec.cmake.in b/data/ShibokenConfig-spec.cmake.in index 6e0372821..74c5f4e5f 100644 --- a/data/ShibokenConfig-spec.cmake.in +++ b/data/ShibokenConfig-spec.cmake.in @@ -21,11 +21,4 @@ SET(SHIBOKEN_PYTHON_BASENAME "@PYTHON_BASENAME@") message(STATUS "libshiboken built for @SHIBOKEN_BUILD_TYPE@") @SBK_ADD_PY_DEBUG_DEFINITION@ -# We don't use just "if (@AVOID_PROTECTED_HACK@)" to avoid require all users to turn on the cmake policy CMP0012 -# for more info type: cmake --help-policy CMP0012 -set(SHIBOKEN_AVOID_PROTECTED_HACK @AVOID_PROTECTED_HACK@) -if (SHIBOKEN_AVOID_PROTECTED_HACK) - add_definitions(-DAVOID_PROTECTED_HACK) - message(STATUS "Avoiding protected hack!") -endif() set(SHIBOKEN_BINARY "@CMAKE_INSTALL_PREFIX@/bin/@SHIBOKEN_GENERATOR@") diff --git a/data/shiboken.pc.in b/data/shiboken.pc.in index 5a88622d9..037288120 100644 --- a/data/shiboken.pc.in +++ b/data/shiboken.pc.in @@ -5,7 +5,6 @@ includedir=@CMAKE_INSTALL_PREFIX@/include/shiboken generator_location=@CMAKE_INSTALL_PREFIX@/bin/@SHIBOKEN_GENERATOR@ python_interpreter=@PYTHON_EXECUTABLE@ python_include_dir=@SBK_PYTHON_INCLUDE_DIR@ -avoid_protected_hack=@AVOID_PROTECTED_HACK@ Name: shiboken Description: Support library for Python bindings created with Shiboken generator. diff --git a/generator/cppgenerator.cpp b/generator/cppgenerator.cpp index d7ca1d8b4..e410ae521 100644 --- a/generator/cppgenerator.cpp +++ b/generator/cppgenerator.cpp @@ -216,12 +216,10 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl // write license comment s << licenseComment() << endl; -#ifndef AVOID_PROTECTED_HACK - if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) { + if (!avoidProtectedHack() && !metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) { s << "//workaround to access protected functions" << endl; s << "#define protected public" << endl << endl; } -#endif // headers s << "// default includes" << endl; @@ -304,14 +302,12 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl s << "// Native ---------------------------------------------------------" << endl; s << endl; -#ifdef AVOID_PROTECTED_HACK - if (usePySideExtensions()) { + if (avoidProtectedHack() && usePySideExtensions()) { s << "void " << wrapperName(metaClass) << "::pysideInitQtMetaTypes()\n{\n"; Indentation indent(INDENT); writeInitQtMetaTypeFunctionBody(s, metaClass); s << "}\n\n"; } -#endif foreach (const AbstractMetaFunction* func, filterFunctions(metaClass)) { if ((func->isPrivate() && !visibilityModifiedToPrivate(func)) @@ -319,26 +315,16 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl continue; if (func->isConstructor() && !func->isCopyConstructor() && !func->isUserAdded()) writeConstructorNative(s, func); -#ifdef AVOID_PROTECTED_HACK - else if (!metaClass->hasPrivateDestructor() && (func->isVirtual() || func->isAbstract())) -#else - else if (func->isVirtual() || func->isAbstract()) -#endif + else if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) + && (func->isVirtual() || func->isAbstract())) writeVirtualMethodNative(s, func); } -#ifdef AVOID_PROTECTED_HACK - if (!metaClass->hasPrivateDestructor()) { -#endif - - if (usePySideExtensions() && metaClass->isQObject()) - writeMetaObjectMethod(s, metaClass); - - writeDestructorNative(s, metaClass); - -#ifdef AVOID_PROTECTED_HACK + if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) { + if (usePySideExtensions() && metaClass->isQObject()) + writeMetaObjectMethod(s, metaClass); + writeDestructorNative(s, metaClass); } -#endif } Indentation indentation(INDENT); @@ -710,13 +696,13 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu ac << arg->name() << "_out"; } else { QString argName = arg->name(); -#ifdef AVOID_PROTECTED_HACK - const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(arg->type()); - if (metaEnum && metaEnum->isProtected()) { - argName.prepend(protectedEnumSurrogateName(metaEnum) + '('); - argName.append(')'); + if (avoidProtectedHack()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(arg->type()); + if (metaEnum && metaEnum->isProtected()) { + argName.prepend(protectedEnumSurrogateName(metaEnum) + '('); + argName.append(')'); + } } -#endif ac << (convert ? "(" : "") << argName << (convert ? ")" : ""); } @@ -779,11 +765,12 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu desiredType = '"' + reinterpret_cast(func->type()->typeEntry())->typeName() + '"'; } else { QString typeName = func->type()->typeEntry()->qualifiedCppName(); -#ifdef AVOID_PROTECTED_HACK - const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); - if (metaEnum && metaEnum->isProtected()) - typeName = protectedEnumSurrogateName(metaEnum); -#endif + if (avoidProtectedHack()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); + if (metaEnum && metaEnum->isProtected()) + typeName = protectedEnumSurrogateName(metaEnum); + } + if (func->type()->isPrimitive()) desiredType = "\"" + func->type()->name() + "\""; else @@ -814,28 +801,25 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu writeCodeSnips(s, convRule, CodeSnip::Any, TypeSystem::NativeCode, func); } else if (!injectedCodeHasReturnValueAttribution(func, TypeSystem::NativeCode)) { s << INDENT; -#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 + QString protectedEnumName; + if (avoidProtectedHack()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); + bool isProtectedEnum = metaEnum && metaEnum->isProtected(); + if (isProtectedEnum) { + protectedEnumName = metaEnum->name(); + if (metaEnum->enclosingClass()) + protectedEnumName = metaEnum->enclosingClass()->qualifiedCppName() + "::" + protectedEnumName; + s << protectedEnumName; + } + } + if (protectedEnumName.isEmpty()) s << translateTypeForWrapperMethod(func->type(), func->implementingClass()); s << " " CPP_RETURN_VAR "("; -#ifdef AVOID_PROTECTED_HACK - if (isProtectedEnum) - s << enumName << '('; -#endif + if (avoidProtectedHack() && !protectedEnumName.isEmpty()) + s << protectedEnumName << '('; writeToCppConversion(s, func->type(), func->implementingClass(), PYTHON_RETURN_VAR); -#ifdef AVOID_PROTECTED_HACK - if (isProtectedEnum) + if (avoidProtectedHack() && !protectedEnumName.isEmpty()) s << ')'; -#endif s << ')'; s << ';' << endl; } @@ -1179,13 +1163,13 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) { s << INDENT; -#ifdef AVOID_PROTECTED_HACK - QString _wrapperName = wrapperName(rfunc->ownerClass()); - bool hasProtectedMembers = rfunc->ownerClass()->hasProtectedMembers(); - s << (hasProtectedMembers ? _wrapperName : rfunc->ownerClass()->qualifiedCppName()); -#else - s << rfunc->ownerClass()->qualifiedCppName(); -#endif + QString protectedClassWrapperName; + if (avoidProtectedHack() && rfunc->ownerClass()->hasProtectedMembers()) { + protectedClassWrapperName = wrapperName(rfunc->ownerClass()); + s << protectedClassWrapperName; + } else { + s << rfunc->ownerClass()->qualifiedCppName(); + } s << "* " CPP_SELF_VAR " = 0;" << endl; if (rfunc->isOperatorOverload() && rfunc->isBinaryOperator()) { @@ -1198,9 +1182,8 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction // Sets the C++ "self" (the "this" for the object) if it has one. QString cppSelfAttribution = CPP_SELF_VAR " = "; -#ifdef AVOID_PROTECTED_HACK - cppSelfAttribution += (hasProtectedMembers ? QString("(%1*)").arg(_wrapperName) : ""); -#endif + if (avoidProtectedHack() && !protectedClassWrapperName.isEmpty()) + cppSelfAttribution += QString("(%1*)").arg(protectedClassWrapperName); cppSelfAttribution += cpythonWrapperCPtr(rfunc->ownerClass(), "self"); // Checks if the underlying C++ object is valid. @@ -1429,14 +1412,15 @@ void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunc return; s << INDENT; -#ifdef AVOID_PROTECTED_HACK - QString _wrapperName = wrapperName(func->ownerClass()); - bool hasProtectedMembers = func->ownerClass()->hasProtectedMembers(); - s << (hasProtectedMembers ? _wrapperName : func->ownerClass()->qualifiedCppName()) << "* " CPP_SELF_VAR " = "; - s << (hasProtectedMembers ? QString("(%1*)").arg(_wrapperName) : ""); -#else - s << func->ownerClass()->qualifiedCppName() << "* " CPP_SELF_VAR " = "; -#endif + if (avoidProtectedHack()) { + QString _wrapperName = wrapperName(func->ownerClass()); + bool hasProtectedMembers = func->ownerClass()->hasProtectedMembers(); + s << (hasProtectedMembers ? _wrapperName : func->ownerClass()->qualifiedCppName()); + s << "* " CPP_SELF_VAR " = "; + s << (hasProtectedMembers ? QString("(%1*)").arg(_wrapperName) : ""); + } else { + s << func->ownerClass()->qualifiedCppName() << "* " CPP_SELF_VAR " = "; + } s << cpythonWrapperCPtr(func->ownerClass(), "self") << ';' << endl; if (func->isUserAdded()) s << INDENT << "(void)" CPP_SELF_VAR "; // avoid warnings about unused variables" << endl; @@ -2097,21 +2081,22 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f mc << ')'; } else { if (func->ownerClass()) { -#ifdef AVOID_PROTECTED_HACK - if (!func->isProtected()) { -#endif - if (func->isStatic()) + if (!avoidProtectedHack() || !func->isProtected()) { + if (func->isStatic()) { mc << func->ownerClass()->qualifiedCppName() << "::"; - else { + } else { if (func->isConstant()) { -#ifdef AVOID_PROTECTED_HACK - mc << "const_castownerClass()->hasProtectedMembers(); - mc << (hasProtectedMembers ? wrapperName(func->ownerClass()) : func->ownerClass()->qualifiedCppName()); - mc << "*>(" CPP_SELF_VAR ")->"; -#else - mc << "const_castownerClass()->qualifiedCppName() << "*>(" CPP_SELF_VAR ")->"; -#endif + if (avoidProtectedHack()) { + mc << "const_castownerClass()->hasProtectedMembers()) + mc << wrapperName(func->ownerClass()); + else + mc << func->ownerClass()->qualifiedCppName(); + mc << "*>(" CPP_SELF_VAR ")->"; + } else { + mc << "const_castownerClass()->qualifiedCppName(); + mc << "*>(" CPP_SELF_VAR ")->"; + } } else { mc << CPP_SELF_VAR "->"; } @@ -2121,8 +2106,6 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f mc << "::%CLASS_NAME::"; mc << func->originalName(); - -#ifdef AVOID_PROTECTED_HACK } else { if (!func->isStatic()) mc << "((" << wrapperName(func->ownerClass()) << "*) " << CPP_SELF_VAR << ")->"; @@ -2131,28 +2114,21 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f mc << (func->isProtected() ? wrapperName(func->ownerClass()) : "::" + func->ownerClass()->qualifiedCppName()) << "::"; mc << func->originalName() << "_protected"; } -#endif } else { mc << func->originalName(); } mc << '(' << userArgs.join(", ") << ')'; if (!func->isAbstract() && func->isVirtual()) { mc.flush(); -#ifdef AVOID_PROTECTED_HACK - if (!func->isProtected()) -#endif - { + if (!avoidProtectedHack() || !func->isProtected()) { QString virtualCall(methodCall); QString normalCall(methodCall); - virtualCall = virtualCall.replace("%CLASS_NAME", func->ownerClass()->qualifiedCppName()); normalCall = normalCall.replace("::%CLASS_NAME::", ""); methodCall = ""; - - virtualCall = virtualCall.replace("%CLASS_NAME", func->ownerClass()->qualifiedCppName()); - normalCall = normalCall.replace("::%CLASS_NAME::", ""); - methodCall = ""; - mc << "(Shiboken::Object::isUserType(self) ? " << virtualCall << ":" << normalCall << ")"; + mc << "(Shiboken::Object::isUserType(self) ? "; + mc << virtualCall << " : " << normalCall << ")"; + } } } } @@ -2162,19 +2138,22 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f if (isCtor) { s << "cptr = "; } 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 + bool writeReturnType = true; + if (avoidProtectedHack()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); + if (metaEnum) { + QString enumName; + if (metaEnum->isProtected()) + enumName = protectedEnumSurrogateName(metaEnum); + else + enumName = func->type()->cppSignature(); + methodCall.prepend(enumName + '('); + methodCall.append(')'); + s << enumName; + writeReturnType = false; + } + } + if (writeReturnType) s << func->type()->cppSignature(); s << " " CPP_RETURN_VAR " = "; } @@ -2795,18 +2774,17 @@ void CppGenerator::writeGetterFunction(QTextStream& s, const AbstractMetaField* !metaType->isPrimitive() && metaType->indirections() == 0); -#ifdef AVOID_PROTECTED_HACK - if (metaField->isProtected()) + if (avoidProtectedHack() && metaField->isProtected()) { cppField = QString("((%1*)%2)->%3()") - .arg(wrapperName(metaField->enclosingClass())) - .arg(cpythonWrapperCPtr(metaField->enclosingClass(), "self")) - .arg(protectedFieldGetterName(metaField)); - else -#endif - cppField= QString("%1%2->%3") - .arg(useReference ? '&' : ' ') - .arg(cpythonWrapperCPtr(metaField->enclosingClass(), "self")) - .arg(metaField->name()); + .arg(wrapperName(metaField->enclosingClass())) + .arg(cpythonWrapperCPtr(metaField->enclosingClass(), "self")) + .arg(protectedFieldGetterName(metaField)); + } else { + cppField = QString("%1%2->%3") + .arg(useReference ? '&' : ' ') + .arg(cpythonWrapperCPtr(metaField->enclosingClass(), "self")) + .arg(metaField->name()); + } if (useReference) { s << "Shiboken::createWrapper(" << cppField << ");" << endl; @@ -2846,20 +2824,21 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField* s << INDENT << '}' << endl << endl; s << INDENT; -#ifdef AVOID_PROTECTED_HACK - if (metaField->isProtected()) { - QString fieldStr = QString("((%1*)%2)->%3").arg(wrapperName(metaField->enclosingClass())).arg(cpythonWrapperCPtr(metaField->enclosingClass(), "self")).arg(protectedFieldSetterName(metaField)); + if (avoidProtectedHack() && metaField->isProtected()) { + QString fieldStr = QString("((%1*)%2)->%3") + .arg(wrapperName(metaField->enclosingClass())) + .arg(cpythonWrapperCPtr(metaField->enclosingClass(), "self")) + .arg(protectedFieldSetterName(metaField)); s << fieldStr << '('; writeToCppConversion(s, metaField->type(), metaField->enclosingClass(), "value"); s << ')'; } else { -#endif - QString fieldStr = QString("%1->%2").arg(cpythonWrapperCPtr(metaField->enclosingClass(), "self")).arg(metaField->name()); + QString fieldStr = QString("%1->%2") + .arg(cpythonWrapperCPtr(metaField->enclosingClass(), "self")) + .arg(metaField->name()); s << fieldStr << " = "; writeToCppConversion(s, metaField->type(), metaField->enclosingClass(), "value"); -#ifdef AVOID_PROTECTED_HACK } -#endif s << ';' << endl << endl; @@ -3082,18 +3061,14 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu continue; QString enumValueText; -#ifdef AVOID_PROTECTED_HACK - if (!cppEnum->isProtected()) { -#endif + if (!avoidProtectedHack() || !cppEnum->isProtected()) { enumValueText = "(long) "; if (cppEnum->enclosingClass()) enumValueText += cppEnum->enclosingClass()->qualifiedCppName() + "::"; enumValueText += enumValue->name(); -#ifdef AVOID_PROTECTED_HACK } else { enumValueText += QString::number(enumValue->value()); } -#endif bool shouldDecrefNumber = false; QString enumItemText = "enumItem"; @@ -3430,10 +3405,12 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m // Fill destrutor QString dtorClassName = metaClass->qualifiedCppName(); if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) { -#ifdef AVOID_PROTECTED_HACK - if (metaClass->hasProtectedDestructor()) + if (avoidProtectedHack() && metaClass->hasProtectedDestructor()) + dtorClassName = wrapperName(metaClass); + // call the real destructor + if (metaClass->typeEntry()->isValue()) dtorClassName = wrapperName(metaClass); -#endif + s << INDENT << "Shiboken::ObjectType::setDestructorFunction(&" << cpythonTypeName(metaClass) << ", &Shiboken::callCppDestructor<" << dtorClassName << " >);" << endl; } @@ -3507,17 +3484,12 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m writeRegisterType(s, metaClass); if (usePySideExtensions()) { -#ifdef AVOID_PROTECTED_HACK - if (shouldGenerateCppWrapper(metaClass)) + if (avoidProtectedHack() && shouldGenerateCppWrapper(metaClass)) s << INDENT << wrapperName(metaClass) << "::pysideInitQtMetaTypes();\n"; else writeInitQtMetaTypeFunctionBody(s, metaClass); -#else - writeInitQtMetaTypeFunctionBody(s, metaClass); -#endif } - s << '}' << endl << endl; } diff --git a/generator/headergenerator.cpp b/generator/headergenerator.cpp index b52bf7c92..3b0de4fd3 100644 --- a/generator/headergenerator.cpp +++ b/generator/headergenerator.cpp @@ -86,9 +86,8 @@ void HeaderGenerator::generateClass(QTextStream& s, const AbstractMetaClass* met s << "#ifndef SBK_" << headerGuard << "_H" << endl; s << "#define SBK_" << headerGuard << "_H" << endl<< endl; -#ifndef AVOID_PROTECTED_HACK - s << "#define protected public" << endl << endl; -#endif + if (!avoidProtectedHack()) + s << "#define protected public" << endl << endl; s << "#include " << endl << endl; @@ -113,37 +112,30 @@ void HeaderGenerator::generateClass(QTextStream& s, const AbstractMetaClass* met writeFunction(s, func); } -#ifdef AVOID_PROTECTED_HACK - if (metaClass->hasProtectedFields()) { + if (avoidProtectedHack() && metaClass->hasProtectedFields()) { foreach (AbstractMetaField* field, metaClass->fields()) { if (!field->isProtected()) continue; writeProtectedFieldAccessors(s, field); } } -#endif //destructor -#ifdef AVOID_PROTECTED_HACK - if (!metaClass->hasPrivateDestructor()) -#endif - s << INDENT << (metaClass->hasVirtualDestructor() || hasVirtualFunction ? "virtual " : "") << "~" << wrapperName << "();" << endl; + if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) { + s << INDENT; + if (metaClass->hasVirtualDestructor() || hasVirtualFunction) + s << "virtual "; + s << "~" << wrapperName << "();" << endl; + } writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::Declaration, TypeSystem::NativeCode); -#ifdef AVOID_PROTECTED_HACK - if (!metaClass->hasPrivateDestructor()) { -#endif - - if (usePySideExtensions() && metaClass->isQObject()) { + if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) + && usePySideExtensions() && metaClass->isQObject()) { s << "public:\n"; s << INDENT << "virtual int qt_metacall(QMetaObject::Call call, int id, void** args);\n"; } -#ifdef AVOID_PROTECTED_HACK - } -#endif - if (m_inheritedOverloads.size()) { s << INDENT << "// Inherited overloads, because the using keyword sux" << endl; writeInheritedOverloads(s); @@ -169,8 +161,7 @@ void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* if (func->isUserAdded()) return; -#ifdef AVOID_PROTECTED_HACK - if (func->isProtected() && !func->isConstructor() && !func->isOperatorOverload()) { + if (avoidProtectedHack() && func->isProtected() && !func->isConstructor() && !func->isOperatorOverload()) { s << INDENT << "inline " << (func->isStatic() ? "static " : ""); s << functionSignature(func, "", "_protected", Generator::EnumAsInts|Generator::OriginalTypeDescription) << " { "; s << (func->type() ? "return " : ""); @@ -192,17 +183,15 @@ void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* s << args.join(", ") << ')'; s << "; }" << endl; } -#endif // pure virtual functions need a default implementation if ((func->isPrivate() && !visibilityModifiedToPrivate(func)) || (func->isModifiedRemoved() && !func->isAbstract())) return; -#ifdef AVOID_PROTECTED_HACK - if (func->ownerClass()->hasPrivateDestructor() && (func->isAbstract() || func->isVirtual())) + if (avoidProtectedHack() && func->ownerClass()->hasPrivateDestructor() + && (func->isAbstract() || func->isVirtual())) return; -#endif if (func->isConstructor() || func->isAbstract() || func->isVirtual()) { s << INDENT; @@ -252,13 +241,14 @@ void HeaderGenerator::writeTypeConverterDecl(QTextStream& s, const TypeEntry* ty QString typeT = type->qualifiedCppName() + (isAbstractOrObjectType ? "*" : ""); QString typeName = type->qualifiedCppName(); -#ifdef AVOID_PROTECTED_HACK - const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(type); - if (metaEnum && metaEnum->isProtected()) { - typeT = protectedEnumSurrogateName(metaEnum); - typeName = typeT; + if (avoidProtectedHack()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(type); + if (metaEnum && metaEnum->isProtected()) { + typeT = protectedEnumSurrogateName(metaEnum); + typeName = typeT; + } } -#endif + typeT.prepend("::"); typeName.prepend("::"); @@ -417,10 +407,10 @@ void HeaderGenerator::finishGeneration() s << "#ifndef " << includeShield << endl; s << "#define " << includeShield << endl<< endl; - #ifndef AVOID_PROTECTED_HACK - s << "//workaround to access protected functions" << endl; - s << "#define protected public" << endl << endl; - #endif + if (!avoidProtectedHack()) { + s << "//workaround to access protected functions" << endl; + s << "#define protected public" << endl << endl; + } s << "#include " << endl; s << "#include " << endl; @@ -510,21 +500,20 @@ void HeaderGenerator::finishGeneration() void HeaderGenerator::writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum) { -#ifdef AVOID_PROTECTED_HACK - if (cppEnum->isProtected()) + if (avoidProtectedHack() && cppEnum->isProtected()) s << "enum " << protectedEnumSurrogateName(cppEnum) << " {};" << endl; -#endif } void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum) { - QString enumName = cppEnum->name(); - if (cppEnum->enclosingClass()) - enumName = cppEnum->enclosingClass()->qualifiedCppName() + "::" + enumName; -#ifdef AVOID_PROTECTED_HACK - if (cppEnum->isProtected()) + QString enumName; + if (avoidProtectedHack() && cppEnum->isProtected()) { enumName = protectedEnumSurrogateName(cppEnum); -#endif + } else { + enumName = cppEnum->name(); + if (cppEnum->enclosingClass()) + enumName = cppEnum->enclosingClass()->qualifiedCppName() + "::" + enumName; + } s << "template<> inline PyTypeObject* SbkType< ::" << enumName << " >() "; s << "{ return " << cpythonTypeNameExt(cppEnum->typeEntry()) << "; }\n"; diff --git a/generator/shibokengenerator.cpp b/generator/shibokengenerator.cpp index 79b19bce1..8d8cd4230 100644 --- a/generator/shibokengenerator.cpp +++ b/generator/shibokengenerator.cpp @@ -31,6 +31,7 @@ #include #define NULL_VALUE "NULL" +#define AVOID_PROTECTED_HACK "avoid-protected-hack" #define PARENT_CTOR_HEURISTIC "enable-parent-ctor-heuristic" #define RETURN_VALUE_HEURISTIC "enable-return-value-heuristic" #define ENABLE_PYSIDE_EXTENSIONS "enable-pyside-extensions" @@ -176,46 +177,39 @@ QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType* const AbstractMetaClass* context, Options options) const { - QString result; + if (cType->isArray()) + return translateTypeForWrapperMethod(cType->arrayElementType(), context, options) + "[]"; - if (cType->isArray()) { - result = translateTypeForWrapperMethod(cType->arrayElementType(), context, options) + "[]"; - } 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, options); + if (avoidProtectedHack() && cType->isEnum()) { + const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(cType); + if (metaEnum && metaEnum->isProtected()) + return protectedEnumSurrogateName(metaEnum); } - return result; + return translateType(cType, context, options); } -bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) +bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) const { bool result = metaClass->isPolymorphic() || metaClass->hasVirtualDestructor(); -#ifdef AVOID_PROTECTED_HACK - result = result || metaClass->hasProtectedFields() || metaClass->hasProtectedDestructor(); - if (!result && metaClass->hasProtectedFunctions()) { - int protectedFunctions = 0; - int protectedOperators = 0; - foreach (const AbstractMetaFunction* func, metaClass->functions()) { - if (!func->isProtected() || func->isSignal() || func->isModifiedRemoved()) - continue; - else if (func->isOperatorOverload()) - protectedOperators++; - else - protectedFunctions++; + if (avoidProtectedHack()) { + result = result || metaClass->hasProtectedFields() || metaClass->hasProtectedDestructor(); + if (!result && metaClass->hasProtectedFunctions()) { + int protectedFunctions = 0; + int protectedOperators = 0; + foreach (const AbstractMetaFunction* func, metaClass->functions()) { + if (!func->isProtected() || func->isSignal() || func->isModifiedRemoved()) + continue; + else if (func->isOperatorOverload()) + protectedOperators++; + else + protectedFunctions++; + } + result = result || (protectedFunctions > protectedOperators); } - result = result || (protectedFunctions > protectedOperators); + } else { + result = result && !metaClass->hasPrivateDestructor(); } -#else - result = result && !metaClass->hasPrivateDestructor(); -#endif return result && !metaClass->isNamespace(); } @@ -251,7 +245,7 @@ const AbstractMetaClass* ShibokenGenerator::getProperEnclosingClassForEnum(const return getProperEnclosingClass(metaEnum->enclosingClass()); } -QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) +QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const { if (shouldGenerateCppWrapper(metaClass)) { QString result = metaClass->name(); @@ -511,18 +505,19 @@ static QString baseConversionString(QString typeName) void ShibokenGenerator::writeBaseConversion(QTextStream& s, const TypeEntry* type) { - QString typeName = type->qualifiedCppName().trimmed(); - if (!type->isCppPrimitive()) - typeName.prepend("::"); - if (type->isObject()) - typeName.append('*'); -#ifdef AVOID_PROTECTED_HACK - if (type->isEnum()) { + QString typeName; + + if (avoidProtectedHack() && type->isEnum()) { const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(type); if (metaEnum && metaEnum->isProtected()) typeName = protectedEnumSurrogateName(metaEnum); + } else { + typeName = type->qualifiedCppName().trimmed(); + if (!type->isCppPrimitive()) + typeName.prepend("::"); + if (type->isObject()) + typeName.append('*'); } -#endif s << baseConversionString(typeName); } @@ -1073,15 +1068,10 @@ AbstractMetaFunctionList ShibokenGenerator::filterFunctions(const AbstractMetaCl AbstractMetaFunctionList result; foreach (AbstractMetaFunction *func, metaClass->functions()) { //skip signals - if (func->isSignal() - || func->isDestructor() -#ifndef AVOID_PROTECTED_HACK - || (func->isModifiedRemoved() && !func->isAbstract())) { -#else - || (func->isModifiedRemoved() && !func->isAbstract() && !func->isProtected())) { -#endif + if (func->isSignal() || func->isDestructor() + || (func->isModifiedRemoved() && !func->isAbstract() + && (!avoidProtectedHack() || !func->isProtected()))) continue; - } result << func; } return result; @@ -1304,26 +1294,26 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, code.replace("%PYTHON_METHOD_OVERRIDE", "py_override"); } -#ifdef AVOID_PROTECTED_HACK - // If the function being processed was added by the user via type system, - // Shiboken needs to find out if there are other overloads for the same method - // name and if any of them is of the protected visibility. This is used to replace - // calls to %FUNCTION_NAME on user written custom code for calls to the protected - // dispatcher. - bool hasProtectedOverload = false; - if (func->isUserAdded()) { - foreach (const AbstractMetaFunction* f, getFunctionOverloads(func->ownerClass(), func->name())) - hasProtectedOverload |= f->isProtected(); - } + if (avoidProtectedHack()) { + // If the function being processed was added by the user via type system, + // Shiboken needs to find out if there are other overloads for the same method + // name and if any of them is of the protected visibility. This is used to replace + // calls to %FUNCTION_NAME on user written custom code for calls to the protected + // dispatcher. + bool hasProtectedOverload = false; + if (func->isUserAdded()) { + foreach (const AbstractMetaFunction* f, getFunctionOverloads(func->ownerClass(), func->name())) + hasProtectedOverload |= f->isProtected(); + } - if (func->isProtected() || hasProtectedOverload) { - code.replace("%TYPE::%FUNCTION_NAME", - QString("%1::%2_protected") - .arg(wrapperName(func->ownerClass())) - .arg(func->originalName())); - code.replace("%FUNCTION_NAME", QString("%1_protected").arg(func->originalName())); + if (func->isProtected() || hasProtectedOverload) { + code.replace("%TYPE::%FUNCTION_NAME", + QString("%1::%2_protected") + .arg(wrapperName(func->ownerClass())) + .arg(func->originalName())); + code.replace("%FUNCTION_NAME", QString("%1_protected").arg(func->originalName())); + } } -#endif if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass())) code.replace("%TYPE", wrapperName(func->ownerClass())); @@ -1631,6 +1621,7 @@ QPair< int, int > ShibokenGenerator::getMinMaxArguments(const AbstractMetaFuncti QMap ShibokenGenerator::options() const { QMap opts(Generator::options()); + opts.insert(AVOID_PROTECTED_HACK, "Avoid the use of the '#define protected public' hack."); opts.insert(PARENT_CTOR_HEURISTIC, "Enable heuristics to detect parent relationship on constructors."); opts.insert(RETURN_VALUE_HEURISTIC, "Enable heuristics to detect parent relationship on return values (USE WITH CAUTION!)"); opts.insert(ENABLE_PYSIDE_EXTENSIONS, "Enable PySide extensions, such as support for signal/slots, use this if you are creating a binding for a Qt-based library."); @@ -1646,6 +1637,7 @@ bool ShibokenGenerator::doSetup(const QMap& args) m_userReturnValueHeuristic = args.contains(RETURN_VALUE_HEURISTIC); m_verboseErrorMessagesDisabled = args.contains(DISABLE_VERBOSE_ERROR_MESSAGES); m_useIsNullAsNbNonZero = args.contains(USE_ISNULL_AS_NB_NONZERO); + m_avoidProtectedHack = args.contains(AVOID_PROTECTED_HACK); return true; } @@ -1669,6 +1661,11 @@ bool ShibokenGenerator::useIsNullAsNbNonZero() const return m_useIsNullAsNbNonZero; } +bool ShibokenGenerator::avoidProtectedHack() const +{ + return m_avoidProtectedHack; +} + QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const { QString result = moduleName.isEmpty() ? ShibokenGenerator::packageName() : moduleName; diff --git a/generator/shibokengenerator.h b/generator/shibokengenerator.h index a238b2c02..c660f2efd 100644 --- a/generator/shibokengenerator.h +++ b/generator/shibokengenerator.h @@ -207,14 +207,14 @@ public: void writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass, const QString& argumentName); /// Verifies if the class should have a C++ wrapper generated for it, instead of only a Python wrapper. - static bool shouldGenerateCppWrapper(const AbstractMetaClass* metaClass); + bool shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) const; /// Adds enums eligible for generation from classes/namespaces marked not to be generated. static void lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList& enumList, const AbstractMetaClass* metaClass); /// Returns the enclosing class for an enum, or NULL if it should be global. const AbstractMetaClass* getProperEnclosingClassForEnum(const AbstractMetaEnum* metaEnum); - static QString wrapperName(const AbstractMetaClass* metaClass); + QString wrapperName(const AbstractMetaClass* metaClass) const; static QString fullPythonFunctionName(const AbstractMetaFunction* func); static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum); @@ -310,8 +310,10 @@ public: bool useReturnValueHeuristic() const; /// Returns true if the user enabled PySide extensions. bool usePySideExtensions() const; - /// Return true if the generator should use the result of isNull()const to compute boolean casts. + /// Returns true if the generator should use the result of isNull()const to compute boolean casts. bool useIsNullAsNbNonZero() const; + /// Returns true if the generated code should use the "#define protected public" hack. + bool avoidProtectedHack() const; QString cppApiVariableName(const QString& moduleName = QString()) const; QString getTypeIndexVariableName(const TypeEntry* metaType); /// Returns true if the user don't want verbose error messages on the generated bindings. @@ -354,7 +356,7 @@ protected: const AbstractMetaFunction* metaFunc, Options options = NoOption) const; - static AbstractMetaFunctionList filterFunctions(const AbstractMetaClass* metaClass); + AbstractMetaFunctionList filterFunctions(const AbstractMetaClass* metaClass); // All data about extended converters: the type entries of the target type, and a // list of AbstractMetaClasses accepted as argument for the conversion. @@ -372,6 +374,7 @@ private: bool m_usePySideExtensions; bool m_verboseErrorMessagesDisabled; bool m_useIsNullAsNbNonZero; + bool m_avoidProtectedHack; }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dc7c69f68..b9d60262f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,13 @@ add_subdirectory(libsample) add_subdirectory(libother) +if(WIN32 OR DEFINED AVOID_PROTECTED_HACK) + message(STATUS "Tests will be generated avoiding the protected hack!") + set(GENERATOR_EXTRA_FLAGS --avoid-protected-hack) +else() + message(STATUS "Tests will be generated using the protected hack!") + set(GENERATOR_EXTRA_FLAGS ) +endif() add_subdirectory(samplebinding) add_subdirectory(otherbinding) diff --git a/tests/otherbinding/CMakeLists.txt b/tests/otherbinding/CMakeLists.txt index 5a859679a..366bdbd55 100644 --- a/tests/otherbinding/CMakeLists.txt +++ b/tests/otherbinding/CMakeLists.txt @@ -18,7 +18,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/other-binding.txt.in" "${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt" @ONLY) add_custom_command(OUTPUT ${other_SRC} -COMMAND ${GENERATORRUNNER_BINARY} --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt +COMMAND ${GENERATORRUNNER_BINARY} --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt ${GENERATOR_EXTRA_FLAGS} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Running generator for 'other' test binding..." ) diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index abe982aab..e21c22864 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -92,7 +92,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sample-binding.txt.in" "${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt" @ONLY) add_custom_command(OUTPUT ${sample_SRC} -COMMAND ${GENERATORRUNNER_BINARY} --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt +COMMAND ${GENERATORRUNNER_BINARY} --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt ${GENERATOR_EXTRA_FLAGS} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Running generator for 'sample' test binding..." ) -- cgit v1.2.3