summaryrefslogtreecommitdiffstats
path: root/generator
diff options
context:
space:
mode:
authorHugo Parente Lima <hugo.pl@gmail.com>2010-09-20 17:26:09 -0300
committerHugo Parente Lima <hugo.pl@gmail.com>2010-09-20 17:33:18 -0300
commit231253beff97ce9d81d63ee437b833cc73ed1142 (patch)
treef3a1bd609b7e4c97aa17133a52666379ac8eb32d /generator
parenta02e6fff64cdfcf2022c73d03d779a2584544842 (diff)
downloadshiboken-231253beff97ce9d81d63ee437b833cc73ed1142.tar.gz
shiboken-231253beff97ce9d81d63ee437b833cc73ed1142.tar.xz
shiboken-231253beff97ce9d81d63ee437b833cc73ed1142.zip
Shiboken generator code moved to the directory generator.
Reviewer: Renato Ara├║jo <renato.filho@openbossa.org> Luciano Wolf <luciano.wolf@openbossa.org>
Diffstat (limited to 'generator')
-rw-r--r--generator/cppgenerator.cpp3849
-rw-r--r--generator/cppgenerator.h201
-rw-r--r--generator/headergenerator.cpp610
-rw-r--r--generator/headergenerator.h58
-rw-r--r--generator/main.cpp34
-rw-r--r--generator/overloaddata.cpp788
-rw-r--r--generator/overloaddata.h147
-rw-r--r--generator/shiboken.cpp27
-rw-r--r--generator/shibokengenerator.cpp1651
-rw-r--r--generator/shibokengenerator.h364
10 files changed, 7729 insertions, 0 deletions
diff --git a/generator/cppgenerator.cpp b/generator/cppgenerator.cpp
new file mode 100644
index 00000000..2df2bae9
--- /dev/null
+++ b/generator/cppgenerator.cpp
@@ -0,0 +1,3849 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009-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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 "cppgenerator.h"
+#include <reporthandler.h>
+#include <typedatabase.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+
+inline CodeSnipList getConversionRule(TypeSystem::Language lang, const AbstractMetaFunction *function)
+{
+ CodeSnipList list;
+
+ foreach(AbstractMetaArgument *arg, function->arguments()) {
+ QString convRule = function->conversionRule(lang, arg->argumentIndex() + 1);
+ if (!convRule.isEmpty()) {
+ CodeSnip snip(0, TypeSystem::TargetLangCode);
+ snip.position = CodeSnip::Beginning;
+
+ convRule.replace("%in", arg->name());
+ convRule.replace("%out", arg->name() + "_out");
+
+ snip.addCode(convRule);
+ list << snip;
+ }
+
+ }
+ return list;
+}
+
+// utiliy functions
+inline CodeSnipList getReturnConversionRule(TypeSystem::Language lang,
+ const AbstractMetaFunction *function,
+ const QString& inputName,
+ const QString& outputName)
+{
+ CodeSnipList list;
+
+ QString convRule = function->conversionRule(lang, 0);
+ if (!convRule.isEmpty()) {
+ CodeSnip snip(0, lang);
+ snip.position = CodeSnip::Beginning;
+
+ convRule.replace("%in", inputName);
+ convRule.replace("%out", outputName);
+
+ snip.addCode(convRule);
+ list << snip;
+ }
+
+ return list;
+}
+
+
+CppGenerator::CppGenerator() : m_currentErrorCode(0)
+{
+ // sequence protocol functions
+ typedef QPair<QString, QString> StrPair;
+ m_sequenceProtocol.insert("__len__", StrPair("PyObject* self", "Py_ssize_t"));
+ m_sequenceProtocol.insert("__getitem__", StrPair("PyObject* self, Py_ssize_t _i", "PyObject*"));
+ m_sequenceProtocol.insert("__setitem__", StrPair("PyObject* self, Py_ssize_t _i, PyObject* _value", "int"));
+ m_sequenceProtocol.insert("__getslice__", StrPair("PyObject* self, Py_ssize_t _i1, Py_ssize_t _i2", "PyObject*"));
+ m_sequenceProtocol.insert("__setslice__", StrPair("PyObject* self, Py_ssize_t _i1, Py_ssize_t _i2, PyObject* _value", "int"));
+ m_sequenceProtocol.insert("__contains__", StrPair("PyObject* self, PyObject* _value", "int"));
+ m_sequenceProtocol.insert("__concat__", StrPair("PyObject* self, PyObject* _other", "PyObject*"));
+}
+
+QString CppGenerator::fileNameForClass(const AbstractMetaClass *metaClass) const
+{
+ return metaClass->qualifiedCppName().toLower().replace("::", "_") + QLatin1String("_wrapper.cpp");
+}
+
+QList<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass,
+ uint query)
+{
+ // ( func_name, num_args ) => func_list
+ QMap<QPair<QString, int >, AbstractMetaFunctionList> results;
+ foreach (AbstractMetaFunction* func, metaClass->operatorOverloads(query)) {
+ if (func->isModifiedRemoved() || func->name() == "operator[]" || func->name() == "operator->")
+ continue;
+ int args;
+ if (func->isComparisonOperator()) {
+ args = -1;
+ } else {
+ args = func->arguments().size();
+ }
+ QPair<QString, int > op(func->name(), args);
+ results[op].append(func);
+ }
+ return results.values();
+}
+
+/*!
+ Function used to write the class generated binding code on the buffer
+ \param s the output buffer
+ \param metaClass the pointer to metaclass information
+*/
+void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaClass)
+{
+ ReportHandler::debugSparse("Generating wrapper implementation for " + metaClass->fullName());
+
+ // write license comment
+ s << licenseComment() << endl;
+
+#ifndef AVOID_PROTECTED_HACK
+ if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
+ s << "//workaround to access protected functions" << endl;
+ s << "#define protected public" << endl << endl;
+ }
+#endif
+
+ // headers
+ s << "// default includes" << endl;
+ s << "#include <shiboken.h>" << endl;
+ if (usePySideExtensions()) {
+ s << "#include <qsignal.h>" << endl;
+ s << "#include <qproperty.h>" << endl;
+ s << "#include <pyside.h>" << endl;
+ }
+
+ s << "#include <typeresolver.h>\n";
+ s << "#include <typeinfo>\n";
+ if (usePySideExtensions()) {
+ if (metaClass->isQObject()) {
+ s << "#include <signalmanager.h>\n";
+ s << "#include <dynamicqmetaobject.h>\n";
+ }
+ }
+
+ // The multiple inheritance initialization function
+ // needs the 'set' class from C++ STL.
+ if (hasMultipleInheritanceInAncestry(metaClass))
+ s << "#include <set>" << endl;
+
+ s << "#include \"" << getModuleHeaderFileName() << '"' << endl << endl;
+
+ QString headerfile = fileNameForClass(metaClass);
+ headerfile.replace("cpp", "h");
+ s << "#include \"" << headerfile << '"' << endl;
+ foreach (AbstractMetaClass* innerClass, metaClass->innerClasses()) {
+ if (shouldGenerate(innerClass)) {
+ QString headerfile = fileNameForClass(innerClass);
+ headerfile.replace("cpp", "h");
+ s << "#include \"" << headerfile << '"' << endl;
+ }
+ }
+
+ //Extra includes
+ s << endl << "// Extra includes" << endl;
+ QList<Include> includes = metaClass->typeEntry()->extraIncludes();
+ qSort(includes.begin(), includes.end());
+ foreach (Include inc, includes)
+ s << inc.toString() << endl;
+ s << endl;
+
+ if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated)
+ s << "#Deprecated" << endl;
+
+ s << "using namespace Shiboken;" << endl;
+
+ //Use class base namespace
+ const AbstractMetaClass *context = metaClass->enclosingClass();
+ while(context) {
+ if (context->isNamespace() && !context->enclosingClass()) {
+ s << "using namespace " << context->qualifiedCppName() << ";" << endl;
+ break;
+ }
+ context = context->enclosingClass();
+ }
+
+ s << endl;
+
+ // class inject-code native/beginning
+ if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::Beginning, TypeSystem::NativeCode, 0, 0, metaClass);
+ s << endl;
+ }
+
+ if (shouldGenerateCppWrapper(metaClass)) {
+ s << "// Native ---------------------------------------------------------" << endl;
+ s << endl;
+
+ foreach (const AbstractMetaFunction* func, filterFunctions(metaClass)) {
+ if ((func->isPrivate() && !visibilityModifiedToPrivate(func))
+ || (func->isModifiedRemoved() && !func->isAbstract()))
+ 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
+ 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
+ }
+#endif
+ }
+
+ Indentation indentation(INDENT);
+
+ QString methodsDefinitions;
+ QTextStream md(&methodsDefinitions);
+ QString singleMethodDefinitions;
+ QTextStream smd(&singleMethodDefinitions);
+
+ bool hasComparisonOperator = metaClass->hasComparisonOperatorOverload();
+ bool typeAsNumber = metaClass->hasArithmeticOperatorOverload() || metaClass->hasLogicalOperatorOverload() || metaClass->hasBitwiseOperatorOverload();
+
+ s << endl << "// Target ---------------------------------------------------------" << endl << endl;
+ s << "extern \"C\" {" << endl;
+ foreach (AbstractMetaFunctionList allOverloads, getFunctionGroups(metaClass).values()) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, allOverloads) {
+ if (!func->isAssignmentOperator()
+ && !func->isCastOperator()
+ && !func->isModifiedRemoved()
+ && (!func->isPrivate() || func->functionType() == AbstractMetaFunction::EmptyFunction)
+ && func->ownerClass() == func->implementingClass())
+ overloads.append(func);
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ const AbstractMetaFunction* rfunc = overloads.first();
+ if (m_sequenceProtocol.contains(rfunc->name()))
+ continue;
+
+ if (rfunc->isConstructor())
+ writeConstructorWrapper(s, overloads);
+
+ if (!rfunc->isConstructor() && !rfunc->isOperatorOverload()) {
+ writeMethodWrapper(s, overloads);
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
+ QString methDefName = cpythonMethodDefinitionName(rfunc);
+ smd << "static PyMethodDef " << methDefName << " = {" << endl;
+ smd << INDENT;
+ writeMethodDefinitionEntry(smd, overloads);
+ smd << endl << "};" << endl << endl;
+ }
+ writeMethodDefinition(md, overloads);
+ }
+ }
+
+ QString className = cpythonTypeName(metaClass).replace(QRegExp("_Type$"), "");
+
+ // Write single method definitions
+ s << singleMethodDefinitions;
+
+ // Write methods definition
+ s << "static PyMethodDef " << className << "_methods[] = {" << endl;
+ s << methodsDefinitions << INDENT << "{0} // Sentinel" << endl;
+ s << "};" << endl << endl;
+
+ // Write tp_getattro function
+ if (usePySideExtensions() && metaClass->qualifiedCppName() == "QObject") {
+ writeGetattroFunction(s, metaClass);
+ s << endl;
+ writeSetattroFunction(s, metaClass);
+ s << endl;
+ } else if (classNeedsGetattroFunction(metaClass)) {
+ writeGetattroFunction(s, metaClass);
+ s << endl;
+ }
+
+ if (typeAsNumber) {
+ QList<AbstractMetaFunctionList> opOverloads = filterGroupedOperatorFunctions(
+ metaClass,
+ AbstractMetaClass::ArithmeticOp
+ | AbstractMetaClass::LogicalOp
+ | AbstractMetaClass::BitwiseOp);
+
+ foreach (AbstractMetaFunctionList allOverloads, opOverloads) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, allOverloads) {
+ if (!func->isModifiedRemoved()
+ && !func->isPrivate()
+ && (func->ownerClass() == func->implementingClass() || func->isAbstract()))
+ overloads.append(func);
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ writeMethodWrapper(s, overloads);
+ }
+
+ s << "// type has number operators" << endl;
+ writeTypeAsNumberDefinition(s, metaClass);
+ }
+
+ if (supportsSequenceProtocol(metaClass)) {
+ writeSequenceMethods(s, metaClass);
+ writeTypeAsSequenceDefinition(s, metaClass);
+ }
+
+ if (hasComparisonOperator) {
+ s << "// Rich comparison" << endl;
+ writeRichCompareFunction(s, metaClass);
+ }
+
+ if (shouldGenerateGetSetList(metaClass)) {
+ foreach (const AbstractMetaField* metaField, metaClass->fields()) {
+ if (metaField->isStatic())
+ continue;
+ writeGetterFunction(s, metaField);
+ if (!metaField->type()->isConstant())
+ writeSetterFunction(s, metaField);
+ s << endl;
+ }
+
+ s << "// Getters and Setters for " << metaClass->name() << endl;
+ s << "static PyGetSetDef " << cpythonGettersSettersDefinitionName(metaClass) << "[] = {" << endl;
+ foreach (const AbstractMetaField* metaField, metaClass->fields()) {
+ if (metaField->isStatic())
+ continue;
+
+ bool hasSetter = !metaField->type()->isConstant();
+ s << INDENT << "{const_cast<char*>(\"" << metaField->name() << "\"), ";
+ s << cpythonGetterFunctionName(metaField);
+ s << ", " << (hasSetter ? cpythonSetterFunctionName(metaField) : "0");
+ s << "}," << endl;
+ }
+ s << INDENT << "{0} // Sentinel" << endl;
+ s << "};" << endl << endl;
+ }
+
+ s << "} // extern \"C\"" << endl << endl;
+
+ if (!metaClass->typeEntry()->hashFunction().isEmpty())
+ writeHashFunction(s, metaClass);
+ writeObjCopierFunction(s, metaClass);
+ writeClassDefinition(s, metaClass);
+ s << endl;
+
+ if (metaClass->isPolymorphic() && metaClass->baseClass())
+ writeTypeDiscoveryFunction(s, metaClass);
+
+
+ foreach (AbstractMetaEnum* cppEnum, metaClass->enums()) {
+ if (cppEnum->isAnonymous())
+ continue;
+
+ bool hasFlags = cppEnum->typeEntry()->flags();
+ if (hasFlags) {
+ writeFlagsMethods(s, cppEnum);
+ writeFlagsNumberMethodsDefinition(s, cppEnum);
+ s << endl;
+ }
+
+ writeEnumDefinition(s, cppEnum);
+
+ if (hasFlags) {
+ // Write Enum as Flags definition (at the moment used only by QFlags<enum>)
+ writeFlagsDefinition(s, cppEnum);
+ s << endl;
+ }
+ }
+ s << endl;
+
+ writeClassRegister(s, metaClass);
+
+ // class inject-code native/end
+ if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::End, TypeSystem::NativeCode, 0, 0, metaClass);
+ s << endl;
+ }
+}
+
+void CppGenerator::writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+ s << functionSignature(func, wrapperName(func->ownerClass()) + "::", "",
+ OriginalTypeDescription | SkipDefaultValues);
+ s << " : ";
+ writeFunctionCall(s, func);
+ if (usePySideExtensions() && func->ownerClass()->isQObject())
+ s << ", m_metaObject(0)";
+
+ s << " {" << endl;
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, func->injectedCodeSnips(), CodeSnip::Beginning, TypeSystem::NativeCode, func, lastArg);
+ s << INDENT << "// ... middle" << endl;
+ writeCodeSnips(s, func->injectedCodeSnips(), CodeSnip::End, TypeSystem::NativeCode, func, lastArg);
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeDestructorNative(QTextStream &s, const AbstractMetaClass *metaClass)
+{
+ Indentation indentation(INDENT);
+ s << wrapperName(metaClass) << "::~" << wrapperName(metaClass) << "()" << endl << '{' << endl;
+ s << INDENT << "BindingManager::instance().invalidateWrapper(this);" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFunction* func)
+{
+ //skip metaObject function, this will be written manually ahead
+ if (usePySideExtensions() && func->ownerClass() && func->ownerClass()->isQObject() &&
+ ((func->name() == "metaObject") || (func->name() == "qt_metacall")))
+ return;
+
+ const TypeEntry* type = func->type() ? func->type()->typeEntry() : 0;
+
+ QString prefix = wrapperName(func->ownerClass()) + "::";
+ s << functionSignature(func, prefix, "", Generator::SkipDefaultValues|Generator::OriginalTypeDescription) << endl;
+ s << "{" << endl;
+
+ Indentation indentation(INDENT);
+
+ if (func->isAbstract() && func->isModifiedRemoved()) {
+ ReportHandler::warning("Pure virtual method \"" + func->ownerClass()->name() + "::" + func->minimalSignature() + "\" must be implement but was completely removed on typesystem.");
+ s << INDENT << "return";
+ if (func->type()) {
+ s << ' ';
+ writeMinimalConstructorCallArguments(s, func->type());
+ }
+ s << ';' << endl;
+ s << '}' << endl << endl;
+ return;
+ }
+
+ s << INDENT << "Shiboken::GilState gil;" << endl;
+
+ s << INDENT << "Shiboken::AutoDecRef py_override(BindingManager::instance().getOverride(this, \"";
+ s << func->name() << "\"));" << endl;
+
+ s << INDENT << "if (py_override.isNull()) {" << endl;
+ {
+ Indentation indentation(INDENT);
+
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, CodeSnip::Beginning, TypeSystem::ShellCode, func, lastArg);
+ s << endl;
+ }
+
+ if (func->isAbstract()) {
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
+ s << func->ownerClass()->name() << '.' << func->name();
+ s << "()' not implemented.\");" << endl;
+ s << INDENT << "return ";
+ if (func->type()) {
+ writeMinimalConstructorCallArguments(s, func->type());
+ }
+ } else {
+ if (func->allowThread()) {
+ s << INDENT << "Shiboken::ThreadStateSaver " THREAD_STATE_SAVER_VAR ";" << endl;
+ s << INDENT << THREAD_STATE_SAVER_VAR ".save();" << endl;
+ }
+
+ s << INDENT << "return this->" << func->implementingClass()->qualifiedCppName() << "::";
+ writeFunctionCall(s, func, Generator::VirtualCall);
+ }
+ }
+ s << ';' << endl;
+ s << INDENT << '}' << endl << endl;
+
+ CodeSnipList convRules = getConversionRule(TypeSystem::TargetLangCode, func);
+ if (convRules.size())
+ writeCodeSnips(s, convRules, CodeSnip::Beginning, TypeSystem::TargetLangCode, func);
+
+ s << INDENT << "Shiboken::AutoDecRef pyargs(";
+
+ if (func->arguments().isEmpty()) {
+ s << "PyTuple_New(0));" << endl;
+ } else {
+ QStringList argConversions;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+
+ QString argConv;
+ QTextStream ac(&argConv);
+ bool convert = arg->type()->isObject()
+ || arg->type()->isQObject()
+ || arg->type()->isValue()
+ || arg->type()->isValuePointer()
+ || arg->type()->isNativePointer()
+ || arg->type()->isFlags()
+ || arg->type()->isEnum()
+ || arg->type()->isContainer()
+ || arg->type()->isReference()
+ || (arg->type()->isPrimitive()
+ && !m_formatUnits.contains(arg->type()->typeEntry()->name()));
+
+ bool hasConversionRule = !func->conversionRule(TypeSystem::TargetLangCode, arg->argumentIndex() + 1).isEmpty();
+
+ Indentation indentation(INDENT);
+ ac << INDENT;
+ if (convert && !hasConversionRule)
+ writeToPythonConversion(ac, arg->type(), func->ownerClass());
+
+ if (hasConversionRule) {
+ 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(')');
+ }
+#endif
+ ac << (convert ? "(" : "") << argName << (convert ? ")" : "");
+ }
+
+ argConversions << argConv;
+ }
+
+ s << "Py_BuildValue(\"(" << getFormatUnitString(func, false) << ")\"," << endl;
+ s << argConversions.join(",\n") << endl;
+ s << INDENT << "));" << endl;
+ }
+
+ bool invalidateReturn = false;
+ foreach (FunctionModification funcMod, func->modifications()) {
+ foreach (ArgumentModification argMod, funcMod.argument_mods) {
+ if (argMod.resetAfterUse)
+ s << INDENT << "bool invalidadeArg" << argMod.index << " = PyTuple_GET_ITEM(pyargs, " << argMod.index - 1 << ")->ob_refcnt == 1;" << endl;
+ else if (argMod.index == 0 && argMod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::CppOwnership)
+ invalidateReturn = true;
+ }
+ }
+ s << endl;
+
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+
+ if (injectedCodeUsesPySelf(func))
+ s << INDENT << "PyObject* pySelf = BindingManager::instance().retrieveWrapper(this);" << endl;
+
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, CodeSnip::Beginning, TypeSystem::NativeCode, func, lastArg);
+ s << endl;
+ }
+
+ if (!injectedCodeCallsPythonOverride(func)) {
+ s << INDENT;
+ s << "Shiboken::AutoDecRef " PYTHON_RETURN_VAR "(PyObject_Call(py_override, pyargs, NULL));" << endl;
+ if (type) {
+ if (invalidateReturn)
+ s << INDENT << "bool invalidadeArg0 = " PYTHON_RETURN_VAR "->ob_refcnt == 1;" << endl;
+
+ s << INDENT << "// An error happened in python code!" << endl;
+ s << INDENT << "if (" PYTHON_RETURN_VAR ".isNull()) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_Print();" << endl;
+ s << INDENT << "return ";
+ writeMinimalConstructorCallArguments(s, func->type());
+ s << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ if (func->type()) {
+ s << INDENT << "// Check return type" << endl;
+ s << INDENT << "bool typeIsValid = ";
+ QString desiredType;
+ if (func->typeReplaced(0).isEmpty()) {
+ s << cpythonIsConvertibleFunction(func->type());
+ // SbkType would return null when the type is a container.
+ if (func->type()->typeEntry()->isContainer()) {
+ desiredType = '"' + reinterpret_cast<const ContainerTypeEntry*>(func->type()->typeEntry())->typeName() + '"';
+ } else {
+ QString typeName = func->type()->cppSignature();
+#ifdef AVOID_PROTECTED_HACK
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type());
+ if (metaEnum && metaEnum->isProtected())
+ typeName = protectedEnumSurrogateName(metaEnum);
+#endif
+ if (func->type()->isPrimitive())
+ desiredType = "\"" + func->type()->name() + "\"";
+ else
+ desiredType = "SbkType<" + typeName + " >()->tp_name";
+ }
+ } else {
+ s << guessCPythonCheckFunction(func->typeReplaced(0));
+ desiredType = '"' + func->typeReplaced(0) + '"';
+ }
+ s << "(" PYTHON_RETURN_VAR ");" << endl;
+ if (func->type()->isQObject() || func->type()->isObject() || func->type()->isValuePointer())
+ s << INDENT << "typeIsValid = typeIsValid || (" PYTHON_RETURN_VAR " == Py_None);" << endl;
+
+ s << INDENT << "if (!typeIsValid) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_Format(PyExc_TypeError, \"Invalid return value in function %s, expected %s, got %s.\", \""
+ << func->ownerClass()->name() << '.' << func->name() << "\", " << desiredType
+ << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl;
+ s << INDENT << "return ";
+ writeMinimalConstructorCallArguments(s, func->type());
+ s << ';' << endl;
+ }
+ s << INDENT << "}" << endl;
+ }
+
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, 0).isEmpty();
+ if (hasConversionRule) {
+ CodeSnipList convRule = getReturnConversionRule(TypeSystem::NativeCode, func, "", CPP_RETURN_VAR);
+ 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
+ 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;
+ }
+ }
+ }
+
+ if (invalidateReturn) {
+ s << INDENT << "if (invalidadeArg0)" << endl;
+ Indentation indentation(INDENT);
+ s << INDENT << "BindingManager::instance().invalidateWrapper(" << PYTHON_RETURN_VAR ".object());" << endl;
+ }
+
+ foreach (FunctionModification funcMod, func->modifications()) {
+ foreach (ArgumentModification argMod, funcMod.argument_mods) {
+ if (argMod.resetAfterUse) {
+ s << INDENT << "if (invalidadeArg" << argMod.index << ")" << endl;
+ Indentation indentation(INDENT);
+ s << INDENT << "BindingManager::instance().invalidateWrapper(PyTuple_GET_ITEM(pyargs, ";
+ s << (argMod.index - 1) << "));" << endl;
+ }
+ }
+ }
+
+ if (func->hasInjectedCode()) {
+ s << endl;
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, CodeSnip::End, TypeSystem::NativeCode, func, lastArg);
+ }
+
+ if (type) {
+ if (!invalidateReturn && (func->type()->isObject() || func->type()->isValuePointer()) ) {
+ s << INDENT << "if (" << PYTHON_RETURN_VAR << "->ob_refcnt < 2) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_ReferenceError, \"Returning last python reference on virutal function: "
+ << func->ownerClass()->name() << "." << func->name() << "\");" << endl;
+ s << INDENT << "PyErr_Print();" << endl;
+ s << INDENT << "assert(false);" << endl;
+ }
+ s << INDENT << "}" << endl;
+ }
+ s << INDENT << "return " CPP_RETURN_VAR ";" << endl;
+ }
+
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ Indentation indentation(INDENT);
+ QString wrapperClassName = wrapperName(metaClass);
+ QString prefix = wrapperClassName + "::";
+ s << "const QMetaObject* " << wrapperClassName << "::metaObject() const\n{\n";
+ s << INDENT << "if (!m_metaObject) {\n";
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "PyObject *pySelf = BindingManager::instance().retrieveWrapper(this);\n"
+ << INDENT << "void *typeData = Shiboken::getTypeUserData(reinterpret_cast<Shiboken::SbkBaseWrapper*>(pySelf));" << endl
+ << INDENT << "if (!typeData) {" << endl;
+ {
+ Indentation indentation2(INDENT);
+ s << INDENT << "m_metaObject = PySide::DynamicQMetaObject::createBasedOn(pySelf, pySelf->ob_type, &"
+ << metaClass->qualifiedCppName() << "::staticMetaObject);" << endl
+ << INDENT << "Shiboken::setTypeUserData(reinterpret_cast<Shiboken::SbkBaseWrapper*>(pySelf), m_metaObject, PySide::deleteDynamicQMetaObject);" << endl;
+ }
+ s << INDENT << "} else {" << endl;
+ {
+ Indentation indentation2(INDENT);
+ s << INDENT << "m_metaObject = reinterpret_cast<PySide::DynamicQMetaObject*>(typeData);" << endl;
+ }
+ s << INDENT << "}" << endl;
+ }
+ s << INDENT << "}" << endl;
+ s << INDENT << "return m_metaObject;\n";
+ s << "}\n\n";
+
+ s << "int " << wrapperClassName << "::qt_metacall(QMetaObject::Call call, int id, void** args)\n";
+ s << "{\n";
+ s << INDENT << "int result = " << metaClass->qualifiedCppName() << "::qt_metacall(call, id, args);\n";
+ s << INDENT << "return result < 0 ? result : PySide::SignalManager::qt_metacall(this, call, id, args);\n";
+ s << "}\n\n";
+}
+
+void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ OverloadData overloadData(overloads, this);
+
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ const AbstractMetaClass* metaClass = rfunc->ownerClass();
+ QString className = cpythonTypeName(metaClass);
+
+ m_currentErrorCode = -1;
+
+ s << "static int" << endl;
+ s << cpythonFunctionName(rfunc) << "(PyObject* self, PyObject* args, PyObject* kwds)" << endl;
+ s << '{' << endl;
+
+ // Check if the right constructor was called.
+ if (!metaClass->hasPrivateDestructor()) {
+ s << INDENT << "if (Shiboken::isUserType(self) && !Shiboken::canCallConstructor(self->ob_type, Shiboken::SbkType<" << metaClass->qualifiedCppName() << " >()))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ }
+
+ s << INDENT;
+ bool hasCppWrapper = shouldGenerateCppWrapper(metaClass);
+ s << (hasCppWrapper ? wrapperName(metaClass) : metaClass->qualifiedCppName());
+ s << "* cptr = 0;" << endl;
+
+ bool needsOverloadId = overloadData.maxArgs() > 0;
+ if (needsOverloadId)
+ s << INDENT << "int overloadId = -1;" << endl;
+
+ QSet<QString> argNamesSet;
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ // Write argNames variable with all known argument names.
+ foreach (const AbstractMetaFunction* func, overloadData.overloads()) {
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (arg->defaultValueExpression().isEmpty() || func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ argNamesSet << arg->name();
+ }
+ }
+ QStringList argNamesList = argNamesSet.toList();
+ qSort(argNamesList.begin(), argNamesList.end());
+ if (argNamesList.isEmpty())
+ s << INDENT << "const char** argNames = 0;" << endl;
+ else
+ s << INDENT << "const char* argNames[] = {\"" << argNamesList.join("\", \"") << "\"};" << endl;
+ s << INDENT << "const QMetaObject* metaObject;" << endl;
+ }
+
+
+ s << INDENT << "SbkBaseWrapper* sbkSelf = reinterpret_cast<SbkBaseWrapper*>(self);" << endl;
+
+ if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) {
+ s << INDENT << "SbkBaseWrapperType* type = reinterpret_cast<SbkBaseWrapperType*>(self->ob_type);" << endl;
+ s << INDENT << "SbkBaseWrapperType* myType = reinterpret_cast<SbkBaseWrapperType*>(" << cpythonTypeNameExt(metaClass->typeEntry()) << ");" << endl;
+ }
+
+ if (metaClass->isAbstract()) {
+ s << INDENT << "if (type == myType) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError," << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "\"'" << metaClass->qualifiedCppName();
+ }
+ s << "' represents a C++ abstract class and cannot be instantiated\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+ }
+
+ if (metaClass->baseClassNames().size() > 1) {
+ if (!metaClass->isAbstract()) {
+ s << INDENT << "if (type != myType) {" << endl;
+ }
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "type->mi_init = myType->mi_init;" << endl;
+ s << INDENT << "type->mi_offsets = myType->mi_offsets;" << endl;
+ s << INDENT << "type->mi_specialcast = myType->mi_specialcast;" << endl;
+ }
+ if (!metaClass->isAbstract())
+ s << INDENT << '}' << endl << endl;
+ }
+
+ s << endl;
+
+ if (!metaClass->isQObject() && overloadData.hasArgumentWithDefaultValue())
+ s << INDENT << "int numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);" << endl;
+ if (overloadData.maxArgs() > 0) {
+ s << endl << INDENT << "int numArgs = ";
+ writeArgumentsInitializer(s, overloadData);
+ }
+
+ if (needsOverloadId)
+ writeOverloadedFunctionDecisor(s, overloadData);
+
+ writeFunctionCalls(s, overloadData);
+ s << endl;
+
+ s << INDENT << "if (PyErr_Occurred() || !Shiboken::setCppPointer(sbkSelf, Shiboken::SbkType<" << metaClass->qualifiedCppName() << " >(), cptr)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "delete cptr;" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+ if (overloadData.maxArgs() > 0) {
+ s << INDENT << "if (!cptr) goto " << cpythonFunctionName(rfunc) << "_TypeError;" << endl;
+ s << endl;
+ }
+
+ s << INDENT << "sbkSelf->validCppObject = 1;" << endl;
+ // If the created C++ object has a C++ wrapper the ownership is assigned to Python
+ // (first "1") and the flag indicating that the Python wrapper holds an C++ wrapper
+ // is marked as true (the second "1"). Otherwise the default values apply:
+ // Python owns it and C++ wrapper is false.
+ if (shouldGenerateCppWrapper(overloads.first()->ownerClass()))
+ s << INDENT << "sbkSelf->containsCppWrapper = 1;" << endl;
+ s << INDENT << "BindingManager::instance().registerWrapper(sbkSelf, cptr);" << endl;
+
+ // Create metaObject and register signal/slot
+ if (metaClass->isQObject() && usePySideExtensions()) {
+ s << endl << INDENT << "// QObject setup" << endl;
+ s << INDENT << "PySide::signalUpdateSource(self);" << endl;
+ s << INDENT << "metaObject = cptr->metaObject(); // <- init python qt properties" << endl;
+ s << INDENT << "if (kwds && !PySide::fillQtProperties(self, metaObject, kwds, argNames, " << argNamesSet.count() << "))" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ }
+
+ // Constructor code injections, position=end
+ bool hasCodeInjectionsAtEnd = false;
+ foreach(AbstractMetaFunction* func, overloads) {
+ foreach (CodeSnip cs, func->injectedCodeSnips()) {
+ if (cs.position == CodeSnip::End) {
+ hasCodeInjectionsAtEnd = true;
+ break;
+ }
+ }
+ }
+ if (hasCodeInjectionsAtEnd) {
+ // FIXME: C++ arguments are not available in code injection on constructor when position = end.
+ s << INDENT << "switch(overloadId) {" << endl;
+ foreach(AbstractMetaFunction* func, overloads) {
+ Indentation indent(INDENT);
+ foreach (CodeSnip cs, func->injectedCodeSnips()) {
+ if (cs.position == CodeSnip::End) {
+ s << INDENT << "case " << metaClass->functions().indexOf(func) << ':' << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ writeCodeSnips(s, func->injectedCodeSnips(), CodeSnip::End, TypeSystem::TargetLangCode, func);
+ }
+ s << INDENT << '}' << endl;
+ break;
+ }
+ }
+ }
+ s << '}' << endl;
+ }
+
+ s << endl;
+ s << endl << INDENT << "return 1;" << endl;
+ if (overloadData.maxArgs() > 0)
+ writeErrorSection(s, overloadData);
+ s << '}' << endl << endl;
+ m_currentErrorCode = 0;
+}
+
+void CppGenerator::writeMinimalConstructorCallArguments(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return;
+
+ AbstractMetaFunctionList ctors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
+ const AbstractMetaFunction* ctor = 0;
+
+ foreach (const AbstractMetaFunction* candidate, ctors) {
+ if (candidate->arguments().size() == 0) {
+ ctor = candidate;
+ break;
+ }
+
+ bool allPrimitives = true;
+ foreach (const AbstractMetaArgument* arg, candidate->arguments()) {
+ if (!arg->type()->isPrimitive() && arg->defaultValueExpression().isEmpty()) {
+ allPrimitives = false;
+ break;
+ }
+ }
+ if (allPrimitives) {
+ if (!ctor || candidate->arguments().size() < ctor->arguments().size())
+ ctor = candidate;
+ }
+ }
+
+ if (!ctor) {
+ ReportHandler::warning("Class "+metaClass->name()+" does not have a default constructor.");
+ return;
+ }
+
+ QStringList argValues;
+ AbstractMetaArgumentList args = ctor->arguments();
+ for (int i = 0; i < args.size(); i++) {
+ if (args[i]->defaultValueExpression().isEmpty())
+ argValues << args[i]->type()->name()+"(0)";
+ }
+ s << metaClass->qualifiedCppName() << '(' << argValues.join(QLatin1String(", ")) << ')';
+}
+
+void CppGenerator::writeMinimalConstructorCallArguments(QTextStream& s, const AbstractMetaType* metaType)
+{
+ Q_ASSERT(metaType);
+ const TypeEntry* type = metaType->typeEntry();
+
+ if (type->isObject() || metaType->isValuePointer()) {
+ s << "0";
+ } else if (type->isPrimitive()) {
+ const PrimitiveTypeEntry* primitiveTypeEntry = reinterpret_cast<const PrimitiveTypeEntry*>(type);
+ if (primitiveTypeEntry->hasDefaultConstructor())
+ s << primitiveTypeEntry->defaultConstructor();
+ else
+ s << type->name() << "(0)";
+ } else if (type->isContainer() || type->isFlags() || type->isEnum()){
+ s << metaType->cppSignature() << "()";
+ } else if (metaType->isNativePointer() && type->isVoid()) {
+ s << "0";
+ } else {
+ // this is slowwwww, FIXME: Fix the API od APIExtractor, these things should be easy!
+ foreach (AbstractMetaClass* metaClass, classes()) {
+ if (metaClass->typeEntry() == type) {
+ writeMinimalConstructorCallArguments(s, metaClass);
+ return;
+ }
+ }
+ ReportHandler::warning("Could not find a AbstractMetaClass for type "+metaType->name());
+ }
+}
+
+void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ OverloadData overloadData(overloads, this);
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+
+ //DEBUG
+// if (rfunc->name() == "operator+" && rfunc->ownerClass()->name() == "Str") {
+// QString dumpFile = QString("/tmp/%1_%2.dot").arg(moduleName()).arg(pythonOperatorFunctionName(rfunc)).toLower();
+// overloadData.dumpGraph(dumpFile);
+// }
+ //DEBUG
+
+ int minArgs = overloadData.minArgs();
+ int maxArgs = overloadData.maxArgs();
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
+ bool usesNamedArguments = overloadData.hasArgumentWithDefaultValue();
+
+ s << "static PyObject* ";
+ s << cpythonFunctionName(rfunc) << "(PyObject* self";
+ if (maxArgs > 0) {
+ s << ", PyObject* arg";
+ if (usePyArgs)
+ s << 's';
+ if (usesNamedArguments)
+ s << ", PyObject* kwds";
+ }
+ s << ')' << endl << '{' << endl;
+
+ if (rfunc->implementingClass() &&
+ (!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
+ s << "* " CPP_SELF_VAR " = 0;" << endl;
+
+ if (rfunc->isOperatorOverload() && rfunc->isBinaryOperator()) {
+ QString checkFunc = cpythonCheckFunction(rfunc->ownerClass()->typeEntry());
+ s << INDENT << "bool isReverse = " << checkFunc << "(arg) && !" << checkFunc << "(self);\n"
+ << INDENT << "if (isReverse)\n";
+ Indentation indent(INDENT);
+ s << INDENT << "std::swap(self, arg);\n\n";
+ }
+
+ // 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
+ cppSelfAttribution += cpythonWrapperCPtr(rfunc->ownerClass(), "self");
+
+ // Checks if the underlying C++ object is valid.
+ if (overloadData.hasStaticFunction()) {
+ s << INDENT << "if (self) {" << endl;
+ {
+ Indentation indent(INDENT);
+ writeInvalidCppObjectCheck(s);
+ s << INDENT << cppSelfAttribution << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+ } else {
+ writeInvalidCppObjectCheck(s);
+ s << INDENT << cppSelfAttribution << ';' << endl;
+ }
+ s << endl;
+ }
+
+ bool hasReturnValue = overloadData.hasNonVoidReturnType();
+
+ if (hasReturnValue && !rfunc->isInplaceOperator())
+ s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+
+ bool needsOverloadId = overloadData.maxArgs() > 0;
+ if (needsOverloadId)
+ s << INDENT << "int overloadId = -1;" << endl;
+
+ if (usesNamedArguments) {
+ s << INDENT << "int numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);" << endl;
+ }
+
+ if (minArgs != maxArgs || maxArgs > 1) {
+ s << INDENT << "int numArgs = ";
+ if (minArgs == 0 && maxArgs == 1 && !usePyArgs)
+ s << "(arg == 0 ? 0 : 1);" << endl;
+ else
+ writeArgumentsInitializer(s, overloadData);
+ }
+ s << endl;
+
+ /*
+ * Make sure reverse <</>> operators defined in other classes (specially from other modules)
+ * are called. A proper and generic solution would require an reengineering in the operator
+ * system like the extended converters.
+ *
+ * Solves #119 - QDataStream <</>> operators not working for QPixmap
+ * http://bugs.openbossa.org/show_bug.cgi?id=119
+ */
+ bool callExtendedReverseOperator = hasReturnValue && !rfunc->isInplaceOperator() && rfunc->isOperatorOverload();
+ if (callExtendedReverseOperator) {
+ QString revOpName = ShibokenGenerator::pythonOperatorFunctionName(rfunc).insert(2, 'r');
+ if (rfunc->isBinaryOperator()) {
+ s << INDENT << "if (!isReverse" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "&& SbkBaseWrapper_Check(arg)" << endl;
+ s << INDENT << "&& !PyObject_TypeCheck(arg, self->ob_type)" << endl;
+ s << INDENT << "&& PyObject_HasAttrString(arg, const_cast<char*>(\"" << revOpName << "\"))) {" << endl;
+ // This PyObject_CallMethod call will emit lots of warnings like
+ // "deprecated conversion from string constant to char *" during compilation
+ // due to the method name argument being declared as "char*" instead of "const char*"
+ // issue 6952 http://bugs.python.org/issue6952
+ s << INDENT << "PyObject* revOpMethod = PyObject_GetAttrString(arg, const_cast<char*>(\"" << revOpName << "\"));" << endl;
+ s << INDENT << "if (revOpMethod && PyCallable_Check(revOpMethod)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << PYTHON_RETURN_VAR " = PyObject_CallFunction(revOpMethod, const_cast<char*>(\"O\"), self);" << endl;
+ s << INDENT << "if (PyErr_Occurred() && (PyErr_ExceptionMatches(PyExc_NotImplementedError)";
+ s << " || PyErr_ExceptionMatches(PyExc_AttributeError))) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_Clear();" << endl;
+ s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << PYTHON_RETURN_VAR " = 0;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << "}" << endl;
+ s << INDENT << "Py_XDECREF(revOpMethod);" << endl << endl;
+ }
+ s << INDENT << "}" << endl;
+ }
+ s << INDENT << "// Do not enter here if other object has implemented a reverse operator." << endl;
+ s << INDENT << "if (!" PYTHON_RETURN_VAR ") {" << endl << endl;
+ }
+
+ if (needsOverloadId)
+ writeOverloadedFunctionDecisor(s, overloadData);
+
+ writeFunctionCalls(s, overloadData);
+ s << endl;
+
+ if (callExtendedReverseOperator)
+ s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl << endl;
+
+ s << endl << INDENT << "if (PyErr_Occurred()";
+ if (hasReturnValue && !rfunc->isInplaceOperator())
+ s << " || !" PYTHON_RETURN_VAR;
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ if (hasReturnValue && !rfunc->isInplaceOperator())
+ s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ if (hasReturnValue) {
+ if (rfunc->isInplaceOperator()) {
+ s << INDENT << "Py_INCREF(self);\n";
+ s << INDENT << "return self;\n";
+ } else {
+ s << INDENT << "return " PYTHON_RETURN_VAR ";\n";
+ }
+ } else {
+ s << INDENT << "Py_RETURN_NONE;" << endl;
+ }
+
+ if (maxArgs > 0)
+ writeErrorSection(s, overloadData);
+
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData)
+{
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ s << "PyTuple_GET_SIZE(args);" << endl;
+
+ int minArgs = overloadData.minArgs();
+ int maxArgs = overloadData.maxArgs();
+
+ QStringList palist;
+
+ s << INDENT << "PyObject* ";
+ if (!pythonFunctionWrapperUsesListOfArguments(overloadData)) {
+ s << "arg = 0";
+ palist << "&arg";
+ } else {
+ s << "pyargs[] = {" << QString(maxArgs, '0').split("", QString::SkipEmptyParts).join(", ") << '}';
+ for (int i = 0; i < maxArgs; i++)
+ palist << QString("&(pyargs[%1])").arg(i);
+ }
+ s << ';' << endl << endl;
+
+ QString pyargs = palist.join(", ");
+
+ if (overloadData.hasVarargs()) {
+ maxArgs--;
+ if (minArgs > maxArgs)
+ minArgs = maxArgs;
+
+ s << INDENT << "PyObject* nonvarargs = PyTuple_GetSlice(args, 0, " << maxArgs << ");" << endl;
+ s << INDENT << "Shiboken::AutoDecRef auto_nonvarargs(nonvarargs);" << endl;
+ s << INDENT << "pyargs[" << maxArgs << "] = PyTuple_GetSlice(args, " << maxArgs << ", numArgs);" << endl;
+ s << INDENT << "Shiboken::AutoDecRef auto_varargs(pyargs[" << maxArgs << "]);" << endl;
+ s << endl;
+ }
+
+ bool usesNamedArguments = overloadData.hasArgumentWithDefaultValue();
+
+ s << INDENT << "// invalid argument lengths" << endl;
+ bool ownerClassIsQObject = rfunc->ownerClass() && rfunc->ownerClass()->isQObject() && rfunc->isConstructor();
+ if (usesNamedArguments) {
+ if (!ownerClassIsQObject) {
+ s << INDENT << "if (numArgs" << (overloadData.hasArgumentWithDefaultValue() ? " + numNamedArgs" : "") << " > " << maxArgs << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}';
+ }
+ if (minArgs > 0) {
+ if (ownerClassIsQObject)
+ s << INDENT;
+ else
+ s << " else ";
+ s << "if (numArgs < " << minArgs << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}';
+ }
+ }
+ QList<int> invalidArgsLength = overloadData.invalidArgumentLengths();
+ if (!invalidArgsLength.isEmpty()) {
+ QStringList invArgsLen;
+ foreach (int i, invalidArgsLength)
+ invArgsLen << QString("numArgs == %1").arg(i);
+ if (usesNamedArguments && (!ownerClassIsQObject || minArgs > 0))
+ s << " else ";
+ else
+ s << INDENT;
+ s << "if (" << invArgsLen.join(" || ") << ")" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;";
+ }
+ s << endl << endl;
+
+ QString funcName;
+ if (rfunc->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ else
+ funcName = rfunc->name();
+
+ if (usesNamedArguments) {
+ s << INDENT << "if (!PyArg_ParseTuple(" << (overloadData.hasVarargs() ? "nonvarargs" : "args");
+ s << ", \"|" << QByteArray(maxArgs, 'O') << ':' << funcName << "\", " << pyargs << "))" << endl;
+ } else {
+ s << INDENT << "if (!PyArg_UnpackTuple(" << (overloadData.hasVarargs() ? "nonvarargs" : "args");
+ s << ", \"" << funcName << "\", " << minArgs << ", " << maxArgs << ", " << pyargs << "))" << endl;
+ }
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << endl;
+}
+
+void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunction* func)
+{
+ if (!func->ownerClass() || func->isStatic() || func->isConstructor())
+ 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
+ s << cpythonWrapperCPtr(func->ownerClass(), "self") << ';' << endl;
+ if (func->isUserAdded())
+ s << INDENT << "(void)" CPP_SELF_VAR "; // avoid warnings about unused variables" << endl;
+}
+
+void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData)
+{
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ s << endl << INDENT << cpythonFunctionName(rfunc) << "_TypeError:" << endl;
+ Indentation indentation(INDENT);
+ QString funcName = fullPythonFunctionName(rfunc);
+
+ QString argsVar = pythonFunctionWrapperUsesListOfArguments(overloadData) ? "args" : "arg";;
+ if (verboseErrorMessagesDisabled()) {
+ s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", 0);" << endl;
+ } else {
+ QStringList overloadSignatures;
+ foreach (const AbstractMetaFunction* f, overloadData.overloads()) {
+ QStringList args;
+ foreach(AbstractMetaArgument* arg, f->arguments()) {
+ QString strArg;
+ AbstractMetaType* argType = arg->type();
+ if (isCString(argType)) {
+ strArg = "str";
+ } else if (argType->isPrimitive()) {
+ const PrimitiveTypeEntry* ptp = reinterpret_cast<const PrimitiveTypeEntry*>(argType->typeEntry());
+ while (ptp->aliasedTypeEntry())
+ ptp = ptp->aliasedTypeEntry();
+
+ if (strArg == "QString") {
+ strArg = "unicode";
+ } else if (strArg == "QChar") {
+ strArg = "1-unicode";
+ } else {
+ strArg = ptp->name().replace(QRegExp("^signed\\s+"), "");
+ if (strArg == "double")
+ strArg = "float";
+ }
+ } else if (argType->typeEntry()->isContainer()) {
+ strArg = argType->fullName();
+ if (strArg == "QList" || strArg == "QVector"
+ || strArg == "QLinkedList" || strArg == "QStack"
+ || strArg == "QQueue") {
+ strArg = "list";
+ } else if (strArg == "QMap" || strArg == "QHash"
+ || strArg == "QMultiMap" || strArg == "QMultiHash") {
+ strArg = "dict";
+ } else if (strArg == "QPair") {
+ strArg == "2-tuple";
+ }
+ } else {
+ strArg = argType->fullName();
+ }
+ if (!arg->defaultValueExpression().isEmpty()) {
+ strArg += " = ";
+ if ((isCString(argType) || argType->isValuePointer() || argType->typeEntry()->isObject())
+ && arg->defaultValueExpression() == "0")
+ strArg += "None";
+ else
+ strArg += arg->defaultValueExpression().replace("::", ".").replace("\"", "\\\"");
+ }
+ args << strArg;
+ }
+ overloadSignatures << "\""+args.join(", ")+"\"";
+ }
+ s << INDENT << "const char* overloads[] = {" << overloadSignatures.join(", ") << ", 0};" << endl;
+ s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", overloads);" << endl;
+ }
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+}
+
+void CppGenerator::writeInvalidCppObjectCheck(QTextStream& s, QString pyArgName, const TypeEntry* type)
+{
+ s << INDENT << "if (Shiboken::cppObjectIsInvalid(" << pyArgName << "))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+}
+
+void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber, QString customType)
+{
+ if (!customType.isEmpty())
+ s << guessCPythonCheckFunction(customType);
+ else if (argType->isEnum())
+ s << cpythonIsConvertibleFunction(argType, false);
+ else
+ s << cpythonIsConvertibleFunction(argType, isNumber);
+
+ s << '(' << argumentName << ')';
+}
+
+void CppGenerator::writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName)
+{
+ QSet<const TypeEntry*> numericTypes;
+
+ foreach (OverloadData* od, overloadData->previousOverloadData()->nextOverloadData()) {
+ foreach (const AbstractMetaFunction* func, od->overloads()) {
+ const AbstractMetaArgument* arg = od->argument(func);
+
+ if (!arg->type()->isPrimitive())
+ continue;
+ if (ShibokenGenerator::isNumber(arg->type()->typeEntry()))
+ numericTypes << arg->type()->typeEntry();
+ }
+ }
+
+ // This condition trusts that the OverloadData object will arrange for
+ // PyInt type to come after the more precise numeric types (e.g. float and bool)
+ const AbstractMetaType* argType = overloadData->argType();
+ bool numberType = numericTypes.count() == 1 || ShibokenGenerator::isPyInt(argType);
+ QString customType = (overloadData->hasArgumentTypeReplace() ? overloadData->argumentTypeReplaced() : "");
+ writeTypeCheck(s, argType, argumentName, numberType, customType);
+}
+
+void CppGenerator::writeArgumentConversion(QTextStream& s,
+ const AbstractMetaType* argType,
+ QString argName, QString pyArgName,
+ const AbstractMetaClass* context,
+ QString defaultValue)
+{
+ const TypeEntry* type = argType->typeEntry();
+
+ if (type->isCustom() || type->isVarargs())
+ return;
+
+ QString typeName;
+ QString baseTypeName = type->name();
+ bool isWrappedCppClass = type->isValue() || type->isObject();
+ if (isWrappedCppClass)
+ typeName = baseTypeName + '*';
+ else
+ typeName = translateTypeForWrapperMethod(argType, context);
+
+ if (type->isContainer() || type->isPrimitive()) {
+ // If the type is a const char*, we don't remove the "const".
+ if (typeName.startsWith("const ") && !(isCString(argType)))
+ typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
+ if (typeName.endsWith("&"))
+ typeName.chop(1);
+ }
+ typeName = typeName.trimmed();
+
+ bool hasImplicitConversions = !implicitConversions(argType).isEmpty();
+
+ if (isWrappedCppClass) {
+ const TypeEntry* typeEntry = (hasImplicitConversions ? type : 0);
+ writeInvalidCppObjectCheck(s, pyArgName, typeEntry);
+ }
+
+ // Auto pointer to dealloc new objects created because to satisfy implicit conversion.
+ if (hasImplicitConversions)
+ s << INDENT << "std::auto_ptr<" << baseTypeName << " > " << argName << "_auto_ptr;" << endl;
+
+ // Value type that has default value.
+ if (argType->isValue() && !defaultValue.isEmpty())
+ s << INDENT << baseTypeName << ' ' << argName << "_tmp = " << defaultValue << ';' << endl;
+
+ if (usePySideExtensions() && typeName == "QStringRef") {
+ s << INDENT << "QString " << argName << "_qstring = ";
+ if (!defaultValue.isEmpty())
+ s << pyArgName << " ? ";
+ s << "Shiboken::Converter<QString>::toCpp(" << pyArgName << ')' << endl;
+ if (!defaultValue.isEmpty())
+ s << " : " << defaultValue;
+ s << ';' << endl;
+ s << INDENT << "QStringRef " << argName << "(&" << argName << "_qstring);" << endl;
+ } else {
+ s << INDENT << typeName << ' ' << argName << " = ";
+ if (!defaultValue.isEmpty())
+ s << pyArgName << " ? ";
+ s << "Shiboken::Converter<" << typeName << " >::toCpp(" << pyArgName << ')';
+ if (!defaultValue.isEmpty()) {
+ s << " : ";
+ if (argType->isValue())
+ s << '&' << argName << "_tmp";
+ else
+ s << defaultValue;
+ }
+ s << ';' << endl;
+ }
+
+ if (hasImplicitConversions) {
+ s << INDENT << "if (";
+ if (!defaultValue.isEmpty())
+ s << pyArgName << " && ";
+ s << '!' << cpythonCheckFunction(type) << '(' << pyArgName << "))";
+ s << endl;
+ Indentation indent(INDENT);
+ s << INDENT << argName << "_auto_ptr = std::auto_ptr<" << baseTypeName;
+ s << " >(" << argName << ");" << endl;
+ }
+}
+
+void CppGenerator::writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue)
+{
+ if (thereIsReturnValue && (!func->type() || func->argumentRemoved(0)) && !injectedCodeHasReturnValueAttribution(func)) {
+ s << INDENT << PYTHON_RETURN_VAR " = Py_None;" << endl;
+ s << INDENT << "Py_INCREF(Py_None);" << endl;
+ }
+}
+
+void CppGenerator::writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData)
+{
+ s << INDENT << "// Overloaded function decisor" << endl;
+ QList<const AbstractMetaFunction*> functionOverloads = overloadData.overloadsWithoutRepetition();
+ for (int i = 0; i < functionOverloads.count(); i++)
+ s << INDENT << "// " << i << ": " << functionOverloads.at(i)->minimalSignature() << endl;
+ writeOverloadedFunctionDecisorEngine(s, &overloadData);
+ s << endl;
+
+ s << INDENT << "// Function signature not found." << endl;
+ s << INDENT << "if (overloadId == -1) goto " << cpythonFunctionName(overloadData.referenceFunction()) << "_TypeError;" << endl;
+ s << endl;
+}
+
+void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const OverloadData* parentOverloadData)
+{
+ bool hasDefaultCall = parentOverloadData->nextArgumentHasDefaultValue();
+ const AbstractMetaFunction* referenceFunction = parentOverloadData->referenceFunction();
+
+ // If the next argument has not an argument with a default value, it is still possible
+ // that one of the overloads for the current overload data has its final occurrence here.
+ // If found, the final occurrence of a method is attributed to the referenceFunction
+ // variable to be used further on this method on the conditional that identifies default
+ // method calls.
+ if (!hasDefaultCall) {
+ foreach (const AbstractMetaFunction* func, parentOverloadData->overloads()) {
+ if (parentOverloadData->isFinalOccurrence(func)) {
+ referenceFunction = func;
+ hasDefaultCall = true;
+ break;
+ }
+ }
+ }
+
+ int maxArgs = parentOverloadData->maxArgs();
+ // Python constructors always receive multiple arguments.
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(*parentOverloadData);
+
+ // Functions without arguments are identified right away.
+ if (maxArgs == 0) {
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(referenceFunction);
+ s << "; // " << referenceFunction->minimalSignature() << endl;
+ return;
+
+ // To decide if a method call is possible at this point the current overload
+ // data object cannot be the head, since it is just an entry point, or a root,
+ // for the tree of arguments and it does not represent a valid method call.
+ } else if (!parentOverloadData->isHeadOverloadData()) {
+ bool isLastArgument = parentOverloadData->nextOverloadData().isEmpty();
+ bool signatureFound = parentOverloadData->overloads().size() == 1;
+
+ // The current overload data describes the last argument of a signature,
+ // so the method can be identified right now.
+ if (isLastArgument || (signatureFound && !hasDefaultCall)) {
+ const AbstractMetaFunction* func = parentOverloadData->referenceFunction();
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
+ return;
+ }
+ }
+
+ bool isFirst = true;
+
+ // If the next argument has a default value the decisor can perform a method call;
+ // it just need to check if the number of arguments received from Python are equal
+ // to the number of parameters preceding the argument with the default value.
+ if (hasDefaultCall) {
+ isFirst = false;
+ int numArgs = parentOverloadData->argPos() + 1;
+ s << INDENT << "if (numArgs == " << numArgs << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ const AbstractMetaFunction* func = referenceFunction;
+ foreach (OverloadData* overloadData, parentOverloadData->nextOverloadData()) {
+ const AbstractMetaFunction* defValFunc = overloadData->getFunctionWithDefaultValue();
+ if (defValFunc) {
+ func = defValFunc;
+ break;
+ }
+ }
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
+ }
+ s << INDENT << '}';
+ }
+
+ foreach (OverloadData* overloadData, parentOverloadData->nextOverloadData()) {
+ bool signatureFound = overloadData->overloads().size() == 1
+ && !overloadData->getFunctionWithDefaultValue()
+ && !overloadData->findNextArgWithDefault();
+
+ const AbstractMetaFunction* refFunc = overloadData->referenceFunction();
+
+ if (isFirst) {
+ isFirst = false;
+ s << INDENT;
+ } else {
+ s << " else ";
+ }
+
+ QString typeChecks;
+ QTextStream tck(&typeChecks);
+
+ QString pyArgName = (usePyArgs && maxArgs > 1) ? QString("pyargs[%1]").arg(overloadData->argPos()) : "arg";
+
+ OverloadData* od = overloadData;
+ int startArg = od->argPos();
+ int sequenceArgCount = 0;
+ while (od && !od->argType()->isVarargs()) {
+ if (usePyArgs)
+ pyArgName = QString("pyargs[%1]").arg(od->argPos());
+
+ writeTypeCheck(tck, od, pyArgName);
+ sequenceArgCount++;
+
+ if (od->nextOverloadData().isEmpty()
+ || od->nextArgumentHasDefaultValue()
+ || od->nextOverloadData().size() != 1
+ || od->overloads().size() != od->nextOverloadData().first()->overloads().size()) {
+ overloadData = od;
+ od = 0;
+ } else {
+ od = od->nextOverloadData().first();
+ if (!od->argType()->isVarargs())
+ tck << " && ";
+ }
+ }
+
+ s << "if (";
+ if (usePyArgs && signatureFound) {
+ AbstractMetaArgumentList args = refFunc->arguments();
+ int lastArgIsVarargs = (int) (args.size() > 1 && args.last()->type()->isVarargs());
+ int numArgs = args.size() - OverloadData::numberOfRemovedArguments(refFunc) - lastArgIsVarargs;
+ s << "numArgs " << (lastArgIsVarargs ? ">=" : "==") << " " << numArgs << " && ";
+ } else if (sequenceArgCount > 1) {
+ s << "numArgs >= " << (startArg + sequenceArgCount) << " && ";
+ }
+
+ if (refFunc->isOperatorOverload())
+ s << (refFunc->isReverseOperator() ? "" : "!") << "isReverse && ";
+
+ s << typeChecks << ") {" << endl;
+
+ {
+ Indentation indent(INDENT);
+ writeOverloadedFunctionDecisorEngine(s, overloadData);
+ }
+
+ s << INDENT << "}";
+ }
+ s << endl;
+}
+
+void CppGenerator::writeFunctionCalls(QTextStream& s, const OverloadData& overloadData)
+{
+ QList<const AbstractMetaFunction*> overloads = overloadData.overloadsWithoutRepetition();
+ s << INDENT << "// Call function/method" << endl;
+ s << INDENT << "{" << endl;
+ {
+ Indentation indent(INDENT);
+ if (overloadData.hasAllowThread())
+ s << INDENT << "Shiboken::ThreadStateSaver " THREAD_STATE_SAVER_VAR ";" << endl;
+
+ s << INDENT << (overloads.count() > 1 ? "switch (overloadId) " : "") << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ if (overloads.count() == 1) {
+ writeSingleFunctionCall(s, overloadData, overloads.first());
+ } else {
+ for (int i = 0; i < overloads.count(); i++) {
+ const AbstractMetaFunction* func = overloads.at(i);
+ s << INDENT << "case " << i << ": // " << func->minimalSignature() << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ writeSingleFunctionCall(s, overloadData, func);
+ s << INDENT << "break;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ }
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << '}' << endl;
+}
+
+void CppGenerator::writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func)
+{
+ if (func->functionType() == AbstractMetaFunction::EmptyFunction) {
+ s << INDENT << "PyErr_Format(PyExc_TypeError, \"%s is a private method.\", \"" << func->signature().replace("::", ".") << "\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ return;
+ }
+
+ const AbstractMetaClass* implementingClass = overloadData.referenceFunction()->implementingClass();
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
+
+ // Handle named arguments.
+ writeNamedArgumentResolution(s, func, usePyArgs);
+
+ int removedArgs = 0;
+ for (int i = 0; i < func->arguments().count(); i++) {
+ if (func->argumentRemoved(i + 1)) {
+ removedArgs++;
+ continue;
+ }
+
+ if (!func->conversionRule(TypeSystem::NativeCode, i + 1).isEmpty())
+ continue;
+
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+ const AbstractMetaType* argType = 0;
+ if (typeReplaced.isEmpty())
+ argType = arg->type();
+ else
+ argType = buildAbstractMetaTypeFromString(typeReplaced);
+
+ if (argType) {
+ QString argName = QString("cpp_arg%1").arg(i - removedArgs);
+ QString pyArgName = usePyArgs ? QString("pyargs[%1]").arg(i - removedArgs) : "arg";
+ QString defaultValue = guessScopeForDefaultValue(func, arg);
+
+ writeArgumentConversion(s, argType, argName, pyArgName, implementingClass, defaultValue);
+
+ // Free a custom type created by buildAbstractMetaTypeFromString.
+ if (argType != arg->type())
+ delete argType;
+ }
+ }
+
+ s << endl;
+
+ int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
+
+ s << INDENT << "if(!PyErr_Occurred()) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ writeMethodCall(s, func, func->arguments().size() - numRemovedArgs);
+ if (!func->isConstructor())
+ writeNoneReturn(s, func, overloadData.hasNonVoidReturnType());
+ }
+ s << INDENT << "}" << endl;
+}
+
+void CppGenerator::writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs)
+{
+ AbstractMetaArgumentList args = OverloadData::getArgumentsWithDefaultValues(func);
+ if (!args.isEmpty()) {
+ s << INDENT << "if (kwds) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "const char* errorArgName = 0;" << endl;
+ s << INDENT << "PyObject* ";
+ foreach (const AbstractMetaArgument* arg, args) {
+ int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
+ QString pyArgName = usePyArgs ? QString("pyargs[%1]").arg(pyArgIndex) : "arg";
+ s << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
+ s << INDENT << "if (value) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "if (" << pyArgName << ")" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "errorArgName = \"" << arg->name() << "\";" << endl;
+ }
+ s << INDENT << "else" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pyArgName << " = value;" << endl;
+ }
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT;
+ }
+ s << "if (errorArgName) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_Format(PyExc_TypeError, \"" << fullPythonFunctionName(func);
+ s << "(): got multiple values for keyword argument '%s'\", errorArgName);" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ }
+ s << INDENT << '}' << endl;
+ }
+}
+
+QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass)
+{
+ *wrappedClass = 0;
+ QString pyArgName;
+ if (argIndex == -1) {
+ pyArgName = QString("self");
+ *wrappedClass = func->implementingClass();
+ } else if (argIndex == 0) {
+ if (func->type()) {
+ pyArgName = PYTHON_RETURN_VAR;
+ *wrappedClass = classes().findClass(func->type()->typeEntry()->name());
+ } else {
+ ReportHandler::warning("Invalid Argument index on function modification: " + func->name());
+ }
+ } else {
+ int realIndex = argIndex - 1 - OverloadData::numberOfRemovedArguments(func, argIndex - 1);
+ *wrappedClass = classes().findClass(func->arguments().at(realIndex)->type()->typeEntry()->name());
+ if (argIndex == 1
+ && OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass())[func->name()]))
+ pyArgName = QString("arg");
+ else
+ pyArgName = QString("pyargs[%1]").arg(argIndex - 1);
+ }
+ return pyArgName;
+}
+
+void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* func, int maxArgs)
+{
+ s << INDENT << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << endl;
+ if (func->isConstructor()) {
+ foreach (CodeSnip cs, func->injectedCodeSnips()) {
+ if (cs.position == CodeSnip::End) {
+ s << INDENT << "overloadId = " << func->ownerClass()->functions().indexOf(const_cast<AbstractMetaFunction* const>(func)) << ';' << endl;
+ break;
+ }
+ }
+ }
+
+ if (func->isAbstract()) {
+ s << INDENT << "if (SbkBaseWrapper_containsCppWrapper(self)) {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
+ s << func->ownerClass()->name() << '.' << func->name() << "()' not implemented.\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << "}\n";
+ }
+
+ // Used to provide contextual information to custom code writer function.
+ const AbstractMetaArgument* lastArg = 0;
+
+ if (func->allowThread())
+ s << INDENT << THREAD_STATE_SAVER_VAR ".save();" << endl;
+
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+
+ // Find the last argument available in the method call to provide
+ // the injected code writer with information to avoid invalid replacements
+ // on the %# variable.
+ if (maxArgs > 0 && maxArgs < func->arguments().size() - OverloadData::numberOfRemovedArguments(func)) {
+ int removedArgs = 0;
+ for (int i = 0; i < maxArgs + removedArgs; i++) {
+ lastArg = func->arguments().at(i);
+ if (func->argumentRemoved(i + 1))
+ removedArgs++;
+ }
+ } else if (maxArgs != 0 && !func->arguments().isEmpty()) {
+ lastArg = func->arguments().last();
+ }
+
+ writeCodeSnips(s, snips, CodeSnip::Beginning, TypeSystem::TargetLangCode, func, lastArg);
+ s << endl;
+ }
+
+ CodeSnipList convRules = getConversionRule(TypeSystem::NativeCode, func);
+ if (convRules.size())
+ writeCodeSnips(s, convRules, CodeSnip::Beginning, TypeSystem::TargetLangCode, func);
+
+ // Code to restore the threadSaver has been written?
+ bool threadRestored = false;
+
+ if (!func->isUserAdded()) {
+ bool badModifications = false;
+ QStringList userArgs;
+
+ if (!func->isCopyConstructor()) {
+ int removedArgs = 0;
+ for (int i = 0; i < maxArgs + removedArgs; i++) {
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+ if (func->argumentRemoved(i + 1)) {
+
+ // If some argument with default value is removed from a
+ // method signature, the said value must be explicitly
+ // added to the method call.
+ removedArgs++;
+
+ // If have conversion rules I will use this for removed args
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
+ if (hasConversionRule) {
+ userArgs << arg->name() + "_out";
+ } else {
+ if (arg->defaultValueExpression().isEmpty())
+ badModifications = true;
+ else
+ userArgs << guessScopeForDefaultValue(func, arg);
+ }
+ } else {
+ int idx = arg->argumentIndex() - removedArgs;
+ QString argName;
+
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
+ if (hasConversionRule) {
+ argName = arg->name() + "_out";
+ } else {
+ argName = QString("cpp_arg%1").arg(idx);
+ if (shouldDereferenceArgumentPointer(arg))
+ argName.prepend('*');
+ }
+ userArgs << argName;
+ }
+ }
+
+ // If any argument's default value was modified the method must be called
+ // with this new value whenever the user doesn't pass an explicit value to it.
+ // Also, any unmodified default value coming after the last user specified
+ // argument and before the modified argument must be explicitly stated.
+ QStringList otherArgs;
+ bool otherArgsModified = false;
+ bool argsClear = true;
+ for (int i = func->arguments().size() - 1; i >= maxArgs + removedArgs; i--) {
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+ bool defValModified = arg->defaultValueExpression() != arg->originalDefaultValueExpression();
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
+ if (argsClear && !defValModified && !hasConversionRule)
+ continue;
+ else
+ argsClear = false;
+
+ otherArgsModified |= defValModified || hasConversionRule || func->argumentRemoved(i + 1);
+
+ if (!arg->defaultValueExpression().isEmpty())
+ otherArgs.prepend(guessScopeForDefaultValue(func, arg));
+ else if (hasConversionRule)
+ otherArgs.prepend(arg->name() + "_out");
+ else
+ badModifications = true;
+ }
+ if (otherArgsModified)
+ userArgs << otherArgs;
+ }
+
+ bool isCtor = false;
+ QString methodCall;
+ QTextStream mc(&methodCall);
+
+ if (badModifications) {
+ // When an argument is removed from a method signature and no other
+ // means of calling the method is provided (as with code injection)
+ // the generator must write a compiler error line stating the situation.
+ if (func->injectedCodeSnips(CodeSnip::Any, TypeSystem::TargetLangCode).isEmpty()) {
+ qFatal(qPrintable("No way to call \"" + func->ownerClass()->name()
+ + "::" + func->minimalSignature()
+ +"\" with the modifications described in the type system file"));
+ }
+ } else if (func->isOperatorOverload()) {
+ QString firstArg("(*" CPP_SELF_VAR ")");
+ QString secondArg("cpp_arg0");
+ if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().first())) {
+ secondArg.prepend("(*");
+ secondArg.append(')');
+ }
+
+ if (func->isUnaryOperator())
+ std::swap(firstArg, secondArg);
+
+ QString op = func->originalName();
+ op = op.right(op.size() - (sizeof("operator")/sizeof(char)-1));
+
+ if (func->isBinaryOperator()) {
+ if (func->isReverseOperator())
+ std::swap(firstArg, secondArg);
+ mc << firstArg << ' ' << op << ' ' << secondArg;
+ } else {
+ mc << op << ' ' << secondArg;
+ }
+ } else if (!injectedCodeCallsCppFunction(func)) {
+ if (func->isConstructor() || func->isCopyConstructor()) {
+ isCtor = true;
+ QString className = wrapperName(func->ownerClass());
+ mc << "new " << className << '(';
+ if (func->isCopyConstructor() && maxArgs == 1) {
+ mc << '*';
+ QString arg("cpp_arg0");
+ if (shouldGenerateCppWrapper(func->ownerClass()))
+ arg = QString("reinterpret_cast<%1*>(%2)").arg(className).arg(arg);
+ mc << arg;
+ } else {
+ mc << userArgs.join(", ");
+ }
+ mc << ')';
+ } else {
+ if (func->ownerClass()) {
+#ifndef AVOID_PROTECTED_HACK
+ if (!func->isStatic())
+ mc << CPP_SELF_VAR "->";
+ if (!func->isAbstract())
+ mc << func->ownerClass()->qualifiedCppName() << "::";
+ mc << func->originalName();
+#else
+ if (!func->isStatic()) {
+ if (func->isProtected())
+ mc << "((" << wrapperName(func->ownerClass()) << "*) ";
+ mc << CPP_SELF_VAR << (func->isProtected() ? ")" : "") << "->";
+ }
+ if (!func->isAbstract())
+ mc << (func->isProtected() ? wrapperName(func->ownerClass()) : func->ownerClass()->qualifiedCppName()) << "::";
+ mc << func->originalName() << (func->isProtected() ? "_protected" : "");
+#endif
+ } else {
+ mc << func->originalName();
+ }
+ mc << '(' << userArgs.join(", ") << ')';
+ }
+ }
+
+ if (!injectedCodeCallsCppFunction(func)) {
+ s << INDENT;
+ 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
+ s << func->type()->cppSignature();
+ s << " " CPP_RETURN_VAR " = ";
+ }
+ s << methodCall << ';' << endl;
+
+ if (func->allowThread()) {
+ s << INDENT << THREAD_STATE_SAVER_VAR ".restore();" << endl;
+ threadRestored = true;
+ }
+
+ if (!isCtor && !func->isInplaceOperator() && func->type()) {
+ s << INDENT << PYTHON_RETURN_VAR " = ";
+ writeToPythonConversion(s, func->type(), func->ownerClass(), CPP_RETURN_VAR);
+ s << ';' << endl;
+ }
+ }
+ }
+
+ if (!threadRestored && func->allowThread())
+ s << INDENT << THREAD_STATE_SAVER_VAR ".restore();" << endl;
+
+ if (func->hasInjectedCode() && !func->isConstructor()) {
+ s << endl;
+ writeCodeSnips(s, snips, CodeSnip::End, TypeSystem::TargetLangCode, func, lastArg);
+ }
+
+ bool hasReturnPolicy = false;
+
+ // Ownership transference between C++ and Python.
+ QList<ArgumentModification> ownership_mods;
+ // Python object reference management.
+ QList<ArgumentModification> refcount_mods;
+ foreach (FunctionModification func_mod, func->modifications()) {
+ foreach (ArgumentModification arg_mod, func_mod.argument_mods) {
+ if (!arg_mod.ownerships.isEmpty() && arg_mod.ownerships.contains(TypeSystem::TargetLangCode))
+ ownership_mods.append(arg_mod);
+ else if (!arg_mod.referenceCounts.isEmpty())
+ refcount_mods.append(arg_mod);
+ }
+ }
+
+ if (!ownership_mods.isEmpty()) {
+ s << endl << INDENT << "// Ownership transferences." << endl;
+ foreach (ArgumentModification arg_mod, ownership_mods) {
+ const AbstractMetaClass* wrappedClass = 0;
+ QString pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass);
+ if (!wrappedClass) {
+ s << "#error Invalid ownership modification for argument " << arg_mod.index << '(' << pyArgName << ')' << endl << endl;
+ break;
+ }
+
+ if (arg_mod.index == 0)
+ hasReturnPolicy = true;
+
+ // The default ownership does nothing. This is useful to avoid automatic heuristically
+ // based generation of code defining parenting.
+ if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::DefaultOwnership)
+ continue;
+
+ s << INDENT;
+ if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::TargetLangOwnership) {
+ s << "SbkBaseWrapper_setOwnership(" << pyArgName << ", true);";
+ } else if (wrappedClass->hasVirtualDestructor()) {
+ if (arg_mod.index == 0) {
+ s << "SbkBaseWrapper_setOwnership(" PYTHON_RETURN_VAR ", 0);";
+ } else {
+ s << "BindingManager::instance().transferOwnershipToCpp(" << pyArgName << ");";
+ }
+ } else {
+ s << "BindingManager::instance().invalidateWrapper(" << pyArgName << ");";
+ }
+ s << endl;
+ }
+
+ } else if (!refcount_mods.isEmpty()) {
+ foreach (ArgumentModification arg_mod, refcount_mods) {
+ if (arg_mod.referenceCounts.first().action != ReferenceCount::Add)
+ continue;
+ const AbstractMetaClass* wrappedClass = 0;
+ QString pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass);
+ if (pyArgName.isEmpty()) {
+ s << "#error Invalid reference count modification for argument " << arg_mod.index << endl << endl;
+ break;
+ }
+
+ s << INDENT << "Shiboken::keepReference(reinterpret_cast<SbkBaseWrapper*>(self), \"";
+ QString varName = arg_mod.referenceCounts.first().varName;
+ if (varName.isEmpty())
+ varName = func->minimalSignature() + QString().number(arg_mod.index);
+
+ s << varName << "\", " << pyArgName << ");" << endl;
+
+ if (arg_mod.index == 0)
+ hasReturnPolicy = true;
+ }
+ }
+ writeParentChildManagement(s, func, !hasReturnPolicy);
+}
+
+QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClass* metaClass)
+{
+ QStringList result;
+ AbstractMetaClassList baseClases = getBaseClasses(metaClass);
+ if (!baseClases.isEmpty()) {
+ foreach (const AbstractMetaClass* baseClass, baseClases) {
+ result.append(QString("((size_t) static_cast<const %1*>(class_ptr)) - base").arg(baseClass->qualifiedCppName()));
+ result.append(QString("((size_t) static_cast<const %1*>((%2*)((void*)class_ptr))) - base").arg(baseClass->qualifiedCppName()).arg(metaClass->qualifiedCppName()));
+ }
+ foreach (const AbstractMetaClass* baseClass, baseClases)
+ result.append(getAncestorMultipleInheritance(baseClass));
+ }
+ 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;
+}
+
+void CppGenerator::writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString className = metaClass->qualifiedCppName();
+ s << "static void* " << cpythonSpecialCastFunctionName(metaClass) << "(void* obj, SbkBaseWrapperType* desiredType)\n";
+ s << "{\n";
+ s << INDENT << className << "* me = reinterpret_cast<" << className << "*>(obj);\n";
+ bool firstClass = true;
+ foreach (const AbstractMetaClass* baseClass, getAllAncestors(metaClass)) {
+ s << INDENT << (!firstClass ? "else " : "") << "if (desiredType == reinterpret_cast<SbkBaseWrapperType*>(" << cpythonTypeNameExt(baseClass->typeEntry()) << "))\n";
+ Indentation indent(INDENT);
+ s << INDENT << "return static_cast<" << baseClass->qualifiedCppName() << "*>(me);\n";
+ firstClass = false;
+ }
+ s << INDENT << "return me;\n";
+ s << "}\n\n";
+}
+
+void CppGenerator::writeExtendedIsConvertibleFunction(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions)
+{
+ s << "static bool " << extendedIsConvertibleFunctionName(externalType) << "(PyObject* pyobj)" << endl;
+ s << '{' << endl;
+ s << INDENT << "return ";
+ bool isFirst = true;
+ foreach (const AbstractMetaClass* metaClass, conversions) {
+ Indentation indent(INDENT);
+ if (isFirst)
+ isFirst = false;
+ else
+ s << endl << INDENT << " || ";
+ s << cpythonIsConvertibleFunction(metaClass->typeEntry()) << "(pyobj)";
+ }
+ s << ';' << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeExtendedToCppFunction(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions)
+{
+ s << "static void* " << extendedToCppFunctionName(externalType) << "(PyObject* pyobj)" << endl;
+ s << '{' << endl;
+ s << INDENT << "void* cptr = 0;" << endl;
+ bool isFirst = true;
+ foreach (const AbstractMetaClass* metaClass, conversions) {
+ s << INDENT;
+ if (isFirst)
+ isFirst = false;
+ else
+ s << "else ";
+ s << "if (" << cpythonIsConvertibleFunction(metaClass->typeEntry()) << "(pyobj))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "cptr = new " << externalType->name() << '(';
+ writeToCppConversion(s, metaClass, "pyobj");
+ s << ");" << endl;
+ }
+ s << INDENT << "return cptr;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions)
+{
+ s << INDENT << "// Extended implicit conversions for " << externalType->targetLangPackage() << '.' << externalType->name() << endl;
+ s << INDENT << "shiboType = reinterpret_cast<Shiboken::SbkBaseWrapperType*>(";
+ s << cppApiVariableName(externalType->targetLangPackage()) << '[';
+ s << getTypeIndexVariableName(externalType) << "]);" << endl;
+ s << INDENT << "shiboType->ext_isconvertible = " << extendedIsConvertibleFunctionName(externalType) << ';' << endl;
+ s << INDENT << "shiboType->ext_tocpp = " << extendedToCppFunctionName(externalType) << ';' << 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()) {
+ if (metaClass->hasFunction(funcName))
+ return true;
+ }
+
+ const ComplexTypeEntry* baseType = metaClass->typeEntry()->baseContainerType();
+ if (baseType && (reinterpret_cast<const ContainerTypeEntry*>(baseType)->type() == ContainerTypeEntry::ListContainer))
+ return true;
+
+ return false;
+}
+
+bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass* metaClass)
+{
+ foreach (AbstractMetaField* f, metaClass->fields()) {
+ if (!f->isStatic())
+ return true;
+ }
+ return false;
+}
+
+void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString tp_flags;
+ QString tp_init;
+ QString tp_new;
+ QString tp_dealloc;
+ QString cpp_dtor('0');
+ QString tp_as_number('0');
+ QString tp_as_sequence('0');
+ QString tp_hash('0');
+ QString mi_init('0');
+ QString obj_copier('0');
+ QString mi_specialcast('0');
+ QString cppClassName = metaClass->qualifiedCppName();
+ QString className = cpythonTypeName(metaClass).replace(QRegExp("_Type$"), "");
+ QString baseClassName('0');
+ AbstractMetaFunctionList ctors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
+ bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
+
+ if (metaClass->hasArithmeticOperatorOverload()
+ || metaClass->hasLogicalOperatorOverload()
+ || metaClass->hasBitwiseOperatorOverload()) {
+ tp_as_number = QString("&%1_as_number").arg(cpythonBaseName(metaClass));
+ }
+
+ // sequence protocol check
+ if (supportsSequenceProtocol(metaClass))
+ tp_as_sequence = QString("&Py%1_as_sequence").arg(cppClassName);
+
+ if (!metaClass->baseClass())
+ baseClassName = "reinterpret_cast<PyTypeObject*>(&Shiboken::SbkBaseWrapper_Type)";
+
+ if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) {
+ tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES";
+ tp_dealloc = metaClass->hasPrivateDestructor() ?
+ "Shiboken::deallocWrapperWithPrivateDtor" : "0";
+ tp_init = "0";
+ } else {
+ if (onlyPrivCtor)
+ tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES";
+ else
+ tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES";
+
+ QString deallocClassName;
+ if (shouldGenerateCppWrapper(metaClass))
+ deallocClassName = wrapperName(metaClass);
+ else
+ deallocClassName = cppClassName;
+ tp_dealloc = "&Shiboken::deallocWrapper";
+
+ QString dtorClassName = metaClass->qualifiedCppName();
+#ifdef AVOID_PROTECTED_HACK
+ if (metaClass->hasProtectedDestructor())
+ dtorClassName = wrapperName(metaClass);
+#endif
+ cpp_dtor = "&Shiboken::callCppDestructor<" + dtorClassName + " >";
+
+ tp_init = onlyPrivCtor ? "0" : cpythonFunctionName(ctors.first());
+ }
+
+ QString tp_getattro('0');
+ QString tp_setattro('0');
+ if (usePySideExtensions() && (metaClass->qualifiedCppName() == "QObject")) {
+ tp_getattro = cpythonGetattroFunctionName(metaClass);
+ tp_setattro = cpythonSetattroFunctionName(metaClass);
+ } else if (classNeedsGetattroFunction(metaClass)) {
+ tp_getattro = cpythonGetattroFunctionName(metaClass);
+ }
+
+ if (metaClass->hasPrivateDestructor() || onlyPrivCtor)
+ tp_new = "0";
+ else
+ tp_new = "Shiboken::SbkBaseWrapper_TpNew";
+
+ QString tp_richcompare = QString('0');
+ if (metaClass->hasComparisonOperatorOverload())
+ tp_richcompare = cpythonBaseName(metaClass) + "_richcompare";
+
+ QString tp_getset = QString('0');
+ if (shouldGenerateGetSetList(metaClass))
+ tp_getset = cpythonGettersSettersDefinitionName(metaClass);
+
+ // search for special functions
+ ShibokenGenerator::clearTpFuncs();
+ foreach (AbstractMetaFunction* func, metaClass->functions()) {
+ if (m_tpFuncs.contains(func->name()))
+ m_tpFuncs[func->name()] = cpythonFunctionName(func);
+ }
+
+ // class or some ancestor has multiple inheritance
+ const AbstractMetaClass* miClass = getMultipleInheritingClass(metaClass);
+ if (miClass) {
+ if (metaClass == miClass) {
+ mi_init = multipleInheritanceInitializerFunctionName(miClass);
+ writeMultipleInheritanceInitializerFunction(s, metaClass);
+ }
+ mi_specialcast = '&'+cpythonSpecialCastFunctionName(metaClass);
+ writeSpecialCastFunction(s, metaClass);
+ s << endl;
+ }
+
+ if (metaClass->typeEntry()->isValue() && shouldGenerateCppWrapper(metaClass))
+ obj_copier = '&' + cpythonBaseName(metaClass) + "_ObjCopierFunc";
+
+ if (!metaClass->typeEntry()->hashFunction().isEmpty())
+ tp_hash = '&' + cpythonBaseName(metaClass) + "_HashFunc";
+
+ s << "// Class Definition -----------------------------------------------" << endl;
+ s << "extern \"C\" {" << endl;
+ s << "static SbkBaseWrapperType " << className + "_Type" << " = { { {" << endl;
+ s << INDENT << "PyObject_HEAD_INIT(&Shiboken::SbkBaseWrapperType_Type)" << endl;
+ s << INDENT << "/*ob_size*/ 0," << endl;
+ s << INDENT << "/*tp_name*/ \"" << metaClass->fullName() << "\"," << endl;
+ s << INDENT << "/*tp_basicsize*/ sizeof(Shiboken::SbkBaseWrapper)," << endl;
+ s << INDENT << "/*tp_itemsize*/ 0," << endl;
+ s << INDENT << "/*tp_dealloc*/ " << tp_dealloc << ',' << endl;
+ s << INDENT << "/*tp_print*/ 0," << endl;
+ s << INDENT << "/*tp_getattr*/ 0," << endl;
+ s << INDENT << "/*tp_setattr*/ 0," << endl;
+ s << INDENT << "/*tp_compare*/ 0," << endl;
+ s << INDENT << "/*tp_repr*/ " << m_tpFuncs["__repr__"] << "," << endl;
+ s << INDENT << "/*tp_as_number*/ " << tp_as_number << ',' << endl;
+ s << INDENT << "/*tp_as_sequence*/ " << tp_as_sequence << ',' << endl;
+ s << INDENT << "/*tp_as_mapping*/ 0," << endl;
+ s << INDENT << "/*tp_hash*/ " << tp_hash << ',' << endl;
+ s << INDENT << "/*tp_call*/ 0," << endl;
+ s << INDENT << "/*tp_str*/ " << m_tpFuncs["__str__"] << ',' << endl;
+ s << INDENT << "/*tp_getattro*/ " << tp_getattro << ',' << endl;
+ s << INDENT << "/*tp_setattro*/ " << tp_setattro << ',' << endl;
+ s << INDENT << "/*tp_as_buffer*/ 0," << endl;
+ s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl;
+ s << INDENT << "/*tp_doc*/ 0," << endl;
+ s << INDENT << "/*tp_traverse*/ 0," << endl;
+ s << INDENT << "/*tp_clear*/ 0," << endl;
+ s << INDENT << "/*tp_richcompare*/ " << tp_richcompare << ',' << endl;
+ s << INDENT << "/*tp_weaklistoffset*/ 0," << endl;
+ s << INDENT << "/*tp_iter*/ 0," << endl;
+ s << INDENT << "/*tp_iternext*/ 0," << endl;
+ s << INDENT << "/*tp_methods*/ " << className << "_methods," << endl;
+ s << INDENT << "/*tp_members*/ 0," << endl;
+ s << INDENT << "/*tp_getset*/ " << tp_getset << ',' << endl;
+ s << INDENT << "/*tp_base*/ " << baseClassName << ',' << endl;
+ s << INDENT << "/*tp_dict*/ 0," << endl;
+ s << INDENT << "/*tp_descr_get*/ 0," << endl;
+ s << INDENT << "/*tp_descr_set*/ 0," << endl;
+ s << INDENT << "/*tp_dictoffset*/ 0," << endl;
+ s << INDENT << "/*tp_init*/ " << tp_init << ',' << endl;
+ s << INDENT << "/*tp_alloc*/ 0," << endl;
+ s << INDENT << "/*tp_new*/ " << tp_new << ',' << endl;
+ s << INDENT << "/*tp_free*/ 0," << endl;
+ s << INDENT << "/*tp_is_gc*/ 0," << endl;
+ s << INDENT << "/*tp_bases*/ 0," << endl;
+ s << INDENT << "/*tp_mro*/ 0," << endl;
+ s << INDENT << "/*tp_cache*/ 0," << endl;
+ s << INDENT << "/*tp_subclasses*/ 0," << endl;
+ s << INDENT << "/*tp_weaklist*/ 0" << endl;
+ s << "}, }," << endl;
+ s << INDENT << "/*mi_offsets*/ 0," << endl;
+ s << INDENT << "/*mi_init*/ " << mi_init << ',' << endl;
+ s << INDENT << "/*mi_specialcast*/ " << mi_specialcast << ',' << endl;
+ s << INDENT << "/*type_discovery*/ 0," << endl;
+ s << INDENT << "/*obj_copier*/ " << obj_copier << ',' << endl;
+ s << INDENT << "/*ext_isconvertible*/ 0," << endl;
+ s << INDENT << "/*ext_tocpp*/ 0," << endl;
+ s << INDENT << "/*cpp_dtor*/ " << cpp_dtor << ',' << endl;
+ s << INDENT << "/*is_multicpp*/ 0," << endl;
+ s << INDENT << "/*is_user_type*/ 0," << endl;
+ QString suffix;
+ if (metaClass->typeEntry()->isObject() || metaClass->typeEntry()->isQObject())
+ suffix = "*";
+ s << INDENT << "/*original_name*/ \"" << metaClass->qualifiedCppName() << suffix << "\"," << endl;
+ s << INDENT << "/*user_data*/ 0" << endl;
+ s << "};" << endl;
+ s << "} //extern" << endl;
+}
+
+
+void CppGenerator::writeSequenceMethods(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+
+ QMap<QString, QString> funcs;
+ bool injectedCode = false;
+
+ QHash< QString, QPair< QString, QString > >::const_iterator it = m_sequenceProtocol.begin();
+ for (; it != m_sequenceProtocol.end(); ++it) {
+ const AbstractMetaFunction* func = metaClass->findFunction(it.key());
+ if (!func)
+ continue;
+ injectedCode = true;
+ QString funcName = cpythonFunctionName(func);
+ QString funcArgs = it.value().first;
+ QString funcRetVal = it.value().second;
+
+ CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::TargetLangCode);
+ s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl;
+ writeInvalidCppObjectCheck(s);
+
+ writeCppSelfDefinition(s, func);
+
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips,CodeSnip::Any, TypeSystem::TargetLangCode, func, lastArg);
+ s << '}' << endl << endl;
+ }
+
+ if (!injectedCode)
+ writeStdListWrapperMethods(s, metaClass);
+}
+
+void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString className = metaClass->qualifiedCppName();
+ QMap<QString, QString> funcs;
+
+ bool hasFunctions = false;
+ foreach(QString funcName, m_sequenceProtocol.keys()) {
+ const AbstractMetaFunction* func = metaClass->findFunction(funcName);
+ funcs[funcName] = func ? cpythonFunctionName(func).prepend("&") : "0";
+ if (!hasFunctions && func)
+ hasFunctions = true;
+ }
+
+ //use default implementation
+ if (!hasFunctions) {
+ QString baseName = cpythonBaseName(metaClass->typeEntry());
+ funcs["__len__"] = baseName + "__len__";
+ funcs["__getitem__"] = baseName + "__getitem__";
+ funcs["__setitem__"] = baseName + "__setitem__";
+ }
+
+ s << "static PySequenceMethods Py" << className << "_as_sequence = {\n"
+ << INDENT << "/*sq_length*/ " << funcs["__len__"] << ",\n"
+ << INDENT << "/*sq_concat*/ " << funcs["__concat__"] << ",\n"
+ << INDENT << "/*sq_repeat*/ 0,\n"
+ << INDENT << "/*sq_item*/ " << funcs["__getitem__"] << ",\n"
+ << INDENT << "/*sq_slice*/ " << funcs["__getslice__"] << ",\n"
+ << INDENT << "/*sq_ass_item*/ " << funcs["__setitem__"] << ",\n"
+ << INDENT << "/*sq_ass_slice*/ " << funcs["__setslice__"] << ",\n"
+ << INDENT << "/*sq_contains*/ " << funcs["__contains__"] << ",\n"
+ << INDENT << "/*sq_inplace_concat*/ 0,\n"
+ << INDENT << "/*sq_inplace_repeat*/ 0\n"
+ << "};\n\n";
+}
+
+void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QMap<QString, QString> nb;
+
+ nb["__add__"] = QString('0');
+ nb["__sub__"] = QString('0');
+ nb["__mul__"] = QString('0');
+ nb["__div__"] = QString('0');
+ nb["__mod__"] = QString('0');
+ nb["__neg__"] = QString('0');
+ nb["__pos__"] = QString('0');
+ nb["__invert__"] = QString('0');
+ nb["__lshift__"] = QString('0');
+ nb["__rshift__"] = QString('0');
+ nb["__and__"] = QString('0');
+ nb["__xor__"] = QString('0');
+ nb["__or__"] = QString('0');
+ nb["__iadd__"] = QString('0');
+ nb["__isub__"] = QString('0');
+ nb["__imul__"] = QString('0');
+ nb["__idiv__"] = QString('0');
+ nb["__imod__"] = QString('0');
+ nb["__ilshift__"] = QString('0');
+ nb["__irshift__"] = QString('0');
+ nb["__iand__"] = QString('0');
+ nb["__ixor__"] = QString('0');
+ nb["__ior__"] = QString('0');
+
+ QList<AbstractMetaFunctionList> opOverloads =
+ filterGroupedOperatorFunctions(metaClass,
+ AbstractMetaClass::ArithmeticOp
+ | AbstractMetaClass::LogicalOp
+ | AbstractMetaClass::BitwiseOp);
+
+ foreach (AbstractMetaFunctionList opOverload, opOverloads) {
+ const AbstractMetaFunction* rfunc = opOverload[0];
+ QString opName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ nb[opName] = cpythonFunctionName(rfunc);
+ }
+
+ s << "static PyNumberMethods " << cpythonBaseName(metaClass);
+ s << "_as_number = {" << endl;
+ s << INDENT << "/*nb_add*/ (binaryfunc)" << nb["__add__"] << ',' << endl;
+ s << INDENT << "/*nb_subtract*/ (binaryfunc)" << nb["__sub__"] << ',' << endl;
+ s << INDENT << "/*nb_multiply*/ (binaryfunc)" << nb["__mul__"] << ',' << endl;
+ s << INDENT << "/*nb_divide*/ (binaryfunc)" << nb["__div__"] << ',' << endl;
+ s << INDENT << "/*nb_remainder*/ (binaryfunc)" << nb["__mod__"] << ',' << endl;
+ s << INDENT << "/*nb_divmod*/ 0," << endl;
+ s << INDENT << "/*nb_power*/ 0," << endl;
+ s << INDENT << "/*nb_negative*/ (unaryfunc)" << nb["__neg__"] << ',' << endl;
+ s << INDENT << "/*nb_positive*/ (unaryfunc)" << nb["__pos__"] << ',' << endl;
+ s << INDENT << "/*nb_absolute*/ 0," << endl;
+ s << INDENT << "/*nb_nonzero*/ 0," << endl;
+ s << INDENT << "/*nb_invert*/ (unaryfunc)" << nb["__invert__"] << ',' << endl;
+ s << INDENT << "/*nb_lshift*/ (binaryfunc)" << nb["__lshift__"] << ',' << endl;
+ s << INDENT << "/*nb_rshift*/ (binaryfunc)" << nb["__rshift__"] << ',' << endl;
+ s << INDENT << "/*nb_and*/ (binaryfunc)" << nb["__and__"] << ',' << endl;
+ s << INDENT << "/*nb_xor*/ (binaryfunc)" << nb["__xor__"] << ',' << endl;
+ s << INDENT << "/*nb_or*/ (binaryfunc)" << nb["__or__"] << ',' << endl;
+ s << INDENT << "/*nb_coerce*/ 0," << endl;
+ s << INDENT << "/*nb_int*/ 0," << endl;
+ s << INDENT << "/*nb_long*/ 0," << endl;
+ s << INDENT << "/*nb_float*/ 0," << endl;
+ s << INDENT << "/*nb_oct*/ 0," << endl;
+ s << INDENT << "/*nb_hex*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_add*/ (binaryfunc)" << nb["__iadd__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_subtract*/ (binaryfunc)" << nb["__isub__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_multiply*/ (binaryfunc)" << nb["__imul__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_divide*/ (binaryfunc)" << nb["__idiv__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_remainder*/ (binaryfunc)" << nb["__imod__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_power*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_lshift*/ (binaryfunc)" << nb["__ilshift__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_rshift*/ (binaryfunc)" << nb["__irshift__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_and*/ (binaryfunc)" << nb["__iand__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_xor*/ (binaryfunc)" << nb["__ixor__"] << ',' << endl;
+ s << INDENT << "/*nb_inplace_or*/ (binaryfunc)" << nb["__ior__"] << ',' << endl;
+ s << INDENT << "/*nb_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_index*/ 0" << endl;
+ s << "};" << endl << endl;
+}
+
+void CppGenerator::writeGetterFunction(QTextStream& s, const AbstractMetaField* metaField)
+{
+ s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* self, void*)" << endl;
+ s << '{' << endl;
+ s << INDENT << "return ";
+
+ QString cppField;
+#ifdef AVOID_PROTECTED_HACK
+ if (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").arg(cpythonWrapperCPtr(metaField->enclosingClass(), "self")).arg(metaField->name());
+ writeToPythonConversion(s, metaField->type(), metaField->enclosingClass(), cppField);
+ s << ';' << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField* metaField)
+{
+ s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* self, PyObject* value, void*)" << endl;
+ s << '{' << endl;
+
+ s << INDENT << "if (value == 0) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"'";
+ s << metaField->name() << "' may not be deleted\");" << endl;
+ s << INDENT << "return -1;" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ s << INDENT << "if (!";
+ writeTypeCheck(s, metaField->type(), "value", isNumber(metaField->type()->typeEntry()));
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"wrong type attributed to '";
+ s << metaField->name() << "', '" << metaField->type()->name() << "' or convertible type expected\");" << endl;
+ s << INDENT << "return -1;" << endl;
+ }
+ 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));
+ 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());
+ s << fieldStr << " = ";
+ writeToCppConversion(s, metaField->type(), metaField->enclosingClass(), "value");
+#ifdef AVOID_PROTECTED_HACK
+ }
+#endif
+ s << ';' << endl << endl;
+
+
+ bool pythonWrapperRefCounting = metaField->type()->typeEntry()->isObject()
+ || metaField->type()->isValuePointer();
+ if (pythonWrapperRefCounting) {
+ s << INDENT << "Shiboken::keepReference(reinterpret_cast<SbkBaseWrapper*>(self), \"";
+ s << metaField->name() << "\", value);" << endl;
+ //s << INDENT << "Py_XDECREF(oldvalue);" << endl;
+ s << endl;
+ }
+
+ s << INDENT << "return 0;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeRichCompareFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static PyObject* ";
+ s << baseName << "_richcompare(PyObject* self, PyObject* other, int op)" << endl;
+ s << '{' << endl;
+ QList<AbstractMetaFunctionList> cmpOverloads = filterGroupedOperatorFunctions(metaClass, AbstractMetaClass::ComparisonOp);
+ s << INDENT << "bool result = false;" << endl;
+ s << INDENT << metaClass->qualifiedCppName() << "& cpp_self = *" << cpythonWrapperCPtr(metaClass) << ';' << endl;
+ s << endl;
+
+ s << INDENT << "switch (op) {" << endl;
+ {
+ Indentation indent(INDENT);
+ foreach (AbstractMetaFunctionList overloads, cmpOverloads) {
+ OverloadData overloadData(overloads, this);
+ const AbstractMetaFunction* rfunc = overloads[0];
+
+ s << INDENT << "case " << ShibokenGenerator::pythonRichCompareOperatorId(rfunc) << ':' << endl;
+
+ Indentation indent(INDENT);
+
+ QString op = rfunc->originalName();
+ op = op.right(op.size() - QString("operator").size());
+
+ int alternativeNumericTypes = 0;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (!func->isStatic() &&
+ ShibokenGenerator::isNumber(func->arguments()[0]->type()->typeEntry()))
+ alternativeNumericTypes++;
+ }
+
+ bool first = true;
+ bool comparesWithSameType = false;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (func->isStatic())
+ continue;
+
+ const AbstractMetaType* type = func->arguments()[0]->type();
+ bool numberType = alternativeNumericTypes == 1 || ShibokenGenerator::isPyInt(type);
+
+ if (!comparesWithSameType)
+ comparesWithSameType = type->typeEntry() == metaClass->typeEntry();
+
+ if (!first) {
+ s << " else ";
+ } else {
+ first = false;
+ s << INDENT;
+ }
+
+ s << "if (" << cpythonIsConvertibleFunction(type, numberType) << "(other)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "// " << func->signature() << endl;
+ s << INDENT;
+ AbstractMetaClass* clz = classes().findClass(type->typeEntry());
+ if (type->typeEntry()->isValue()) {
+ Q_ASSERT(clz);
+ s << clz->qualifiedCppName() << '*';
+ } else
+ s << translateTypeForWrapperMethod(type, metaClass);
+ s << " cpp_other = ";
+ if (type->typeEntry()->isValue())
+ s << cpythonWrapperCPtr(type, "other");
+ else
+ writeToCppConversion(s, type, metaClass, "other");
+ s << ';' << endl;
+
+ s << INDENT << "result = ";
+ // It's a value type and the conversion for a pointer returned null.
+ if (type->typeEntry()->isValue()) {
+ s << "!cpp_other ? cpp_self == ";
+ writeToCppConversion(s, type, metaClass, "other", ExcludeReference | ExcludeConst);
+ s << " : ";
+ }
+ s << "(cpp_self " << op << ' ' << (type->typeEntry()->isValue() ? "(*" : "");
+ s << "cpp_other" << (type->typeEntry()->isValue() ? ")" : "") << ");" << endl;
+ }
+ s << INDENT << '}';
+ }
+
+ // Compares with implicit conversions
+ if (comparesWithSameType && !metaClass->implicitConversions().isEmpty()) {
+ AbstractMetaType temporaryType;
+ temporaryType.setTypeEntry(metaClass->typeEntry());
+ temporaryType.setConstant(true);
+ temporaryType.setReference(false);
+ temporaryType.setTypeUsagePattern(AbstractMetaType::ValuePattern);
+ s << " else if (" << cpythonIsConvertibleFunction(metaClass->typeEntry());
+ s << "(other)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ writeArgumentConversion(s, &temporaryType, "cpp_other", "other", metaClass);
+ s << INDENT << "result = (cpp_self " << op << " (*cpp_other));" << endl;
+ }
+ s << INDENT << '}';
+ }
+
+ s << " else goto " << baseName << "_RichComparison_TypeError;" << endl;
+ s << endl;
+
+ s << INDENT << "break;" << endl;
+ }
+ s << INDENT << "default:" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"operator not implemented.\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ }
+ s << INDENT << '}' << endl << endl;
+
+ s << INDENT << "if (result)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Py_RETURN_TRUE;" << endl;
+ }
+ s << INDENT << baseName << "_RichComparison_TypeError:" << endl;
+ s << INDENT << "Py_RETURN_FALSE;" << endl << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ Q_ASSERT(!overloads.isEmpty());
+ OverloadData overloadData(overloads, this);
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
+ const AbstractMetaFunction* func = overloadData.referenceFunction();
+ int min = overloadData.minArgs();
+ int max = overloadData.maxArgs();
+
+ s << '"' << func->name() << "\", (PyCFunction)" << cpythonFunctionName(func) << ", ";
+ if ((min == max) && (max < 2) && !usePyArgs) {
+ if (max == 0)
+ s << "METH_NOARGS";
+ else
+ s << "METH_O";
+ } else {
+ s << "METH_VARARGS";
+ if (overloadData.hasArgumentWithDefaultValue())
+ s << "|METH_KEYWORDS";
+ }
+ if (func->ownerClass() && overloadData.hasStaticFunction())
+ s << "|METH_STATIC";
+}
+
+void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ Q_ASSERT(!overloads.isEmpty());
+ const AbstractMetaFunction* func = overloads.first();
+ if (m_tpFuncs.contains(func->name()))
+ return;
+
+ s << INDENT;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
+ s << cpythonMethodDefinitionName(func);
+ } else {
+ s << '{';
+ writeMethodDefinitionEntry(s, overloads);
+ s << '}';
+ }
+ s << ',' << endl;
+}
+
+void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString cpythonName = cpythonEnumName(cppEnum);
+ QString addFunction;
+ if (cppEnum->enclosingClass())
+ addFunction = "PyDict_SetItemString(" + cpythonTypeName(cppEnum->enclosingClass()) + ".super.ht_type.tp_dict,";
+ else if (cppEnum->isAnonymous())
+ addFunction = "PyModule_AddIntConstant(module,";
+ else
+ addFunction = "PyModule_AddObject(module,";
+
+ s << INDENT << "// init ";
+ if (cppEnum->isAnonymous())
+ s << "anonymous enum identified by enum value: ";
+ else
+ s << "enum: ";
+ s << cppEnum->name() << endl;
+
+ if (!cppEnum->isAnonymous()) {
+ s << INDENT << cpythonTypeNameExt(cppEnum->typeEntry()) << " = &" << cpythonTypeName(cppEnum->typeEntry()) << ';' << endl;
+ s << INDENT << "if (PyType_Ready((PyTypeObject*)&" << cpythonName << "_Type) < 0)" << endl;
+ s << INDENT << INDENT << "return;" << endl;
+
+ s << INDENT << "Py_INCREF(&" << cpythonName << "_Type);" << endl;
+
+ s << INDENT << addFunction << endl;
+ s << INDENT << INDENT << INDENT << '\"' << cppEnum->name() << "\",";
+ s << "((PyObject*)&" << cpythonName << "_Type));" << endl << endl;
+
+ FlagsTypeEntry* flags = cppEnum->typeEntry()->flags();
+ if (flags) {
+ QString flagsName = cpythonFlagsName(flags);
+ s << INDENT << "// init flags class: " << flags->name() << endl;
+ s << INDENT << cpythonTypeNameExt(flags) << " = &" << cpythonTypeName(flags) << ';' << endl;
+
+ s << INDENT << "if (PyType_Ready((PyTypeObject*)&" << flagsName << "_Type) < 0)" << endl;
+ s << INDENT << INDENT << "return;" << endl;
+
+ s << INDENT << "Py_INCREF(&" << flagsName << "_Type);" << endl;
+
+ s << INDENT << addFunction << endl;
+ s << INDENT << INDENT << INDENT << '\"' << flags->flagsName() << "\",";
+ s << "((PyObject*)&" << flagsName << "_Type));" << endl << endl;
+ }
+ }
+
+
+ foreach (const AbstractMetaEnumValue* enumValue, cppEnum->values()) {
+ if (cppEnum->typeEntry()->isEnumValueRejected(enumValue->name()))
+ continue;
+
+ QString enumValueText;
+#ifdef AVOID_PROTECTED_HACK
+ if (!cppEnum->isProtected()) {
+#endif
+ enumValueText = "(long) ";
+ if (cppEnum->enclosingClass())
+ enumValueText += cppEnum->enclosingClass()->qualifiedCppName() + "::";
+ enumValueText += enumValue->name();
+#ifdef AVOID_PROTECTED_HACK
+ } else {
+ enumValueText += enumValue->value();
+ }
+#endif
+
+ bool shouldDecrefNumber = false;
+ QString enumItemText = "enum_item";
+ if (!cppEnum->isAnonymous()) {
+ s << INDENT << "enum_item = Shiboken::SbkEnumObject_New(&";
+ s << cpythonName << "_Type," << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << enumValueText << ", \"" << enumValue->name() << "\");" << endl;
+ }
+ } else if (cppEnum->enclosingClass()) {
+ s << INDENT << "enum_item = PyInt_FromLong(" << enumValueText << ");" << endl;
+ shouldDecrefNumber = true;
+ } else {
+ enumItemText = enumValueText;
+ }
+
+ s << INDENT << addFunction << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << '"' << enumValue->name() << "\", " << enumItemText << ");" << endl;
+ }
+ if (shouldDecrefNumber)
+ s << INDENT << "Py_DECREF(enum_item);" << endl;
+
+ if (!cppEnum->isAnonymous()) {
+ s << INDENT << "PyDict_SetItemString(" << cpythonName << "_Type.tp_dict," << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << '"' << enumValue->name() << "\", enum_item);" << endl;
+ }
+ }
+
+ }
+
+ if (!cppEnum->isAnonymous()) {
+ // TypeResolver stuff
+ s << INDENT << "Shiboken::TypeResolver::createValueTypeResolver<int>(\"";
+ if (cppEnum->enclosingClass())
+ s << cppEnum->enclosingClass()->qualifiedCppName() << "::";
+ s << cppEnum->name() << "\");\n";
+ }
+
+
+ s << endl;
+}
+
+void CppGenerator::writeSignalInitialization(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QHash<QString, QStringList> signatures;
+
+ foreach (const AbstractMetaFunction* cppSignal, metaClass->cppSignalFunctions()) {
+ QString signature;
+ if (cppSignal->declaringClass() == metaClass) {
+ if (cppSignal->arguments().count()) {
+ for (int i = 0; i < cppSignal->arguments().count(); ++i) {
+ if (i > 0)
+ signature += ", ";
+ AbstractMetaArgument *a = cppSignal->arguments().at(i);
+ signature += a->type()->cppSignature();
+ }
+ } else {
+ signature = "void";
+ }
+ signatures[cppSignal->name()].append(QMetaObject::normalizedSignature(signature.toAscii()));
+ }
+ }
+
+ if (signatures.size() == 0)
+ return;
+
+ s << INDENT << "// Initialize signals" << endl;
+ s << INDENT << "PyObject* signal_item;" << endl << endl;
+
+ foreach(QString funcName, signatures.keys()) {
+ s << INDENT << "signal_item = PySide::signalNew(\"" << funcName <<"\"";
+ foreach(QString signature, signatures[funcName])
+ s << ", \"" + signature << "\"";
+ s << ", NULL);" << endl;
+ s << INDENT << "PyDict_SetItemString(" + cpythonTypeName(metaClass) + ".super.ht_type.tp_dict";
+ s << ", \"" << funcName << "\", signal_item);" << endl;
+ s << INDENT << "Py_DECREF(signal_item);" << endl;
+ }
+ s << endl;
+}
+
+void CppGenerator::writeEnumNewMethod(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString cpythonName = cpythonEnumName(cppEnum);
+ s << "static PyObject* ";
+ s << cpythonName << "_New(PyTypeObject* type, PyObject* args, PyObject* kwds)" << endl;
+ s << '{' << endl;
+ s << INDENT << "int item_value = 0;" << endl;
+ s << INDENT << "if (!PyArg_ParseTuple(args, \"|i:__new__\", &item_value))" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return 0;" << endl;
+ }
+ s << INDENT << "PyObject* self = Shiboken::SbkEnumObject_New(type, item_value);" << endl << endl;
+ s << INDENT << "if (!self)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return 0;" << endl;
+ }
+ s << INDENT << "return self;" << endl << '}' << endl;
+}
+
+void CppGenerator::writeEnumDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString cpythonName = cpythonEnumName(cppEnum);
+ QString tp_as_number("0");
+ if (cppEnum->typeEntry()->flags())
+ tp_as_number = QString("&%1_as_number").arg(cpythonName);
+
+
+ s << "static PyGetSetDef " << cpythonName << "_getsetlist[] = {" << endl;
+ s << INDENT << "{const_cast<char*>(\"name\"), (getter)Shiboken::SbkEnumObject_name}," << endl;
+ s << INDENT << "{0} // Sentinel" << endl;
+ s << "};" << endl << endl;
+
+ QString newFunc = cpythonName + "_New";
+
+ s << "// forward declaration of new function" << endl;
+ s << "static PyObject* " << newFunc << "(PyTypeObject*, PyObject*, PyObject*);" << endl << endl;
+
+ s << "static PyTypeObject " << cpythonName << "_Type = {" << endl;
+ s << INDENT << "PyObject_HEAD_INIT(&Shiboken::SbkEnumType_Type)" << endl;
+ s << INDENT << "/*ob_size*/ 0," << endl;
+ s << INDENT << "/*tp_name*/ \"" << cppEnum->name() << "\"," << endl;
+ s << INDENT << "/*tp_basicsize*/ sizeof(Shiboken::SbkEnumObject)," << endl;
+ s << INDENT << "/*tp_itemsize*/ 0," << endl;
+ s << INDENT << "/*tp_dealloc*/ 0," << endl;
+ s << INDENT << "/*tp_print*/ 0," << endl;
+ s << INDENT << "/*tp_getattr*/ 0," << endl;
+ s << INDENT << "/*tp_setattr*/ 0," << endl;
+ s << INDENT << "/*tp_compare*/ 0," << endl;
+ s << INDENT << "/*tp_repr*/ Shiboken::SbkEnumObject_repr," << endl;
+ s << INDENT << "/*tp_as_number*/ " << tp_as_number << ',' << endl;
+ s << INDENT << "/*tp_as_sequence*/ 0," << endl;
+ s << INDENT << "/*tp_as_mapping*/ 0," << endl;
+ s << INDENT << "/*tp_hash*/ 0," << endl;
+ s << INDENT << "/*tp_call*/ 0," << endl;
+ s << INDENT << "/*tp_str*/ Shiboken::SbkEnumObject_repr," << endl;
+ s << INDENT << "/*tp_getattro*/ 0," << endl;
+ s << INDENT << "/*tp_setattro*/ 0," << endl;
+ s << INDENT << "/*tp_as_buffer*/ 0," << endl;
+ s << INDENT << "/*tp_flags*/ Py_TPFLAGS_DEFAULT," << endl;
+ s << INDENT << "/*tp_doc*/ 0," << endl;
+ s << INDENT << "/*tp_traverse*/ 0," << endl;
+ s << INDENT << "/*tp_clear*/ 0," << endl;
+ s << INDENT << "/*tp_richcompare*/ 0," << endl;
+ s << INDENT << "/*tp_weaklistoffset*/ 0," << endl;
+ s << INDENT << "/*tp_iter*/ 0," << endl;
+ s << INDENT << "/*tp_iternext*/ 0," << endl;
+ s << INDENT << "/*tp_methods*/ 0," << endl;
+ s << INDENT << "/*tp_members*/ 0," << endl;
+ s << INDENT << "/*tp_getset*/ " << cpythonName << "_getsetlist," << endl;
+ s << INDENT << "/*tp_base*/ &PyInt_Type," << endl;
+ s << INDENT << "/*tp_dict*/ 0," << endl;
+ s << INDENT << "/*tp_descr_get*/ 0," << endl;
+ s << INDENT << "/*tp_descr_set*/ 0," << endl;
+ s << INDENT << "/*tp_dictoffset*/ 0," << endl;
+ s << INDENT << "/*tp_init*/ 0," << endl;
+ s << INDENT << "/*tp_alloc*/ 0," << endl;
+ s << INDENT << "/*tp_new*/ " << newFunc << ',' << endl;
+ s << INDENT << "/*tp_free*/ 0," << endl;
+ s << INDENT << "/*tp_is_gc*/ 0," << endl;
+ s << INDENT << "/*tp_bases*/ 0," << endl;
+ s << INDENT << "/*tp_mro*/ 0," << endl;
+ s << INDENT << "/*tp_cache*/ 0," << endl;
+ s << INDENT << "/*tp_subclasses*/ 0," << endl;
+ s << INDENT << "/*tp_weaklist*/ 0" << endl;
+ s << "};" << endl << endl;
+
+ writeEnumNewMethod(s, cppEnum);
+ s << endl;
+}
+
+void CppGenerator::writeFlagsMethods(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ writeFlagsBinaryOperator(s, cppEnum, "and", "&");
+ writeFlagsBinaryOperator(s, cppEnum, "or", "|");
+ writeFlagsBinaryOperator(s, cppEnum, "xor", "^");
+
+ writeFlagsUnaryOperator(s, cppEnum, "invert", "~");
+ s << endl;
+}
+
+void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString cpythonName = cpythonEnumName(cppEnum);
+
+ s << "static PyNumberMethods " << cpythonName << "_as_number = {" << endl;
+ s << INDENT << "/*nb_add*/ 0," << endl;
+ s << INDENT << "/*nb_subtract*/ 0," << endl;
+ s << INDENT << "/*nb_multiply*/ 0," << endl;
+ s << INDENT << "/*nb_divide*/ 0," << endl;
+ s << INDENT << "/*nb_remainder*/ 0," << endl;
+ s << INDENT << "/*nb_divmod*/ 0," << endl;
+ s << INDENT << "/*nb_power*/ 0," << endl;
+ s << INDENT << "/*nb_negative*/ 0," << endl;
+ s << INDENT << "/*nb_positive*/ 0," << endl;
+ s << INDENT << "/*nb_absolute*/ 0," << endl;
+ s << INDENT << "/*nb_nonzero*/ 0," << endl;
+ s << INDENT << "/*nb_invert*/ (unaryfunc)" << cpythonName << "___invert__" << "," << endl;
+ s << INDENT << "/*nb_lshift*/ 0," << endl;
+ s << INDENT << "/*nb_rshift*/ 0," << endl;
+ s << INDENT << "/*nb_and*/ (binaryfunc)" << cpythonName << "___and__" << ',' << endl;
+ s << INDENT << "/*nb_xor*/ (binaryfunc)" << cpythonName << "___xor__" << ',' << endl;
+ s << INDENT << "/*nb_or*/ (binaryfunc)" << cpythonName << "___or__" << ',' << endl;
+ s << INDENT << "/*nb_coerce*/ 0," << endl;
+ s << INDENT << "/*nb_int*/ 0," << endl;
+ s << INDENT << "/*nb_long*/ 0," << endl;
+ s << INDENT << "/*nb_float*/ 0," << endl;
+ s << INDENT << "/*nb_oct*/ 0," << endl;
+ s << INDENT << "/*nb_hex*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_add*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_subtract*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_multiply*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_remainder*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_power*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_lshift*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_rshift*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_and*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_xor*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_or*/ 0," << endl;
+ s << INDENT << "/*nb_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_index*/ 0" << endl;
+ s << "};" << endl << endl;
+}
+
+void CppGenerator::writeFlagsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ if (!flagsEntry)
+ return;
+ QString cpythonName = cpythonFlagsName(flagsEntry);
+ QString enumName = cpythonEnumName(cppEnum);
+
+ s << "// forward declaration of new function" << endl;
+ s << "static PyTypeObject " << cpythonName << "_Type = {" << endl;
+ s << INDENT << "PyObject_HEAD_INIT(&PyType_Type)" << endl;
+ s << INDENT << "/*ob_size*/ 0," << endl;
+ s << INDENT << "/*tp_name*/ \"" << flagsEntry->flagsName() << "\"," << endl;
+ s << INDENT << "/*tp_basicsize*/ 0," << endl;
+ s << INDENT << "/*tp_itemsize*/ 0," << endl;
+ s << INDENT << "/*tp_dealloc*/ 0," << endl;
+ s << INDENT << "/*tp_print*/ 0," << endl;
+ s << INDENT << "/*tp_getattr*/ 0," << endl;
+ s << INDENT << "/*tp_setattr*/ 0," << endl;
+ s << INDENT << "/*tp_compare*/ 0," << endl;
+ s << INDENT << "/*tp_repr*/ 0," << endl;
+ s << INDENT << "/*tp_as_number*/ " << enumName << "_Type.tp_as_number," << endl;
+ s << INDENT << "/*tp_as_sequence*/ 0," << endl;
+ s << INDENT << "/*tp_as_mapping*/ 0," << endl;
+ s << INDENT << "/*tp_hash*/ 0," << endl;
+ s << INDENT << "/*tp_call*/ 0," << endl;
+ s << INDENT << "/*tp_str*/ 0," << endl;
+ s << INDENT << "/*tp_getattro*/ 0," << endl;
+ s << INDENT << "/*tp_setattro*/ 0," << endl;
+ s << INDENT << "/*tp_as_buffer*/ 0," << endl;
+ s << INDENT << "/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES," << endl;
+ s << INDENT << "/*tp_doc*/ 0," << endl;
+ s << INDENT << "/*tp_traverse*/ 0," << endl;
+ s << INDENT << "/*tp_clear*/ 0," << endl;
+ s << INDENT << "/*tp_richcompare*/ 0," << endl;
+ s << INDENT << "/*tp_weaklistoffset*/ 0," << endl;
+ s << INDENT << "/*tp_iter*/ 0," << endl;
+ s << INDENT << "/*tp_iternext*/ 0," << endl;
+ s << INDENT << "/*tp_methods*/ 0," << endl;
+ s << INDENT << "/*tp_members*/ 0," << endl;
+ s << INDENT << "/*tp_getset*/ 0," << endl;
+ s << INDENT << "/*tp_base*/ &PyInt_Type," << endl;
+ s << INDENT << "/*tp_dict*/ 0," << endl;
+ s << INDENT << "/*tp_descr_get*/ 0," << endl;
+ s << INDENT << "/*tp_descr_set*/ 0," << endl;
+ s << INDENT << "/*tp_dictoffset*/ 0," << endl;
+ s << INDENT << "/*tp_init*/ 0," << endl;
+ s << INDENT << "/*tp_alloc*/ 0," << endl;
+ s << INDENT << "/*tp_new*/ PyInt_Type.tp_new," << endl;
+ s << INDENT << "/*tp_free*/ 0," << endl;
+ s << INDENT << "/*tp_is_gc*/ 0," << endl;
+ s << INDENT << "/*tp_bases*/ 0," << endl;
+ s << INDENT << "/*tp_mro*/ 0," << endl;
+ s << INDENT << "/*tp_cache*/ 0," << endl;
+ s << INDENT << "/*tp_subclasses*/ 0," << endl;
+ s << INDENT << "/*tp_weaklist*/ 0" << endl;
+ s << "};" << endl << endl;
+}
+
+void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ Q_ASSERT(flagsEntry);
+
+ QString converter = "Shiboken::Converter<" + flagsEntry->originalName() + " >::";
+
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* self, PyObject* arg)" << endl;
+ s << '{' << endl;
+
+ // We need to check the type of self because self and arg can be swapped
+ s << INDENT << "if (" << converter << "checkType(self) && " << converter << "checkType(arg))" << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_Format(PyExc_TypeError, \"unsupported operand type(s) for %s: '%s' and '%s'\", \""
+ << cppOpName << "\", self->ob_type->tp_name, arg->ob_type->tp_name);" << endl;
+ s << INDENT << "return 0;" << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+
+ s << INDENT << "return Shiboken::Converter< " << flagsEntry->originalName() << " >::toPython(" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::Converter<" << flagsEntry->originalName() << ">::toCpp(self)" << endl;
+ s << INDENT << cppOpName << " Shiboken::Converter< ";
+ s << flagsEntry->originalName() << " >::toCpp(arg)" << endl;
+ }
+ s << INDENT << ");" << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName, bool boolResult)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ Q_ASSERT(flagsEntry);
+
+ QString converter = "Shiboken::Converter<" + flagsEntry->originalName() + " >::";
+
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* self, PyObject* arg)" << endl;
+ s << '{' << endl;
+ s << INDENT << "return Shiboken::Converter< " << (boolResult ? "bool" : flagsEntry->originalName());
+ s << " >::toPython(" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << cppOpName << converter << "toCpp(self)" << endl;
+ }
+ s << INDENT << ");" << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString pyTypeName = cpythonTypeName(metaClass);
+ s << "void init_" << metaClass->qualifiedCppName().replace("::", "_") << "(PyObject* module)" << endl;
+ s << '{' << endl;
+ s << INDENT << cpythonTypeNameExt(metaClass->typeEntry()) << " = reinterpret_cast<PyTypeObject*>(&" << cpythonTypeName(metaClass->typeEntry()) << ");" << endl << endl;
+
+ // class inject-code target/beginning
+ if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::Beginning, TypeSystem::TargetLangCode, 0, 0, metaClass);
+ s << endl;
+ }
+
+ 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) {
+ s << INDENT << pyTypeName << ".super.ht_type.tp_bases = PyTuple_Pack(";
+ s << baseClasses.size();
+ s << ',' << endl;
+ QStringList bases;
+ foreach (const AbstractMetaClass* base, baseClasses)
+ bases << "(PyTypeObject*)"+cpythonTypeNameExt(base->typeEntry());
+ Indentation indent(INDENT);
+ s << INDENT << bases.join(", ") << ");" << endl << endl;
+ }
+
+ // Fill multiple inheritance init function, if needed.
+ const AbstractMetaClass* miClass = getMultipleInheritingClass(metaClass);
+ if (miClass && miClass != metaClass) {
+ s << INDENT << cpythonTypeName(metaClass) << ".mi_init = ";
+ s << "reinterpret_cast<SbkBaseWrapperType*>(" + cpythonTypeNameExt(miClass->typeEntry()) + ")->mi_init;" << endl << endl;
+ }
+
+ // 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 = &" << 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;
+ }
+
+ s << INDENT << "if (PyType_Ready((PyTypeObject*)&" << pyTypeName << ") < 0)" << endl;
+ s << INDENT << INDENT << "return;" << endl << endl;
+
+ if (metaClass->enclosingClass() && (metaClass->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass) ) {
+ s << INDENT << "PyDict_SetItemString(module,"
+ << "\"" << metaClass->name() << "\", (PyObject*)&" << pyTypeName << ");" << endl;
+ } else {
+ s << INDENT << "Py_INCREF(reinterpret_cast<PyObject*>(&" << pyTypeName << "));" << endl;
+ s << INDENT << "PyModule_AddObject(module, \"" << metaClass->name() << "\"," << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "((PyObject*)&" << pyTypeName << "));" << endl << endl;
+ }
+
+ if (!metaClass->enums().isEmpty()) {
+ s << INDENT << "// Initialize enums" << endl;
+ s << INDENT << "PyObject* enum_item;" << endl << endl;
+ }
+
+ foreach (const AbstractMetaEnum* cppEnum, metaClass->enums())
+ writeEnumInitialization(s, cppEnum);
+
+ if (metaClass->hasSignals())
+ writeSignalInitialization(s, metaClass);
+
+ // Write static fields
+ foreach (const AbstractMetaField* field, metaClass->fields()) {
+ if (!field->isStatic())
+ continue;
+ s << INDENT << "PyDict_SetItemString(" + cpythonTypeName(metaClass) + ".super.ht_type.tp_dict, \"";
+ s << field->name() << "\", ";
+ writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + "::" + field->name());
+ s << ");" << endl;
+ }
+ s << endl;
+
+ // class inject-code target/end
+ if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
+ s << endl;
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::End, TypeSystem::TargetLangCode, 0, 0, metaClass);
+ }
+
+ if (!metaClass->isNamespace()) {
+ bool isObjectType = metaClass->typeEntry()->isObject();
+ QString typeName = metaClass->qualifiedCppName();
+ if (!isObjectType)
+ s << INDENT << "Shiboken::TypeResolver::createValueTypeResolver<" << typeName << " >" << "(\"" << typeName << "\");\n";
+
+ s << INDENT << "Shiboken::TypeResolver::createObjectTypeResolver<" << typeName << " >" << "(\"" << typeName << "*\");\n";
+
+ QString functionSufix = (isObjectType ? "Object" : "Value");
+ s << INDENT << "Shiboken::TypeResolver::create" << functionSufix;
+ s << "TypeResolver<" << typeName << " >" << "(typeid(" << typeName << ").name());\n";
+ if (shouldGenerateCppWrapper(metaClass)) {
+ s << INDENT << "Shiboken::TypeResolver::create" << functionSufix;
+ s << "TypeResolver<" << typeName << " >" << "(typeid(" << wrapperName(metaClass) << ").name());\n";
+ }
+ }
+
+ if (usePySideExtensions() && !metaClass->isNamespace()) {
+ // Qt metatypes are registered only on their first use, so we do this now.
+ const char* star = metaClass->typeEntry()->isObject() ? "*" : "";
+ s << INDENT << "PySide::initQtMetaType<" << metaClass->qualifiedCppName() << star << " >();" << endl;
+ }
+
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue();
+
+ s << "static SbkBaseWrapperType* " << cpythonBaseName(metaClass) << "_typeDiscovery(void* cptr, SbkBaseWrapperType* instanceType)\n{" << endl;
+
+ if (!metaClass->baseClass()) {
+ s << INDENT << "TypeResolver* typeResolver = TypeResolver::get(typeid(*reinterpret_cast<"
+ << metaClass->qualifiedCppName() << "*>(cptr)).name());" << endl;
+ s << INDENT << "if (typeResolver)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return reinterpret_cast<SbkBaseWrapperType*>(typeResolver->pythonType());" << endl;
+ }
+ } 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";
+}
+
+void CppGenerator::writeSetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* self, PyObject* name, PyObject* value)" << endl;
+ s << '{' << endl;
+ if (usePySideExtensions()) {
+ s << INDENT << "Shiboken::AutoDecRef pp(PySide::qproperty_get_object(self, name));" << endl;
+ s << INDENT << "if (!pp.isNull())" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << INDENT << "return PySide::qproperty_set(pp, self, value);" << endl;
+ }
+ s << INDENT << "return PyObject_GenericSetAttr(self, name, value);" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeGetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* self, PyObject* name)" << endl;
+ s << '{' << endl;
+ if (classNeedsGetattroFunction(metaClass)) {
+ s << INDENT << "if (self) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "if (SbkBaseWrapper_instanceDict(self)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* meth = PyDict_GetItem(SbkBaseWrapper_instanceDict(self), name);" << endl;
+ s << INDENT << "if (meth) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Py_INCREF(meth);" << endl;
+ s << INDENT << "return meth;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "const char* cname = PyString_AS_STRING(name);" << endl;
+ foreach (const AbstractMetaFunction* func, getMethodsWithBothStaticAndNonStaticMethods(metaClass)) {
+ s << INDENT << "if (strcmp(cname, \"" << func->name() << "\") == 0)" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return PyCFunction_NewEx(&" << cpythonMethodDefinitionName(func) << ", self, 0);" << endl;
+ }
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << "PyObject* attr = PyObject_GenericGetAttr(self, name);" << endl;
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ s << INDENT << "if (attr && PySide::isQPropertyType(attr)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject *value = PySide::qproperty_get(attr, self);" << endl;
+ s << INDENT << "if (!value)" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << "Py_DECREF(attr);" << endl;
+ s << INDENT << "Py_INCREF(value);" << endl;
+ s << INDENT << "attr = value;" << endl;
+ }
+ s << INDENT << "}" << endl;
+ }
+ s << INDENT << "return attr;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::finishGeneration()
+{
+ //Generate CPython wrapper file
+ QString classInitDecl;
+ QTextStream s_classInitDecl(&classInitDecl);
+ QString classPythonDefines;
+ QTextStream s_classPythonDefines(&classPythonDefines);
+
+ QSet<Include> includes;
+ QString globalFunctionImpl;
+ QTextStream s_globalFunctionImpl(&globalFunctionImpl);
+ QString globalFunctionDecl;
+ QTextStream s_globalFunctionDef(&globalFunctionDecl);
+
+ Indentation indent(INDENT);
+
+ foreach (AbstractMetaFunctionList globalOverloads, getFunctionGroups().values()) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, globalOverloads) {
+ if (!func->isModifiedRemoved()) {
+ overloads.append(func);
+ if (func->typeEntry())
+ includes << func->typeEntry()->include();
+ }
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ writeMethodWrapper(s_globalFunctionImpl, overloads);
+ writeMethodDefinition(s_globalFunctionDef, overloads);
+ }
+
+ foreach (const AbstractMetaClass* cls, classes()) {
+ if (!shouldGenerate(cls))
+ continue;
+
+ s_classInitDecl << "void init_" << cls->qualifiedCppName().replace("::", "_") << "(PyObject* module);" << endl;
+
+ QString defineStr = "init_" + cls->qualifiedCppName().replace("::", "_");
+
+ if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass))
+ defineStr += "(" + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) +"->tp_dict);";
+ else
+ defineStr += "(module);";
+ s_classPythonDefines << INDENT << defineStr << endl;
+ }
+
+ QString moduleFileName(outputDirectory() + "/" + subDirectoryForPackage(packageName()));
+ moduleFileName += "/" + moduleName().toLower() + "_module_wrapper.cpp";
+
+ QFile file(moduleFileName);
+ if (file.open(QFile::WriteOnly)) {
+ QTextStream s(&file);
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ s << "#include <Python.h>" << endl;
+ s << "#include <shiboken.h>" << endl;
+ s << "#include <algorithm>" << endl;
+
+ s << "#include \"" << getModuleHeaderFileName() << '"' << endl << endl;
+ foreach (const Include& include, includes)
+ s << include;
+ s << endl;
+
+ TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(TypeDatabase::instance()->findType(packageName()));
+ CodeSnipList snips;
+ if (moduleEntry)
+ snips = moduleEntry->codeSnips();
+
+ // module inject-code native/beginning
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, CodeSnip::Beginning, TypeSystem::NativeCode);
+ s << endl;
+ }
+
+ s << "// Global functions ";
+ s << "------------------------------------------------------------" << endl;
+ s << globalFunctionImpl << endl;
+
+ s << "static PyMethodDef " << moduleName() << "_methods[] = {" << endl;
+ s << globalFunctionDecl;
+ s << INDENT << "{0} // Sentinel" << endl << "};" << endl << endl;
+
+ s << "// Classes initialization functions ";
+ s << "------------------------------------------------------------" << endl;
+ s << classInitDecl << endl;
+
+ if (!globalEnums().isEmpty()) {
+ QString converterImpl;
+ QTextStream convImpl(&converterImpl);
+
+ s << "// Enum definitions ";
+ s << "------------------------------------------------------------" << endl;
+ foreach (const AbstractMetaEnum* cppEnum, globalEnums()) {
+ if (cppEnum->isAnonymous())
+ continue;
+ writeEnumDefinition(s, cppEnum);
+ s << endl;
+ }
+
+ if (!converterImpl.isEmpty()) {
+ s << "// Enum converters ";
+ s << "------------------------------------------------------------" << endl;
+ s << "namespace Shiboken" << endl << '{' << endl;
+ s << converterImpl << endl;
+ s << "} // namespace Shiboken" << endl << endl;
+ }
+ }
+
+ s << "PyTypeObject** " << cppApiVariableName() << ";" << endl << endl;;
+ foreach (const QString& requiredModule, TypeDatabase::instance()->requiredTargetImports())
+ s << "PyTypeObject** " << cppApiVariableName(requiredModule) << ";" << endl << endl;;
+
+ s << "// Module initialization ";
+ s << "------------------------------------------------------------" << endl;
+ ExtendedConverterData extendedConverters = getExtendedConverters();
+ if (!extendedConverters.isEmpty())
+ s << "// Extended Converters" << endl;
+ foreach (const TypeEntry* externalType, extendedConverters.keys()) {
+ writeExtendedIsConvertibleFunction(s, externalType, extendedConverters[externalType]);
+ writeExtendedToCppFunction(s, externalType, extendedConverters[externalType]);
+ s << endl;
+ }
+ s << endl;
+
+
+ s << "#if defined _WIN32 || defined __CYGWIN__" << endl;
+ s << " #define SBK_EXPORT_MODULE __declspec(dllexport)" << endl;
+ s << "#elif __GNUC__ >= 4" << endl;
+ s << " #define SBK_EXPORT_MODULE __attribute__ ((visibility(\"default\")))" << endl;
+ s << "#else" << endl;
+ s << " #define SBK_EXPORT_MODULE" << endl;
+ s << "#endif" << endl << endl;
+
+ s << "extern \"C\" SBK_EXPORT_MODULE void init" << moduleName() << "()" << endl;
+ s << '{' << endl;
+
+ // module inject-code target/beginning
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, CodeSnip::Beginning, TypeSystem::TargetLangCode);
+ s << endl;
+ }
+
+ foreach (const QString& requiredModule, TypeDatabase::instance()->requiredTargetImports()) {
+ s << INDENT << "if (!Shiboken::importModule(\"" << requiredModule << "\", &" << cppApiVariableName(requiredModule) << ")) {" << endl;
+ s << INDENT << INDENT << "PyErr_SetString(PyExc_ImportError," << "\"could not import ";
+ s << requiredModule << "\");" << endl << INDENT << INDENT << "return;" << endl;
+ s << INDENT << "}" << endl << endl;
+ }
+
+ s << INDENT << "Shiboken::initShiboken();" << endl;
+ s << INDENT << "PyObject* module = Py_InitModule(\"" << moduleName() << "\", ";
+ s << moduleName() << "_methods);" << endl << endl;
+
+ s << INDENT << "// Create a CObject containing the API pointer array's address" << endl;
+ s << INDENT << "static PyTypeObject* cppApi[" << "SBK_" << moduleName() << "_IDX_COUNT" << "];" << endl;
+ s << INDENT << cppApiVariableName() << " = cppApi;" << endl;
+ s << INDENT << "PyObject* cppApiObject = PyCObject_FromVoidPtr(reinterpret_cast<void*>(cppApi), 0);" << endl;
+ s << INDENT << "PyModule_AddObject(module, \"_Cpp_Api\", cppApiObject);" << endl << endl;
+ s << INDENT << "// Initialize classes in the type system" << endl;
+ s << classPythonDefines;
+
+ if (!extendedConverters.isEmpty()) {
+ s << INDENT << "// Initialize extended Converters" << endl;
+ s << INDENT << "Shiboken::SbkBaseWrapperType* shiboType;" << endl << endl;
+ }
+ foreach (const TypeEntry* externalType, extendedConverters.keys()) {
+ writeExtendedConverterInitialization(s, externalType, extendedConverters[externalType]);
+ s << endl;
+ }
+ s << endl;
+
+ if (!globalEnums().isEmpty()) {
+ s << INDENT << "// Initialize enums" << endl;
+ s << INDENT << "PyObject* enum_item;" << endl << endl;
+ }
+
+ foreach (const AbstractMetaEnum* cppEnum, globalEnums())
+ writeEnumInitialization(s, cppEnum);
+
+ // Register primitive types on TypeResolver
+ s << INDENT << "// Register primitive types on TypeResolver" << endl;
+ foreach(const PrimitiveTypeEntry* pte, primitiveTypes()) {
+ if (pte->generateCode())
+ s << INDENT << "Shiboken::TypeResolver::createValueTypeResolver<" << pte->name() << " >(\"" << pte->name() << "\");" << endl;
+ }
+ // Register type resolver for all containers found in signals.
+ QSet<QString> typeResolvers;
+ foreach (AbstractMetaClass* metaClass, classes()) {
+ if (!metaClass->isQObject() || !metaClass->typeEntry()->generateCode())
+ continue;
+ foreach (AbstractMetaFunction* func, metaClass->functions()) {
+ if (func->isSignal()) {
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ if (arg->type()->isContainer()) {
+ QString value = translateType(arg->type(), metaClass);
+ typeResolvers << QMetaObject::normalizedType(value.toAscii().constData());
+ }
+ }
+ }
+ }
+ }
+ foreach (QString type, typeResolvers)
+ s << INDENT << "Shiboken::TypeResolver::createValueTypeResolver<" << type << " >(\"" << type << "\");" << endl;
+
+ s << endl << INDENT << "if (PyErr_Occurred()) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "PyErr_Print();" << endl;
+ s << INDENT << "Py_FatalError(\"can't initialize module " << moduleName() << "\");" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ // module inject-code target/end
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, CodeSnip::End, TypeSystem::TargetLangCode);
+ s << endl;
+ }
+
+ s << '}' << endl << endl;
+
+ // module inject-code native/end
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, CodeSnip::End, TypeSystem::NativeCode);
+ s << endl;
+ }
+ }
+}
+
+bool CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool useHeuristicPolicy)
+{
+ const int numArgs = func->arguments().count();
+ const AbstractMetaClass* cppClass = func->ownerClass();
+ const AbstractMetaClass* dClass = func->declaringClass();
+ bool ctorHeuristicEnabled = func->isConstructor() && useCtorHeuristic() && useHeuristicPolicy;
+
+ QString parentVariable;
+ QString childVariable;
+ ArgumentOwner argOwner = func->argumentOwner(cppClass, argIndex);
+
+ if (argOwner.index == -2) //invalid
+ argOwner = func->argumentOwner(dClass, argIndex);
+
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(OverloadData(getFunctionGroups(func->implementingClass())[func->name()], this));
+
+ ArgumentOwner::Action action = argOwner.action;
+ int parentIndex = argOwner.index;
+ int childIndex = argIndex;
+ if (ctorHeuristicEnabled && argIndex > 0 && numArgs) {
+ AbstractMetaArgument* arg = func->arguments().at(argIndex-1);
+ if (arg->name() == "parent" && (arg->type()->isObject() || arg->type()->isQObject())) {
+ action = ArgumentOwner::Add;
+ parentIndex = argIndex;
+ childIndex = -1;
+ }
+ }
+
+ if (action != ArgumentOwner::Invalid) {
+ if (!usePyArgs && argIndex > 1)
+ ReportHandler::warning("Argument index for parent tag out of bounds: "+func->signature());
+
+ if (action == ArgumentOwner::Remove) {
+ parentVariable = "Py_None";
+ } else {
+ if (parentIndex == 0)
+ parentVariable = PYTHON_RETURN_VAR;
+ else if (parentIndex == -1)
+ parentVariable = "self";
+ else
+ parentVariable = usePyArgs ? "pyargs["+QString::number(parentIndex-1)+"]" : "arg";
+ }
+
+ if (childIndex == 0)
+ childVariable = PYTHON_RETURN_VAR;
+ else if (childIndex == -1)
+ childVariable = "self";
+ else
+ childVariable = usePyArgs ? "pyargs["+QString::number(childIndex-1)+"]" : "arg";
+
+ s << INDENT << "Shiboken::setParent(" << parentVariable << ", " << childVariable << ");\n";
+
+ return true;
+ }
+
+ if (argIndex == 0 && useHeuristicPolicy)
+ writeReturnValueHeuristics(s, func);
+
+ return false;
+}
+
+void CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool useHeuristicForReturn)
+{
+ const int numArgs = func->arguments().count();
+
+ // -1 = return value
+ // 0 = self
+ // 1..n = func. args.
+ for (int i = -1; i <= numArgs; ++i)
+ writeParentChildManagement(s, func, i, i == 0 ? useHeuristicForReturn : true);
+}
+
+void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self)
+{
+ AbstractMetaType *type = func->type();
+ if (!useReturnValueHeuristic()
+ || !func->ownerClass()
+ || !type
+ || func->isStatic()
+ || !func->typeReplaced(0).isEmpty()) {
+ return;
+ }
+
+ if (type->isQObject() || type->isObject() || type->isValuePointer())
+ s << INDENT << "Shiboken::setParent(" << self << ", " PYTHON_RETURN_VAR ");" << endl;
+}
+
+void CppGenerator::writeHashFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ s << "static long " << cpythonBaseName(metaClass) << "_HashFunc(PyObject* obj)";
+ s << '{' << endl;
+ s << INDENT << "return " << metaClass->typeEntry()->hashFunction() << '(';
+ writeToCppConversion(s, metaClass, "obj");
+ s << ");" << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeObjCopierFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ if (!(metaClass->typeEntry()->isValue() && shouldGenerateCppWrapper(metaClass)))
+ return;
+ s << "static void* " << cpythonBaseName(metaClass) << "_ObjCopierFunc(const void* ptr)";
+ s << '{' << endl;
+ s << INDENT << "return new " << wrapperName(metaClass) << "(*reinterpret_cast<const " << metaClass->qualifiedCppName() << "*>(ptr));\n";
+ s << '}' << endl << endl;
+
+}
+
+void CppGenerator::writeStdListWrapperMethods(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ //len
+ s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__" << "(PyObject* self)" << endl << '{' << endl;
+ s << INDENT << "if (Shiboken::cppObjectIsInvalid(self))" << endl;
+ s << INDENT << INDENT << "return 0;" << endl << endl;
+ s << INDENT << metaClass->qualifiedCppName() << " &cppSelf = Shiboken::Converter<" << metaClass->qualifiedCppName() <<"& >::toCpp(self);" << endl;
+ s << INDENT << "return cppSelf.size();" << endl;
+ s << "}" << endl;
+
+ //getitem
+ s << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__" << "(PyObject* self, Py_ssize_t _i)" << endl << '{' << endl;
+ s << INDENT << "if (Shiboken::cppObjectIsInvalid(self))" << endl;
+ s << INDENT << INDENT << "return 0;" << endl << endl;
+ s << INDENT << metaClass->qualifiedCppName() << " &cppSelf = Shiboken::Converter<" << metaClass->qualifiedCppName() <<"& >::toCpp(self);" << endl;
+ s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) cppSelf.size()) {" << endl;
+ s << INDENT << INDENT << "PyErr_SetString(PyExc_IndexError, \"index out of bounds\");" << endl;
+ s << INDENT << INDENT << "return 0;" << endl << INDENT << "}" << endl;
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = cppSelf.begin();" << endl;
+ s << INDENT << "for(Py_ssize_t pos=0; pos < _i; pos++) _item++;" << endl;
+ s << INDENT << "return Shiboken::Converter<" << metaClass->qualifiedCppName() << "::value_type>::toPython(*_item);" << endl;
+ s << "}" << endl;
+
+ //setitem
+ s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__" << "(PyObject* self, Py_ssize_t _i, PyObject* _value)" << endl << '{' << endl;
+ s << INDENT << "if (Shiboken::cppObjectIsInvalid(self))" << endl;
+ s << INDENT << INDENT << "return -1;" << endl;
+ s << INDENT << metaClass->qualifiedCppName() << " &cppSelf = Shiboken::Converter<" << metaClass->qualifiedCppName() <<"& >::toCpp(self);" << endl;
+ s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) cppSelf.size()) {" << endl;
+ s << INDENT << INDENT << "PyErr_SetString(PyExc_IndexError, \"list assignment index out of range\");" << endl;
+ s << INDENT << INDENT << "return -1;" << endl << INDENT << "}" << endl;
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = cppSelf.begin();" << endl;
+ s << INDENT << "for(Py_ssize_t pos=0; pos < _i; pos++) _item++;" << endl;
+
+ s << INDENT << metaClass->qualifiedCppName() << "::value_type cppValue = Shiboken::Converter<" << metaClass->qualifiedCppName() << "::value_type>::toCpp(_value);" << endl;
+ s << INDENT << "*_item = cppValue;" << endl;
+ s << INDENT << "return 0;";
+ s << endl << "}" << endl;
+}
+
+
diff --git a/generator/cppgenerator.h b/generator/cppgenerator.h
new file mode 100644
index 00000000..b4d68dc4
--- /dev/null
+++ b/generator/cppgenerator.h
@@ -0,0 +1,201 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009-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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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
+ *
+ */
+
+#ifndef CPPGENERATOR_H
+#define CPPGENERATOR_H
+
+#include "shibokengenerator.h"
+#include "overloaddata.h"
+
+/**
+ * The CppGenerator generate the implementations of C++ bindings classes.
+ */
+class CppGenerator : public ShibokenGenerator
+{
+public:
+ CppGenerator();
+protected:
+ QString fileNameForClass(const AbstractMetaClass* metaClass) const;
+ QList<AbstractMetaFunctionList> filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass,
+ uint query);
+ void generateClass(QTextStream& s, const AbstractMetaClass* metaClass);
+ void finishGeneration();
+
+private:
+ void writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func);
+ void writeDestructorNative(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeVirtualMethodNative(QTextStream& s, const AbstractMetaFunction* func);
+ void writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads);
+ void writeDestructorWrapper(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMinimalConstructorCallArguments(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMinimalConstructorCallArguments(QTextStream& s, const AbstractMetaType* type);
+ void writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads);
+ void writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData);
+ void writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunction* func);
+
+ void writeErrorSection(QTextStream& s, OverloadData& overloadData);
+ /**
+ * Writes the check section for the validity of wrapped C++ objects.
+ * \param s text stream to write
+ * \param argName Python argument name
+ * \param type the TypeEntry passed when the validity check must confirm the type of the Python wrapper to be checked
+ */
+ void writeInvalidCppObjectCheck(QTextStream& s, QString pyArgName = "self", const TypeEntry* type = 0);
+ void writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber = false, QString customType = "");
+ void writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName);
+
+ void writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeSetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeGetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ /**
+ * Writes Python to C++ conversions for arguments on Python wrappers.
+ * If implicit conversions, and thus new object allocation, are needed,
+ * code to deallocate a possible new instance is also generated.
+ * \param s text stream to write
+ * \param argType a pointer to the argument type to be converted
+ * \param argName C++ argument name
+ * \param pyArgName Python argument name
+ * \param context the current meta class
+ * \param defaultValue an optional default value to be used instead of the conversion result
+ */
+ void writeArgumentConversion(QTextStream& s, const AbstractMetaType* argType,
+ QString argName, QString pyArgName,
+ const AbstractMetaClass* context = 0,
+ QString defaultValue = QString());
+ /// Convenience method to call writeArgumentConversion with an AbstractMetaArgument instead of an AbstractMetaType.
+ void writeArgumentConversion(QTextStream& s, const AbstractMetaArgument* arg,
+ QString argName, QString pyArgName,
+ const AbstractMetaClass* context = 0,
+ QString defaultValue = QString())
+ {
+ writeArgumentConversion(s, arg->type(), argName, pyArgName, context, defaultValue);
+ }
+
+ /**
+ * Set the Python method wrapper return value variable to Py_None if
+ * there are return types different from void in any of the other overloads
+ * for the function passed as parameter.
+ * \param s text stream to write
+ * \param func a pointer to the function that will possibly return Py_None
+ * \param thereIsReturnValue indicates if the return type of any of the other overloads
+ * for this function is different from 'void'
+ */
+ void writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue);
+
+ /**
+ * Writes the Python function wrapper overload decisor that selects which C++
+ * method/function to call with the received Python arguments.
+ * \param s text stream to write
+ * \param overloadData the overload data describing all the possible overloads for the function/method
+ */
+ void writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData);
+ /// Recursive auxiliar method to the other writeOverloadedFunctionDecisor.
+ void writeOverloadedFunctionDecisorEngine(QTextStream& s, const OverloadData* parentOverloadData);
+
+ /// Writes calls to all the possible method/function overloads.
+ void writeFunctionCalls(QTextStream& s, const OverloadData& overloadData);
+
+ /// Writes the call to a single function usually from a collection of overloads.
+ void writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func = 0);
+ void writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs);
+
+ /// Returns a string containing the name of an argument for the given function and argument index.
+ QString argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass);
+ void writeMethodCall(QTextStream& s, const AbstractMetaFunction* func, int maxArgs = 0);
+
+ void writeClassRegister(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeClassDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads);
+ void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads);
+ /// Writes the implementation of all methods part of python sequence protocol
+ void writeSequenceMethods(QTextStream& s, const AbstractMetaClass* metaClass);
+ /// Writes the struct PySequenceMethods for types thats supports the python sequence protocol
+ void writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeGetterFunction(QTextStream& s, const AbstractMetaField* metaField);
+ void writeSetterFunction(QTextStream& s, const AbstractMetaField* metaField);
+
+ void writeRichCompareFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeEnumNewMethod(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeEnumDefinition(QTextStream& s, const AbstractMetaEnum* metaEnum);
+ void writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum);
+
+ void writeSignalInitialization(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeFlagsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsMethods(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsNumberMethodsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName);
+ 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);
+ /// Writes the implementation of special cast functions, used when we need to cast a class with mulltiple inheritance.
+ void writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeExtendedIsConvertibleFunction(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions);
+ void writeExtendedToCppFunction(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions);
+ void writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions);
+
+ void writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool userHeuristicForReturn);
+ bool writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool userHeuristicPolicy);
+ void writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self = "self");
+ /**
+ * 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);
+
+ /// Returns true if generator should produce getters and setters for the given class.
+ bool shouldGenerateGetSetList(const AbstractMetaClass* metaClass);
+
+ void writeHashFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeObjCopierFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ // Write default implementations for sequence protocol
+ void writeStdListWrapperMethods(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ // Maps special function names to function parameters and return types
+ // used by CPython API in the sequence protocol.
+ QHash<QString, QPair<QString, QString> > m_sequenceProtocol;
+ int m_currentErrorCode;
+};
+
+#endif // CPPGENERATOR_H
+
diff --git a/generator/headergenerator.cpp b/generator/headergenerator.cpp
new file mode 100644
index 00000000..2e060f42
--- /dev/null
+++ b/generator/headergenerator.cpp
@@ -0,0 +1,610 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009-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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 "headergenerator.h"
+#include <typedatabase.h>
+#include <reporthandler.h>
+#include <fileout.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QVariant>
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+
+QString HeaderGenerator::fileNameForClass(const AbstractMetaClass* metaClass) const
+{
+ return metaClass->qualifiedCppName().toLower().replace("::", "_") + QLatin1String("_wrapper.h");
+}
+
+void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const
+{
+ s << INDENT << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName() << "& self)";
+ s << " : " << metaClass->qualifiedCppName() << "(self)" << endl;
+ s << INDENT << "{" << endl;
+ s << INDENT << "}" << endl << endl;
+}
+
+void HeaderGenerator::writeProtectedFieldAccessors(QTextStream& s, const AbstractMetaField* field) const
+{
+ QString fieldType = field->type()->cppSignature();
+ QString fieldName = field->enclosingClass()->qualifiedCppName() + "::" + field->name();
+
+ s << INDENT << "inline " << fieldType << ' ' << protectedFieldGetterName(field) << "()";
+ s << " { return " << fieldName << "; }" << endl;
+ s << INDENT << "inline void " << protectedFieldSetterName(field) << '(' << fieldType << " value)";
+ s << " { " << fieldName << " = value; }" << endl;
+}
+
+void HeaderGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ ReportHandler::debugSparse("Generating header for " + metaClass->fullName());
+ Indentation indent(INDENT);
+
+ // write license comment
+ s << licenseComment();
+
+ QString wrapperName = HeaderGenerator::wrapperName(metaClass);
+ QString headerGuard = wrapperName.replace("::", "_").toUpper();
+
+ // Header
+ s << "#ifndef SBK_" << headerGuard << "_H" << endl;
+ s << "#define SBK_" << headerGuard << "_H" << endl<< endl;
+
+#ifndef AVOID_PROTECTED_HACK
+ s << "#define protected public" << endl << endl;
+#endif
+
+ s << "#include <shiboken.h>" << endl << endl;
+
+ //Includes
+ s << metaClass->typeEntry()->include() << endl;
+
+ if (shouldGenerateCppWrapper(metaClass)) {
+
+ if (usePySideExtensions() && metaClass->isQObject())
+ s << "namespace PySide { class DynamicQMetaObject; }\n\n";
+
+ // Class
+ s << "class " << wrapperName;
+ s << " : public " << metaClass->qualifiedCppName();
+
+ s << endl << '{' << endl << "public:" << endl;
+
+ if (metaClass->typeEntry()->isValue())
+ writeCopyCtor(s, metaClass);
+
+ bool hasVirtualFunction = false;
+ foreach (AbstractMetaFunction *func, filterFunctions(metaClass)) {
+ if (func->isVirtual())
+ hasVirtualFunction = true;
+ writeFunction(s, func);
+ }
+
+#ifdef AVOID_PROTECTED_HACK
+ if (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;
+
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::Declaration, TypeSystem::NativeCode);
+
+#ifdef AVOID_PROTECTED_HACK
+ if (!metaClass->hasPrivateDestructor()) {
+#endif
+
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ s << "public:\n";
+ s << INDENT << "virtual int qt_metacall(QMetaObject::Call call, int id, void** args);\n";
+ s << "private:\n";
+ s << INDENT << "mutable PySide::DynamicQMetaObject* m_metaObject;\n";
+ }
+
+#ifdef AVOID_PROTECTED_HACK
+ }
+#endif
+
+ s << "};" << endl << endl;
+ }
+
+ s << "#endif // SBK_" << headerGuard << "_H" << endl << endl;
+}
+
+void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* func) const
+{
+ // do not write copy ctors here.
+ if (func->isCopyConstructor())
+ return;
+
+ if (func->isConstructor() && func->isUserAdded())
+ return;
+
+#ifdef AVOID_PROTECTED_HACK
+ if (func->isProtected() && !func->isConstructor() && !func->isOperatorOverload()) {
+ s << INDENT << "inline " << (func->isStatic() ? "static " : "");
+ s << functionSignature(func, "", "_protected", Generator::EnumAsInts|Generator::OriginalTypeDescription) << " { ";
+ s << (func->type() ? "return " : "");
+ if (!func->isAbstract())
+ s << func->ownerClass()->qualifiedCppName() << "::";
+ s << func->originalName() << '(';
+ QStringList args;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ QString argName = arg->name();
+ const TypeEntry* enumTypeEntry = 0;
+ if (arg->type()->isFlags())
+ enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(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
+
+ // 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()))
+ return;
+#endif
+
+ if (func->isConstructor() || func->isAbstract() || func->isVirtual()) {
+ s << INDENT;
+ Options virtualOption = Generator::OriginalTypeDescription;
+
+ if (func->isVirtual() || func->isAbstract())
+ s << "virtual ";
+ else if (!func->hasSignatureModifications())
+ virtualOption = Generator::NoOption;
+
+ s << functionSignature(func, "", "", virtualOption) << ';' << endl;
+
+ // TODO: when modified an abstract method ceases to be virtual but stays abstract
+ //if (func->isModifiedRemoved() && func->isAbstract()) {
+ //}
+ }
+}
+
+void HeaderGenerator::writeTypeConverterDecl(QTextStream& s, const TypeEntry* type)
+{
+ s << "template<>" << endl;
+
+ const AbstractMetaClass* metaClass = classes().findClass(type->name());
+ bool isAbstractOrObjectType = (metaClass && metaClass->isAbstract()) || type->isObject();
+
+ AbstractMetaFunctionList implicitConvs;
+ foreach (AbstractMetaFunction* func, implicitConversions(type)) {
+ if (!func->isUserAdded())
+ implicitConvs << func;
+ }
+ 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) {
+ if (type->isEnum())
+ s << " : EnumConverter";
+ else if (type->isFlags())
+ s << " : QFlagsConverter";
+ else if (isAbstractOrObjectType)
+ s << " : ObjectTypeConverter";
+ else
+ s << " : ValueTypeConverter";
+ s << '<' << typeName << " >";
+ }
+ s << endl << '{' << endl;
+ if (isValueTypeWithImplConversions || hasCustomConversion) {
+ s << INDENT << "static " << type->name() << " toCpp(PyObject* pyobj);" << endl;
+ s << INDENT << "static bool isConvertible(PyObject* pyobj);" << endl;
+ if (hasCustomConversion) {
+ s << INDENT << "static bool checkType(PyObject* pyobj);" << endl;
+ s << INDENT << "static inline PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast<"
+ << type->name() << (isAbstractOrObjectType ? "" : "*") << " >(cppObj)); }" << endl;
+ s << INDENT << "static PyObject* toPython(const " << type->name() << "& cppObj);" << endl;
+ }
+ }
+ s << "};" << endl;
+
+ // write value-type like converter to object-types
+ if (isAbstractOrObjectType) {
+ s << endl << "template<>" << endl;
+ s << "struct Converter<" << type->name() << "& > : ObjectTypeReferenceConverter<" << type->name() << " >" << endl << '{' << endl;
+ s << "};" << endl;
+ }
+}
+
+void HeaderGenerator::writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry, int& idx)
+{
+ if (!typeEntry || !typeEntry->generateCode())
+ return;
+ s.setFieldAlignment(QTextStream::AlignLeft);
+ s << "#define ";
+ s.setFieldWidth(60);
+ s << getTypeIndexVariableName(typeEntry);
+ s.setFieldWidth(0);
+ s << ' ' << (idx++) << endl;
+ if (typeEntry->isEnum()) {
+ const EnumTypeEntry* ete = reinterpret_cast<const EnumTypeEntry*>(typeEntry);
+ if (ete->flags())
+ writeTypeIndexDefineLine(s, ete->flags(), idx);
+ }
+}
+
+void HeaderGenerator::writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass, int& idx)
+{
+ if (!metaClass->typeEntry()->generateCode())
+ return;
+ writeTypeIndexDefineLine(s, metaClass->typeEntry(), idx);
+ foreach (const AbstractMetaEnum* metaEnum, metaClass->enums())
+ writeTypeIndexDefineLine(s, metaEnum->typeEntry(), idx);
+}
+
+void HeaderGenerator::finishGeneration()
+{
+ if (classes().isEmpty())
+ return;
+
+ // Generate the main header for this module.
+ // This header should be included by binding modules
+ // extendind on top of this one.
+ QSet<Include> includes;
+ QString macros;
+ QTextStream macrosStream(&macros);
+ QString convertersDecl;
+ QTextStream convDecl(&convertersDecl);
+ QString sbkTypeFunctions;
+ QTextStream typeFunctions(&sbkTypeFunctions);
+ QString converterImpl;
+ QTextStream convImpl(&converterImpl);
+
+ Indentation indent(INDENT);
+
+ macrosStream << "// Type indices" << endl;
+ int idx = 0;
+ foreach (const AbstractMetaClass* metaClass, classes())
+ writeTypeIndexDefine(macrosStream, metaClass, idx);
+ foreach (const AbstractMetaEnum* metaEnum, globalEnums())
+ writeTypeIndexDefineLine(macrosStream, metaEnum->typeEntry(), idx);
+ macrosStream << "#define ";
+ macrosStream.setFieldWidth(60);
+ macrosStream << "SBK_"+moduleName()+"_IDX_COUNT";
+ macrosStream.setFieldWidth(0);
+ macrosStream << ' ' << idx << endl << endl;
+ macrosStream << "// This variable stores all python types exported by this module" << endl;
+ macrosStream << "extern PyTypeObject** " << cppApiVariableName() << ';' << endl << endl;
+
+ macrosStream << "// Macros for type check" << endl;
+ foreach (const AbstractMetaEnum* cppEnum, globalEnums()) {
+ if (cppEnum->isAnonymous())
+ continue;
+ includes << cppEnum->typeEntry()->include();
+ writeTypeConverterDecl(convDecl, cppEnum->typeEntry());
+ convDecl << endl;
+ writeSbkTypeFunction(typeFunctions, cppEnum);
+ }
+
+ foreach (AbstractMetaClass* metaClass, classes()) {
+ if (!shouldGenerate(metaClass))
+ continue;
+
+ //Includes
+ const TypeEntry* classType = metaClass->typeEntry();
+ includes << classType->include();
+
+ foreach (const AbstractMetaEnum* cppEnum, metaClass->enums()) {
+ if (cppEnum->isAnonymous())
+ continue;
+ EnumTypeEntry* enumType = cppEnum->typeEntry();
+ includes << enumType->include();
+ writeTypeConverterDecl(convDecl, enumType);
+ FlagsTypeEntry* flagsEntry = enumType->flags();
+ if (flagsEntry)
+ writeTypeConverterDecl(convDecl, flagsEntry);
+ convDecl << endl;
+ writeSbkTypeFunction(typeFunctions, cppEnum);
+ }
+
+ if (!metaClass->isNamespace()) {
+ writeSbkTypeFunction(typeFunctions, metaClass);
+ writeSbkCopyCppObjectFunction(convDecl, metaClass);
+ writeTypeConverterDecl(convDecl, classType);
+ writeTypeConverterImpl(convImpl, classType);
+ convDecl << endl;
+ }
+ }
+
+ QString moduleHeaderFileName(outputDirectory()
+ + QDir::separator() + subDirectoryForPackage(packageName())
+ + QDir::separator() + getModuleHeaderFileName());
+
+ QString includeShield("SBK_" + moduleName().toUpper() + "_PYTHON_H");
+
+ FileOut file(moduleHeaderFileName);
+ QTextStream& s = file.stream;
+ // write license comment
+ s << licenseComment() << endl << endl;
+
+ 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
+
+ s << "#include <Python.h>" << endl;
+ s << "#include <conversions.h>" << endl;
+ s << "#include <pyenum.h>" << endl;
+ s << "#include <basewrapper.h>" << endl;
+ s << "#include <bindingmanager.h>" << endl;
+ s << "#include <memory>" << endl << endl;
+ if (usePySideExtensions())
+ s << "#include <qsignal.h>" << endl;
+
+ QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports();
+ if (!requiredTargetImports.isEmpty()) {
+ s << "// Module Includes" << endl;
+ foreach (const QString& requiredModule, requiredTargetImports)
+ s << "#include <" << getModuleHeaderFileName(requiredModule) << ">" << endl;
+ s << endl;
+ }
+
+ s << "// Binded library includes" << endl;
+ foreach (const Include& include, includes)
+ s << include;
+
+ if (!primitiveTypes().isEmpty()) {
+ s << "// Conversion Includes - Primitive Types" << endl;
+ foreach (const PrimitiveTypeEntry* ptype, primitiveTypes())
+ s << ptype->include();
+ s << endl;
+ }
+
+ if (!containerTypes().isEmpty()) {
+ s << "// Conversion Includes - Container Types" << endl;
+ foreach (const ContainerTypeEntry* ctype, containerTypes())
+ s << ctype->include();
+ s << endl;
+ }
+
+ s << macros << endl;
+
+ s << "namespace Shiboken" << endl << '{' << endl << endl;
+
+ s << "// PyType functions, to get the PyObjectType for a type T\n";
+ s << sbkTypeFunctions << endl;
+
+ if (usePySideExtensions()) {
+ foreach (AbstractMetaClass* metaClass, classes()) {
+ if (!metaClass->isQObject() || !metaClass->typeEntry()->generateCode())
+ continue;
+
+ s << "template<>" << endl;
+ s << "inline PyObject* createWrapper<" << metaClass->qualifiedCppName() << " >(const ";
+ s << metaClass->qualifiedCppName() << "* cppobj, bool hasOwnership, bool isExactType)" << endl;
+ s << '{' << endl;
+ s << INDENT << "PyObject* pyObj = Shiboken::SbkBaseWrapper_New(reinterpret_cast<SbkBaseWrapperType*>(SbkType<" << metaClass->qualifiedCppName() << " >()),"
+ << "const_cast<" << metaClass->qualifiedCppName() << "*>(cppobj), hasOwnership, isExactType);" << endl;
+ s << INDENT << "PySide::signalUpdateSource(pyObj);" << endl;
+ s << INDENT << "return pyObj;" << endl;
+ s << '}' << endl;
+
+ }
+ }
+
+ s << "// Generated converters declarations ----------------------------------" << endl << endl;
+ s << convertersDecl;
+ s << "} // namespace Shiboken" << endl << endl;
+
+ s << "// User defined converters --------------------------------------------" << endl;
+ foreach (TypeEntry* typeEntry, TypeDatabase::instance()->entries()) {
+ if (typeEntry->hasConversionRule()) {
+ s << "// Conversion rule for: " << typeEntry->name() << endl;
+ s << typeEntry->conversionRule();
+ }
+ }
+ s << "// Generated converters implemantations -------------------------------" << endl << endl;
+ s << converterImpl << endl;
+
+ s << "#endif // " << includeShield << endl << endl;
+}
+
+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()) {
+ 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) {
+ s << "template<> inline PyTypeObject* SbkType<" << flag->name() << " >() "
+ << "{ return " << cpythonTypeNameExt(flag) << "; }\n";
+ }
+}
+
+void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ s << "template<> inline PyTypeObject* SbkType<" << cppClass->qualifiedCppName() << " >() "
+ << "{ return reinterpret_cast<PyTypeObject*>(" << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n";
+}
+
+void HeaderGenerator::writeSbkCopyCppObjectFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ if (!metaClass->typeEntry()->isValue() || !shouldGenerateCppWrapper(metaClass))
+ return;
+ QString className = metaClass->qualifiedCppName();
+ s << "template <>" << endl;
+ s << "struct SbkTypeInfo<" << className << " >" << endl;
+ s << '{' << endl;
+ s << INDENT << "static const bool isCppWrapper = true;" << endl;
+ s << "};" << endl;
+}
+
+void HeaderGenerator::writeTypeConverterImpl(QTextStream& s, const TypeEntry* type)
+{
+ if (type->hasConversionRule())
+ return;
+
+ QString pyTypeName = cpythonTypeName(type);
+
+ AbstractMetaFunctionList implicitConvs;
+ foreach (AbstractMetaFunction* func, implicitConversions(type)) {
+ if (!func->isUserAdded())
+ implicitConvs << func;
+ }
+
+ bool hasImplicitConversions = !implicitConvs.isEmpty();
+
+ // A specialized Converter<T>::toCpp method is only need for
+ // classes with implicit conversions.
+ if (!hasImplicitConversions)
+ return;
+
+ // Write Converter<T>::isConvertible
+ s << "inline bool Shiboken::Converter<" << type->name() << " >::isConvertible(PyObject* pyobj)" << endl;
+ s << '{' << endl;
+
+ if (type->isValue()) {
+ s << INDENT << "if (ValueTypeConverter<" << type->name() << " >::isConvertible(pyobj))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return true;" << endl;
+ }
+
+
+ s << INDENT << "SbkBaseWrapperType* shiboType = reinterpret_cast<SbkBaseWrapperType*>(SbkType<";
+ s << type->name() << " >());" << endl;
+ s << INDENT << "return ";
+ bool isFirst = true;
+ foreach (const AbstractMetaFunction* ctor, implicitConvs) {
+ Indentation indent(INDENT);
+ if (isFirst)
+ isFirst = false;
+ else
+ s << endl << INDENT << " || ";
+ if (ctor->isConversionOperator())
+ s << cpythonCheckFunction(ctor->ownerClass()->typeEntry());
+ else
+ s << cpythonCheckFunction(ctor->arguments().first()->type());
+ s << "(pyobj)";
+ }
+ s << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << " || (shiboType->ext_isconvertible && shiboType->ext_isconvertible(pyobj));" << endl;
+ }
+ s << '}' << endl << endl;
+
+ // Write Converter<T>::toCpp function
+ s << "inline " << type->name() << " Shiboken::Converter<" << type->name() << " >::toCpp(PyObject* pyobj)" << endl;
+ s << '{' << endl;
+
+ s << INDENT << "if (!Shiboken_TypeCheck(pyobj, " << type->name() << ")) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "SbkBaseWrapperType* shiboType = reinterpret_cast<SbkBaseWrapperType*>(SbkType<";
+ s << type->name() << " >());" << endl;
+ }
+ bool firstImplicitIf = true;
+ foreach (const AbstractMetaFunction* ctor, implicitConvs) {
+ if (ctor->isModifiedRemoved())
+ continue;
+
+ Indentation indent(INDENT);
+ s << INDENT;
+ if (firstImplicitIf)
+ firstImplicitIf = false;
+ else
+ s << "else ";
+
+ QString typeCheck;
+ QString toCppConv;
+ QTextStream tcc(&toCppConv);
+ if (ctor->isConversionOperator()) {
+ const AbstractMetaClass* metaClass = ctor->ownerClass();
+ typeCheck = cpythonCheckFunction(metaClass->typeEntry());
+ writeToCppConversion(tcc, metaClass, "pyobj");
+ } else {
+ const AbstractMetaType* argType = ctor->arguments().first()->type();
+ typeCheck = cpythonCheckFunction(argType);
+ writeToCppConversion(tcc, argType, 0, "pyobj");
+ }
+
+ s << "if (" << typeCheck << "(pyobj))" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << type->name() << '(' << toCppConv << ");" << endl;
+ }
+ }
+
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "else if (shiboType->ext_isconvertible && shiboType->ext_tocpp && shiboType->ext_isconvertible(pyobj)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << type->name() << "* cptr = reinterpret_cast<" << type->name() << "*>(shiboType->ext_tocpp(pyobj));" << endl;
+ s << INDENT << "std::auto_ptr<" << type->name() << " > cptr_auto_ptr(cptr);" << endl;
+ s << INDENT << "return *cptr;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+
+ s << INDENT << '}' << endl;
+
+ s << INDENT << "return *" << cpythonWrapperCPtr(type, "pyobj") << ';' << endl;
+ s << '}' << endl << endl;
+}
+
diff --git a/generator/headergenerator.h b/generator/headergenerator.h
new file mode 100644
index 00000000..9802a104
--- /dev/null
+++ b/generator/headergenerator.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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
+ *
+ */
+
+#ifndef HEADERGENERATOR_H
+#define HEADERGENERATOR_H
+
+#include "shibokengenerator.h"
+
+/**
+ * The HeaderGenerator generate the declarations of C++ bindings classes.
+ */
+class HeaderGenerator : public ShibokenGenerator
+{
+public:
+ QMap<QString, QString> options() const { return QMap<QString, QString>(); }
+protected:
+ QString fileNameForClass(const AbstractMetaClass* metaClass) const;
+ void generateClass(QTextStream& s, const AbstractMetaClass* metaClass);
+ void finishGeneration();
+
+private:
+ void writeCopyCtor(QTextStream &s, const AbstractMetaClass* metaClass) const;
+ void writeProtectedFieldAccessors(QTextStream& s, const AbstractMetaField* field) const;
+ void writeFunction(QTextStream& s, const AbstractMetaFunction* func) const;
+ void writePureVirtualEmptyImpl(QTextStream& , const AbstractMetaFunction* func) const;
+ void writeDefaultImplementation(QTextStream& s, const AbstractMetaFunction* func) const;
+ void writeTypeConverterDecl(QTextStream& s, const TypeEntry* type);
+ void writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass);
+ void writeSbkCopyCppObjectFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry, int& idx);
+ void writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass, int& idx);
+ void writeTypeConverterImpl(QTextStream& s, const TypeEntry* type);
+
+};
+
+#endif // HEADERGENERATOR_H
+
diff --git a/generator/main.cpp b/generator/main.cpp
new file mode 100644
index 00000000..05122506
--- /dev/null
+++ b/generator/main.cpp
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 <QtCore>
+
+int main(int argc, char *argv[])
+{
+ QStringList args;
+ args.append("--generatorSet=shiboken");
+ for (int i = 1; i < argc; i++)
+ args.append(argv[i]);
+ return QProcess::execute("generatorrunner", args);
+}
+
diff --git a/generator/overloaddata.cpp b/generator/overloaddata.cpp
new file mode 100644
index 00000000..a71091ea
--- /dev/null
+++ b/generator/overloaddata.cpp
@@ -0,0 +1,788 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 <QtCore/QFile>
+#include <reporthandler.h>
+#include <graph.h>
+#include "overloaddata.h"
+#include "shibokengenerator.h"
+
+static const TypeEntry* getAliasedTypeEntry(const TypeEntry* typeEntry)
+{
+ if (typeEntry->isPrimitive()) {
+ const PrimitiveTypeEntry* pte = reinterpret_cast<const PrimitiveTypeEntry*>(typeEntry);
+ while (pte->aliasedTypeEntry())
+ pte = pte->aliasedTypeEntry();
+ typeEntry = pte;
+ }
+ return typeEntry;
+}
+
+/**
+ * Topologically sort the overloads by implicit convertion order
+ *
+ * This avoids using an implicit conversion if there's an explicit
+ * overload for the convertible type. So, if there's an implicit convert
+ * like TargetType(ConvertibleType foo) and both are in the overload list,
+ * ConvertibleType is checked before TargetType.
+ *
+ * Side effects: Modifies m_nextOverloadData
+ */
+void OverloadData::sortNextOverloads()
+{
+ QHash<QString, int> map; // type_name -> id
+ QHash<int, OverloadData*> reverseMap; // id -> type_name
+ bool checkPyObject = false;
+ int pyobjectIndex = 0;
+
+ // sort the children overloads
+ foreach(OverloadData *ov, m_nextOverloadData) {
+ ov->sortNextOverloads();
+ }
+
+ if (m_nextOverloadData.size() <= 1)
+ return;
+
+ // Creates the map and reverseMap, to map type names to ids, these ids will be used by the topological
+ // sort algorithm, because is easier and faster to work with graph sorting using integers.
+ int i = 0;
+ foreach(OverloadData* ov, m_nextOverloadData) {
+ const TypeEntry* typeEntry = getAliasedTypeEntry(ov->argType()->typeEntry());
+ map[typeEntry->name()] = i;
+ reverseMap[i] = ov;
+
+ if (!checkPyObject && typeEntry->name().contains("PyObject")) {
+ checkPyObject = true;
+ pyobjectIndex = i;
+ }
+ i++;
+ }
+
+ // Create the graph of type dependencies based on implicit conversions.
+ Graph graph(reverseMap.count());
+ // All C++ primitive types, add any forgotten type AT THE END OF THIS LIST!
+ const char* primitiveTypes[] = {"int",
+ "unsigned int",
+ "long",
+ "unsigned long",
+ "short",
+ "unsigned short",
+ "bool",
+ "unsigned char",
+ "char",
+ "float",
+ "double"
+ };
+ const int numPrimitives = sizeof(primitiveTypes)/sizeof(const char*);
+ bool hasPrimitive[numPrimitives];
+ for (int i = 0; i < numPrimitives; ++i)
+ hasPrimitive[i] = map.contains(primitiveTypes[i]);
+ // just some alias
+ bool haveInt = hasPrimitive[0];
+ bool haveLong = hasPrimitive[2];
+ bool haveShort = hasPrimitive[4];
+
+ foreach(OverloadData* ov, m_nextOverloadData) {
+ const AbstractMetaType* targetType = ov->argType();
+ const TypeEntry* targetTypeEntry = getAliasedTypeEntry(targetType->typeEntry());
+
+ foreach(AbstractMetaFunction* function, m_generator->implicitConversions(ov->argType())) {
+ QString convertibleType;
+ if (function->isConversionOperator())
+ convertibleType = function->ownerClass()->typeEntry()->name();
+ else
+ convertibleType = function->arguments().first()->type()->typeEntry()->name();
+
+ if (!map.contains(convertibleType))
+ continue;
+
+ int targetTypeId = map[targetTypeEntry->name()];
+ int convertibleTypeId = map[convertibleType];
+
+ // If a reverse pair already exists, remove it. Probably due to the
+ // container check (This happened to QVariant and QHash)
+ graph.removeEdge(targetTypeId, convertibleTypeId);
+ graph.addEdge(convertibleTypeId, targetTypeId);
+ }
+
+ if (targetType->hasInstantiations()) {
+ foreach(const AbstractMetaType *instantiation, targetType->instantiations()) {
+ if (map.contains(instantiation->typeEntry()->name())) {
+ int target = map[targetTypeEntry->name()];
+ int convertible = map[instantiation->typeEntry()->name()];
+
+ if (!graph.containsEdge(target, convertible)) // Avoid cyclic dependency.
+ graph.addEdge(convertible, target);
+ }
+ }
+ }
+
+ /* Add dependency on PyObject, so its check is the last one (too generic) */
+ if (checkPyObject && !targetTypeEntry->name().contains("PyObject")) {
+ graph.addEdge(map[targetTypeEntry->name()], pyobjectIndex);
+ }
+
+ if (targetTypeEntry->isEnum()) {
+ for (int i = 0; i < numPrimitives; ++i) {
+ if (hasPrimitive[i])
+ graph.addEdge(map[targetTypeEntry->name()], map[primitiveTypes[i]]);
+ }
+ }
+ }
+
+ // Special case for double(int i) (not tracked by m_generator->implicitConversions
+ if (haveInt) {
+ if (map.contains("float"))
+ graph.addEdge(map["float"], map["int"]);
+ if (map.contains("double"))
+ graph.addEdge(map["double"], map["int"]);
+ if (map.contains("bool"))
+ graph.addEdge(map["bool"], map["int"]);
+ }
+
+ if (haveShort) {
+ if (map.contains("float"))
+ graph.addEdge(map["float"], map["short"]);
+ if (map.contains("double"))
+ graph.addEdge(map["double"], map["short"]);
+ if (map.contains("bool"))
+ graph.addEdge(map["bool"], map["short"]);
+ }
+
+ if (haveLong) {
+ if (map.contains("float"))
+ graph.addEdge(map["float"], map["long"]);
+ if (map.contains("double"))
+ graph.addEdge(map["double"], map["long"]);
+ if (map.contains("bool"))
+ graph.addEdge(map["bool"], map["long"]);
+ }
+
+ // sort the overloads topologicaly based on the deps graph.
+
+ QLinkedList<int> unmappedResult = graph.topologicalSort();
+ if (unmappedResult.isEmpty()) {
+ QString funcName = referenceFunction()->name();
+ if (referenceFunction()->ownerClass())
+ funcName.prepend(referenceFunction()->ownerClass()->name() + '.');
+ ReportHandler::warning(QString("Cyclic dependency found on overloaddata for '%1' method!").arg(qPrintable(funcName)));
+ }
+
+ m_nextOverloadData.clear();
+ foreach(int i, unmappedResult)
+ m_nextOverloadData << reverseMap[i];
+}
+
+/**
+ * Root constructor for OverloadData
+ *
+ * This constructor receives the list of overloads for a given function and iterates generating
+ * the graph of OverloadData instances. Each OverloadData instance references an argument/type
+ * combination.
+ *
+ * Example:
+ * addStuff(double, PyObject *)
+ * addStuff(double, int)
+ *
+ * Given these two overloads, there will be the following graph:
+ *
+ * addStuff - double - PyObject*
+ * \- int
+ *
+ */
+OverloadData::OverloadData(const AbstractMetaFunctionList& overloads, const ShibokenGenerator* generator)
+ : m_minArgs(256), m_maxArgs(0), m_argPos(-1), m_argType(0),
+ m_headOverloadData(this), m_previousOverloadData(0), m_generator(generator)
+{
+ foreach (const AbstractMetaFunction* func, overloads) {
+ m_overloads.append(func);
+ int argSize = func->arguments().size() - numberOfRemovedArguments(func);
+ if (m_minArgs > argSize)
+ m_minArgs = argSize;
+ else if (m_maxArgs < argSize)
+ m_maxArgs = argSize;
+ OverloadData* currentOverloadData = this;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ currentOverloadData = currentOverloadData->addOverloadData(func, arg);
+ }
+ }
+
+ // Sort the overload possibilities so that the overload decisor code goes for the most
+ // important cases first, based on the topological order of the implicit conversions
+ sortNextOverloads();
+
+ // Fix minArgs
+ if (minArgs() > maxArgs())
+ m_headOverloadData->m_minArgs = maxArgs();
+}
+
+OverloadData::OverloadData(OverloadData* headOverloadData, const AbstractMetaFunction* func,
+ const AbstractMetaType* argType, int argPos)
+ : m_minArgs(256), m_maxArgs(0), m_argPos(argPos), m_argType(argType),
+ m_headOverloadData(headOverloadData), m_previousOverloadData(0)
+{
+ if (func)
+ this->addOverload(func);
+}
+
+void OverloadData::addOverload(const AbstractMetaFunction* func)
+{
+ int origNumArgs = func->arguments().size();
+ int removed = numberOfRemovedArguments(func);
+ int numArgs = origNumArgs - removed;
+
+ if (numArgs > m_headOverloadData->m_maxArgs)
+ m_headOverloadData->m_maxArgs = numArgs;
+
+ if (numArgs < m_headOverloadData->m_minArgs)
+ m_headOverloadData->m_minArgs = numArgs;
+
+ for (int i = 0; m_headOverloadData->m_minArgs > 0 && i < origNumArgs; i++) {
+ if (func->argumentRemoved(i + 1))
+ continue;
+ if (!func->arguments()[i]->defaultValueExpression().isEmpty()) {
+ int fixedArgIndex = i - removed;
+ if (fixedArgIndex < m_headOverloadData->m_minArgs)
+ m_headOverloadData->m_minArgs = fixedArgIndex;
+ }
+ }
+
+ m_overloads.append(func);
+}
+
+OverloadData* OverloadData::addOverloadData(const AbstractMetaFunction* func,
+ const AbstractMetaArgument* arg)
+{
+ const AbstractMetaType* argType = arg->type();
+ OverloadData* overloadData = 0;
+ if (!func->isOperatorOverload()) {
+ foreach (OverloadData* tmp, m_nextOverloadData) {
+ // TODO: 'const char *', 'char *' and 'char' will have the same TypeEntry?
+
+ // If an argument have a type replacement, then we should create a new overloaddata
+ // for it, unless the next argument also have a identical type replacement.
+ QString replacedArg = func->typeReplaced(tmp->m_argPos + 1);
+ bool argsReplaced = !replacedArg.isEmpty() || !tmp->m_argTypeReplaced.isEmpty();
+ if ((!argsReplaced && tmp->m_argType->typeEntry() == argType->typeEntry())
+ || (argsReplaced && replacedArg == tmp->argumentTypeReplaced())) {
+ tmp->addOverload(func);
+ overloadData = tmp;
+ }
+ }
+ }
+
+ if (!overloadData) {
+ overloadData = new OverloadData(m_headOverloadData, func, argType, m_argPos + 1);
+ overloadData->m_previousOverloadData = this;
+ overloadData->m_generator = this->m_generator;
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+
+ if (!typeReplaced.isEmpty())
+ overloadData->m_argTypeReplaced = typeReplaced;
+ m_nextOverloadData.append(overloadData);
+ }
+
+ return overloadData;
+}
+
+QStringList OverloadData::returnTypes() const
+{
+ QSet<QString> retTypes;
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (!func->typeReplaced(0).isEmpty())
+ retTypes << func->typeReplaced(0);
+ else if (func->type() && !func->argumentRemoved(0))
+ retTypes << func->type()->cppSignature();
+ else
+ retTypes << "void";
+ }
+ return QStringList(retTypes.toList());
+}
+
+bool OverloadData::hasNonVoidReturnType() const
+{
+ QStringList retTypes = returnTypes();
+ return !retTypes.contains("void") || retTypes.size() > 1;
+}
+
+bool OverloadData::hasVarargs() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ AbstractMetaArgumentList args = func->arguments();
+ if (args.size() > 1 && args.last()->type()->isVarargs())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasAllowThread() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (func->allowThread())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticFunction(const AbstractMetaFunctionList& overloads)
+{
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticFunction() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasInstanceFunction(const AbstractMetaFunctionList& overloads)
+{
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (!func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasInstanceFunction() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (!func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticAndInstanceFunctions(const AbstractMetaFunctionList& overloads)
+{
+ return OverloadData::hasStaticFunction(overloads) && OverloadData::hasInstanceFunction(overloads);
+}
+
+bool OverloadData::hasStaticAndInstanceFunctions() const
+{
+ return OverloadData::hasStaticFunction() && OverloadData::hasInstanceFunction();
+}
+
+const AbstractMetaFunction* OverloadData::referenceFunction() const
+{
+ return m_overloads.first();
+}
+
+const AbstractMetaArgument* OverloadData::argument(const AbstractMetaFunction* func) const
+{
+ if (isHeadOverloadData() || !m_overloads.contains(func))
+ return 0;
+
+ int argPos = 0;
+ int removed = 0;
+ for (int i = 0; argPos <= m_argPos; i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ else
+ argPos++;
+ }
+
+ return func->arguments()[m_argPos + removed];
+}
+
+OverloadDataList OverloadData::overloadDataOnPosition(OverloadData* overloadData, int argPos) const
+{
+ OverloadDataList overloadDataList;
+ if (overloadData->argPos() == argPos) {
+ overloadDataList.append(overloadData);
+ } else if (overloadData->argPos() < argPos) {
+ foreach (OverloadData* pd, overloadData->nextOverloadData())
+ overloadDataList += overloadDataOnPosition(pd, argPos);
+ }
+ return overloadDataList;
+}
+
+OverloadDataList OverloadData::overloadDataOnPosition(int argPos) const
+{
+ OverloadDataList overloadDataList;
+ overloadDataList += overloadDataOnPosition(m_headOverloadData, argPos);
+ return overloadDataList;
+}
+
+bool OverloadData::nextArgumentHasDefaultValue() const
+{
+ foreach (OverloadData* overloadData, m_nextOverloadData) {
+ if (overloadData->getFunctionWithDefaultValue())
+ return true;
+ }
+ return false;
+}
+
+static OverloadData* _findNextArgWithDefault(OverloadData* overloadData)
+{
+ if (overloadData->getFunctionWithDefaultValue())
+ return overloadData;
+
+ OverloadData* result = 0;
+ foreach (OverloadData* odata, overloadData->nextOverloadData()) {
+ OverloadData* tmp = _findNextArgWithDefault(odata);
+ if (!result || (tmp && result->argPos() > tmp->argPos()))
+ result = tmp;
+ }
+ return result;
+}
+
+OverloadData* OverloadData::findNextArgWithDefault()
+{
+ return _findNextArgWithDefault(this);
+}
+
+bool OverloadData::isFinalOccurrence(const AbstractMetaFunction* func) const
+{
+ foreach (const OverloadData* pd, m_nextOverloadData) {
+ if (pd->overloads().contains(func))
+ return false;
+ }
+ return true;
+}
+
+QList<const AbstractMetaFunction*> OverloadData::overloadsWithoutRepetition() const
+{
+ QList<const AbstractMetaFunction*> overloads = m_overloads;
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (func->minimalSignature().endsWith("const"))
+ continue;
+ foreach (const AbstractMetaFunction* f, overloads) {
+ if ((func->minimalSignature() + "const") == f->minimalSignature()) {
+ overloads.removeOne(f);
+ break;
+ }
+ }
+ }
+ return overloads;
+}
+
+const AbstractMetaFunction* OverloadData::getFunctionWithDefaultValue() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ int removedArgs = 0;
+ for (int i = 0; i <= m_argPos + removedArgs; i++) {
+ if (func->argumentRemoved(i + 1))
+ removedArgs++;
+ }
+ if (!func->arguments()[m_argPos + removedArgs]->defaultValueExpression().isEmpty())
+ return func;
+ }
+ return 0;
+}
+
+QList<int> OverloadData::invalidArgumentLengths() const
+{
+ QSet<int> validArgLengths;
+
+ foreach (const AbstractMetaFunction* func, m_headOverloadData->m_overloads) {
+ const AbstractMetaArgumentList args = func->arguments();
+ int offset = 0;
+ for (int i = 0; i < args.size(); ++i) {
+ if (func->argumentRemoved(i+1)) {
+ offset++;
+ } else {
+ if (!args[i]->defaultValueExpression().isEmpty())
+ validArgLengths << i-offset;
+ }
+ }
+ validArgLengths << args.size() - offset;
+ }
+
+ QList<int> invalidArgLengths;
+ for (int i = minArgs() + 1; i < maxArgs(); i++) {
+ if (!validArgLengths.contains(i))
+ invalidArgLengths.append(i);
+ }
+
+ return invalidArgLengths;
+}
+
+int OverloadData::numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos)
+{
+ int removed = 0;
+ if (finalArgPos < 0) {
+ for (int i = 0; i < func->arguments().size(); i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ }
+ } else {
+ for (int i = 0; i < finalArgPos + removed; i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ }
+ }
+ return removed;
+}
+
+QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList& overloads)
+{
+ int minArgs = 10000;
+ int maxArgs = 0;
+ for (int i = 0; i < overloads.size(); i++) {
+ const AbstractMetaFunction* func = overloads[i];
+ int origNumArgs = func->arguments().size();
+ int removed = numberOfRemovedArguments(func);
+ int numArgs = origNumArgs - removed;
+ if (maxArgs < numArgs)
+ maxArgs = numArgs;
+ if (minArgs > numArgs)
+ minArgs = numArgs;
+ for (int j = 0; j < origNumArgs; j++) {
+ if (func->argumentRemoved(j + 1))
+ continue;
+ int fixedArgIndex = j - removed;
+ if (fixedArgIndex < minArgs && !func->arguments()[j]->defaultValueExpression().isEmpty())
+ minArgs = fixedArgIndex;
+ }
+ }
+ return QPair<int, int>(minArgs, maxArgs);
+}
+
+bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads)
+{
+ bool singleArgument = true;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (func->arguments().size() - numberOfRemovedArguments(func) != 1) {
+ singleArgument = false;
+ break;
+ }
+ }
+ return singleArgument;
+}
+
+void OverloadData::dumpGraph(QString filename) const
+{
+ QFile file(filename);
+ if (file.open(QFile::WriteOnly)) {
+ QTextStream s(&file);
+ s << m_headOverloadData->dumpGraph();
+ }
+}
+
+QString OverloadData::dumpGraph() const
+{
+ QString indent(4, ' ');
+ QString result;
+ QTextStream s(&result);
+ if (m_argPos == -1) {
+ const AbstractMetaFunction* rfunc = referenceFunction();
+ s << "digraph OverloadedFunction {" << endl;
+ s << indent << "graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];" << endl;
+
+ // Shows all function signatures
+ s << "legend [fontsize=9 fontname=freemono shape=rect label=\"";
+ foreach (const AbstractMetaFunction* func, overloads()) {
+ s << "f" << functionNumber(func) << " : ";
+ if (func->type())
+ s << func->type()->cppSignature().replace('<', "&lt;").replace('>', "&gt;");
+ else
+ s << "void";
+ s << ' ' << func->minimalSignature().replace('<', "&lt;").replace('>', "&gt;") << "\\l";
+ }
+ s << "\"];" << endl;
+
+ // Function box title
+ s << indent << '"' << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+ s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">";
+ if (rfunc->ownerClass())
+ s << rfunc->ownerClass()->name() << "::";
+ s << rfunc->name().replace('<', "&lt;").replace('>', "&gt;") << "</font>";
+ if (rfunc->isVirtual()) {
+ s << "<br/><font color=\"white\" point-size=\"10\">&lt;&lt;";
+ if (rfunc->isAbstract())
+ s << "pure ";
+ s << "virtual&gt;&gt;</font>";
+ }
+ s << "</td></tr>";
+
+ // Function return type
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">";
+ if (rfunc->type())
+ s << rfunc->type()->cppSignature().replace('<', "&lt;").replace('>', "&gt;");
+ else
+ s << "void";
+ s << "</td></tr>";
+
+ // Shows type changes for all function signatures
+ foreach (const AbstractMetaFunction* func, overloads()) {
+ if (func->typeReplaced(0).isEmpty())
+ continue;
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << func->typeReplaced(0).replace('<', "&lt;").replace('>', "&gt;") << "</td></tr>";
+ }
+
+ // Minimum and maximum number of arguments
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">minArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << minArgs() << "</td></tr>";
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">maxArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << maxArgs() << "</td></tr>";
+
+ if (rfunc->ownerClass()) {
+ if (rfunc->implementingClass() != rfunc->ownerClass())
+ s << "<tr><td align=\"right\">implementor</td><td align=\"left\">" << rfunc->implementingClass()->name() << "</td></tr>";
+ if (rfunc->declaringClass() != rfunc->ownerClass() && rfunc->declaringClass() != rfunc->implementingClass())
+ s << "<tr><td align=\"right\">declarator</td><td align=\"left\">" << rfunc->declaringClass()->name() << "</td></tr>";
+ }
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ foreach (const AbstractMetaFunction* func, overloads())
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ s << "</table>> ];" << endl;
+
+ foreach (const OverloadData* pd, nextOverloadData())
+ s << indent << '"' << rfunc->name() << "\" -> " << pd->dumpGraph();
+
+ s << "}" << endl;
+ } else {
+ QString argId = QString("arg_%1").arg((ulong)this);
+ s << argId << ';' << endl;
+
+ s << indent << '"' << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+
+ // Argument box title
+ s << "<tr><td bgcolor=\"black\" align=\"left\" cellpadding=\"2\" colspan=\"2\">";
+ s << "<font color=\"white\" point-size=\"11\">arg #" << argPos() << "</font></td></tr>";
+
+ // Argument type information
+ QString type = hasArgumentTypeReplace() ? argumentTypeReplaced() : argType()->cppSignature();
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << type.replace("&", "&amp;") << "</td></tr>";
+ if (hasArgumentTypeReplace()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">orig. type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << argType()->cppSignature().replace("&", "&amp;") << "</td></tr>";
+ }
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ foreach (const AbstractMetaFunction* func, overloads())
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ // Show default values (original and modified) for various functions
+ foreach (const AbstractMetaFunction* func, overloads()) {
+ const AbstractMetaArgument* arg = argument(func);
+ if (!arg)
+ continue;
+ if (!arg->defaultValueExpression().isEmpty() ||
+ arg->defaultValueExpression() != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << arg->defaultValueExpression() << "</td></tr>";
+ }
+ if (arg->defaultValueExpression() != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-orig-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << arg->originalDefaultValueExpression() << "</td></tr>";
+ }
+ }
+
+ s << "</table>>];" << endl;
+
+ foreach (const OverloadData* pd, nextOverloadData())
+ s << indent << argId << " -> " << pd->dumpGraph();
+ }
+ return result;
+}
+
+int OverloadData::functionNumber(const AbstractMetaFunction* func) const
+{
+ return m_headOverloadData->m_overloads.indexOf(func);
+}
+
+OverloadData::~OverloadData()
+{
+ while (!m_nextOverloadData.isEmpty())
+ delete m_nextOverloadData.takeLast();
+}
+
+bool OverloadData::hasArgumentTypeReplace() const
+{
+ return !m_argTypeReplaced.isEmpty();
+}
+
+QString OverloadData::argumentTypeReplaced() const
+{
+ return m_argTypeReplaced;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunctionList& overloads)
+{
+ if (OverloadData::getMinMaxArguments(overloads).second == 0)
+ return false;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (hasArgumentWithDefaultValue(func))
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue() const
+{
+ if (maxArgs() == 0)
+ return false;
+ foreach (const AbstractMetaFunction* func, overloads()) {
+ if (hasArgumentWithDefaultValue(func))
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunction* func)
+{
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ if (!arg->defaultValueExpression().isEmpty())
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const AbstractMetaFunction* func)
+{
+ AbstractMetaArgumentList args;
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ if (arg->defaultValueExpression().isEmpty()
+ || func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ args << arg;
+ }
+ return args;
+}
+
diff --git a/generator/overloaddata.h b/generator/overloaddata.h
new file mode 100644
index 00000000..a0bd4640
--- /dev/null
+++ b/generator/overloaddata.h
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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
+ *
+ */
+
+#ifndef OVERLOADDATA_H
+#define OVERLOADDATA_H
+
+#include <abstractmetalang.h>
+#include <QtCore/QList>
+#include <QtCore/QBitArray>
+
+class ShibokenGenerator;
+
+class OverloadData;
+typedef QList<OverloadData*> OverloadDataList;
+
+class OverloadData
+{
+public:
+ OverloadData(const AbstractMetaFunctionList& overloads, const ShibokenGenerator* generator);
+ ~OverloadData();
+
+ int minArgs() const { return m_headOverloadData->m_minArgs; }
+ int maxArgs() const { return m_headOverloadData->m_maxArgs; }
+ int argPos() const { return m_argPos; }
+
+ const AbstractMetaType* argType() const { return m_argType; }
+
+ /// Returns a string list containing all the possible return types (including void) for the current OverloadData.
+ QStringList returnTypes() const;
+
+ /// Returns true if any of the overloads for the current OverloadData has a return type different from void.
+ bool hasNonVoidReturnType() const;
+
+ /// Returns true if any of the overloads for the current OverloadData has a varargs argument.
+ bool hasVarargs() const;
+
+ /// Returns true if any of the overloads for the current OverloadData allows threads when called.
+ bool hasAllowThread() const;
+
+ /// Returns true if any of the overloads for the current OverloadData is static.
+ bool hasStaticFunction() const;
+
+ /// Returns true if any of the overloads passed as argument is static.
+ static bool hasStaticFunction(const AbstractMetaFunctionList& overloads);
+
+ /// Returns true if any of the overloads for the current OverloadData is not static.
+ bool hasInstanceFunction() const;
+
+ /// Returns true if any of the overloads passed as argument is not static.
+ static bool hasInstanceFunction(const AbstractMetaFunctionList& overloads);
+
+ /// Returns true if among the overloads for the current OverloadData there are static and non-static methods altogether.
+ bool hasStaticAndInstanceFunctions() const;
+
+ /// Returns true if among the overloads passed as argument there are static and non-static methods altogether.
+ static bool hasStaticAndInstanceFunctions(const AbstractMetaFunctionList& overloads);
+
+ const AbstractMetaFunction* referenceFunction() const;
+ const AbstractMetaArgument* argument(const AbstractMetaFunction* func) const;
+ OverloadDataList overloadDataOnPosition(int argPos) const;
+
+ bool isHeadOverloadData() const { return this == m_headOverloadData; }
+
+ /// Returns the root OverloadData object that represents all the overloads.
+ OverloadData* headOverloadData() const { return m_headOverloadData; }
+
+ /// Returns the function that has a default value at the current OverloadData argument position, otherwise returns null.
+ const AbstractMetaFunction* getFunctionWithDefaultValue() const;
+
+ bool nextArgumentHasDefaultValue() const;
+ /// Returns the nearest occurrence, including this instance, of an argument with a default value.
+ OverloadData* findNextArgWithDefault();
+ bool isFinalOccurrence(const AbstractMetaFunction* func) const;
+
+ /// Returns the list of overloads removing repeated constant functions (ex.: "foo()" and "foo()const", the second is removed).
+ QList<const AbstractMetaFunction*> overloadsWithoutRepetition() const;
+ const QList<const AbstractMetaFunction*>& overloads() const { return m_overloads; }
+ OverloadDataList nextOverloadData() const { return m_nextOverloadData; }
+ OverloadData* previousOverloadData() const { return m_previousOverloadData; }
+
+ QList<int> invalidArgumentLengths() const;
+
+ static int numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos = -1);
+ static QPair<int, int> getMinMaxArguments(const AbstractMetaFunctionList& overloads);
+ /// Returns true if all overloads have no more than one argument.
+ static bool isSingleArgument(const AbstractMetaFunctionList& overloads);
+
+ void dumpGraph(QString filename) const;
+ QString dumpGraph() const;
+
+ bool hasArgumentTypeReplace() const;
+ QString argumentTypeReplaced() const;
+
+ bool hasArgumentWithDefaultValue() const;
+ static bool hasArgumentWithDefaultValue(const AbstractMetaFunctionList& overloads);
+ static bool hasArgumentWithDefaultValue(const AbstractMetaFunction* func);
+
+ /// Returns a list of function arguments which have default values and were not removed.
+ static AbstractMetaArgumentList getArgumentsWithDefaultValues(const AbstractMetaFunction* func);
+
+private:
+ OverloadData(OverloadData* headOverloadData, const AbstractMetaFunction* func,
+ const AbstractMetaType* argType, int argPos);
+
+ void addOverload(const AbstractMetaFunction* func);
+ OverloadData* addOverloadData(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
+
+ void sortNextOverloads();
+
+ int functionNumber(const AbstractMetaFunction* func) const;
+ OverloadDataList overloadDataOnPosition(OverloadData* overloadData, int argPos) const;
+
+ int m_minArgs;
+ int m_maxArgs;
+ int m_argPos;
+ const AbstractMetaType* m_argType;
+ QString m_argTypeReplaced;
+ QList<const AbstractMetaFunction*> m_overloads;
+
+ OverloadData* m_headOverloadData;
+ OverloadDataList m_nextOverloadData;
+ OverloadData* m_previousOverloadData;
+ const ShibokenGenerator* m_generator;
+};
+
+
+#endif // OVERLOADDATA_H
diff --git a/generator/shiboken.cpp b/generator/shiboken.cpp
new file mode 100644
index 00000000..005df90e
--- /dev/null
+++ b/generator/shiboken.cpp
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 "cppgenerator.h"
+#include "headergenerator.h"
+
+EXPORT_GENERATOR_PLUGIN(new CppGenerator << new HeaderGenerator)
diff --git a/generator/shibokengenerator.cpp b/generator/shibokengenerator.cpp
new file mode 100644
index 00000000..e7d0b7de
--- /dev/null
+++ b/generator/shibokengenerator.cpp
@@ -0,0 +1,1651 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 "shibokengenerator.h"
+#include "overloaddata.h"
+#include <reporthandler.h>
+#include <typedatabase.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <limits>
+
+#define NULL_VALUE "NULL"
+#define PARENT_CTOR_HEURISTIC "enable-parent-ctor-heuristic"
+#define RETURN_VALUE_HEURISTIC "enable-return-value-heuristic"
+#define ENABLE_PYSIDE_EXTENSIONS "enable-pyside-extensions"
+#define DISABLE_VERBOSE_ERROR_MESSAGES "disable-verbose-error-messages"
+
+//static void dumpFunction(AbstractMetaFunctionList lst);
+static QString baseConversionString(QString typeName);
+
+QHash<QString, QString> ShibokenGenerator::m_pythonPrimitiveTypeName = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_pythonOperators = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_formatUnits = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_tpFuncs = QHash<QString, QString>();
+
+
+static QString resolveScopePrefix(const AbstractMetaClass* scope, const QString& value)
+{
+ if (!scope)
+ return QString();
+
+ QString name;
+ QStringList parts = scope->qualifiedCppName().split("::", QString::SkipEmptyParts);
+ for(int i = (parts.size() - 1) ; i >= 0; i--) {
+ if (!value.startsWith(parts[i] + "::"))
+ name = parts[i] + "::" + name;
+ else
+ name = "";
+ }
+
+ return name;
+}
+ShibokenGenerator::ShibokenGenerator() : Generator()
+{
+ if (m_pythonPrimitiveTypeName.isEmpty())
+ ShibokenGenerator::initPrimitiveTypesCorrespondences();
+
+ if (m_tpFuncs.isEmpty())
+ ShibokenGenerator::clearTpFuncs();
+}
+
+void ShibokenGenerator::clearTpFuncs()
+{
+ m_tpFuncs["__str__"] = QString("0");
+ m_tpFuncs["__repr__"] = QString("0");
+}
+
+void ShibokenGenerator::initPrimitiveTypesCorrespondences()
+{
+ // Python primitive types names
+ m_pythonPrimitiveTypeName.clear();
+
+ // PyBool
+ m_pythonPrimitiveTypeName["bool"] = "PyBool";
+
+ // PyInt
+ m_pythonPrimitiveTypeName["char"] = "SbkChar";
+ m_pythonPrimitiveTypeName["signed char"] = "SbkChar";
+ m_pythonPrimitiveTypeName["unsigned char"] = "SbkChar";
+ m_pythonPrimitiveTypeName["int"] = "PyInt";
+ m_pythonPrimitiveTypeName["signed int"] = "PyInt";
+ m_pythonPrimitiveTypeName["uint"] = "PyInt";
+ m_pythonPrimitiveTypeName["unsigned int"] = "PyInt";
+ m_pythonPrimitiveTypeName["short"] = "PyInt";
+ m_pythonPrimitiveTypeName["ushort"] = "PyInt";
+ m_pythonPrimitiveTypeName["signed short"] = "PyInt";
+ m_pythonPrimitiveTypeName["unsigned short"] = "PyInt";
+ m_pythonPrimitiveTypeName["long"] = "PyInt";
+
+ // PyFloat
+ m_pythonPrimitiveTypeName["double"] = "PyFloat";
+ m_pythonPrimitiveTypeName["float"] = "PyFloat";
+
+ // PyLong
+ m_pythonPrimitiveTypeName["unsigned long"] = "PyLong";
+ m_pythonPrimitiveTypeName["signed long"] = "PyLong";
+ m_pythonPrimitiveTypeName["ulong"] = "PyLong";
+ m_pythonPrimitiveTypeName["long long"] = "PyLong";
+ m_pythonPrimitiveTypeName["__int64"] = "PyLong";
+ m_pythonPrimitiveTypeName["unsigned long long"] = "PyLong";
+ m_pythonPrimitiveTypeName["unsigned __int64"] = "PyLong";
+
+ // Python operators
+ m_pythonOperators.clear();
+
+ // Arithmetic operators
+ m_pythonOperators["operator+"] = "add";
+ m_pythonOperators["operator-"] = "sub";
+ m_pythonOperators["operator*"] = "mul";
+ m_pythonOperators["operator/"] = "div";
+ m_pythonOperators["operator%"] = "mod";
+
+ // Inplace arithmetic operators
+ m_pythonOperators["operator+="] = "iadd";
+ m_pythonOperators["operator-="] = "isub";
+ m_pythonOperators["operator*="] = "imul";
+ m_pythonOperators["operator/="] = "idiv";
+ m_pythonOperators["operator%="] = "imod";
+
+ // Bitwise operators
+ m_pythonOperators["operator&"] = "and";
+ m_pythonOperators["operator^"] = "xor";
+ m_pythonOperators["operator|"] = "or";
+ m_pythonOperators["operator<<"] = "lshift";
+ m_pythonOperators["operator>>"] = "rshift";
+ m_pythonOperators["operator~"] = "invert";
+
+ // Inplace bitwise operators
+ m_pythonOperators["operator&="] = "iand";
+ m_pythonOperators["operator^="] = "ixor";
+ m_pythonOperators["operator|="] = "ior";
+ m_pythonOperators["operator<<="] = "ilshift";
+ m_pythonOperators["operator>>="] = "irshift";
+
+ // Comparison operators
+ m_pythonOperators["operator=="] = "eq";
+ m_pythonOperators["operator!="] = "ne";
+ m_pythonOperators["operator<"] = "lt";
+ m_pythonOperators["operator>"] = "gt";
+ m_pythonOperators["operator<="] = "le";
+ m_pythonOperators["operator>="] = "ge";
+
+ // Initialize format units for C++->Python->C++ conversion
+ m_formatUnits.clear();
+ m_formatUnits.insert("char", "b");
+ m_formatUnits.insert("unsigned char", "B");
+ m_formatUnits.insert("int", "i");
+ m_formatUnits.insert("unsigned int", "I");
+ m_formatUnits.insert("short", "h");
+ m_formatUnits.insert("unsigned short", "H");
+ m_formatUnits.insert("long", "l");
+ m_formatUnits.insert("unsigned long", "k");
+ m_formatUnits.insert("long long", "L");
+ m_formatUnits.insert("__int64", "L");
+ m_formatUnits.insert("unsigned long long", "K");
+ m_formatUnits.insert("unsigned __int64", "K");
+ m_formatUnits.insert("double", "d");
+ m_formatUnits.insert("float", "f");
+}
+
+QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType* cType,
+ const AbstractMetaClass* context,
+ Options options) const
+{
+ QString result;
+
+ 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);
+ }
+
+ return result;
+}
+
+bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass* metaClass)
+{
+ 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++;
+ }
+ result = result || (protectedFunctions > protectedOperators);
+ }
+#else
+ result = result && !metaClass->hasPrivateDestructor();
+#endif
+ return result && !metaClass->isNamespace();
+}
+
+QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass)
+{
+ if (shouldGenerateCppWrapper(metaClass)) {
+ QString result = metaClass->name();
+ if (metaClass->enclosingClass()) // is a inner class
+ result.replace("::", "_");
+
+ result +="Wrapper";
+ return result;
+ } else {
+ return metaClass->qualifiedCppName();
+ }
+}
+
+QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func)
+{
+ QString funcName;
+ if (func->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(func);
+ else
+ funcName = func->name();
+ if (func->ownerClass()) {
+ QString fullName = func->ownerClass()->fullName();
+ if (func->isConstructor())
+ funcName = fullName;
+ else
+ funcName.prepend(fullName + '.');
+ }
+ return funcName;
+}
+
+QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum)
+{
+ return metaEnum->fullName().replace(".", "_") + "_Surrogate";
+}
+
+QString ShibokenGenerator::protectedFieldGetterName(const AbstractMetaField* field)
+{
+ return QString("protected_%1_getter").arg(field->name());
+}
+
+QString ShibokenGenerator::protectedFieldSetterName(const AbstractMetaField* field)
+{
+ return QString("protected_%1_setter").arg(field->name());
+}
+
+QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunction* func)
+{
+ QString result;
+
+ if (func->ownerClass()) {
+ result = cpythonBaseName(func->ownerClass()->typeEntry());
+ if (func->isConstructor() || func->isCopyConstructor()) {
+ result += "_Init";
+ } else {
+ result += "Func_";
+ if (func->isOperatorOverload())
+ result += ShibokenGenerator::pythonOperatorFunctionName(func);
+ else
+ result += func->name();
+ }
+ } else {
+ result = "Sbk" + moduleName() + "Module_" + func->name();
+ }
+
+ return result;
+}
+
+QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunction* func)
+{
+ if (!func->ownerClass())
+ return QString();
+ return QString("%1Method_%2").arg(cpythonBaseName(func->ownerClass()->typeEntry())).arg(func->name());
+}
+
+QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClass* metaClass)
+{
+ return QString("%1_getsetlist").arg(cpythonBaseName(metaClass));
+}
+
+QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClass* metaClass)
+{
+ return QString("%1_setattro").arg(cpythonBaseName(metaClass));
+}
+
+
+QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass* metaClass)
+{
+ return QString("%1_getattro").arg(cpythonBaseName(metaClass));
+}
+
+QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField* metaField)
+{
+ return QString("%1_get_%2").arg(cpythonBaseName(metaField->enclosingClass())).arg(metaField->name());
+}
+
+QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField* metaField)
+{
+ return QString("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass())).arg(metaField->name());
+}
+
+static QString cpythonEnumFlagsName(QString moduleName, QString qualifiedCppName)
+{
+ QString result = QString("Sbk%1_%2").arg(moduleName).arg(qualifiedCppName);
+ result.replace("::", "_");
+ return result;
+}
+
+static QString searchForEnumScope(const AbstractMetaClass* metaClass, const QString& value)
+{
+ QString enumValueName = value.trimmed();
+
+ if (!metaClass)
+ return QString();
+
+ foreach (const AbstractMetaEnum* metaEnum, metaClass->enums()) {
+ foreach (const AbstractMetaEnumValue* enumValue, metaEnum->values()) {
+ if (enumValueName == enumValue->name())
+ return metaClass->qualifiedCppName();
+ }
+ }
+
+ return searchForEnumScope(metaClass->enclosingClass(), enumValueName);
+}
+
+/*
+ * This function uses some heuristics to find out the scope for a given
+ * argument default value. New situations may arise in the future and
+ * this method should be updated, do it with care.
+ */
+QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg)
+{
+ if (arg->defaultValueExpression().isEmpty())
+ return QString();
+
+ static QRegExp enumValueRegEx("^([A-Za-z_]\\w*)?$");
+ QString value = arg->defaultValueExpression();
+ QString prefix;
+ QString suffix;
+
+ if (arg->type()->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(arg->type());
+ prefix = resolveScopePrefix(metaEnum->enclosingClass(), value);
+ } else if (arg->type()->isFlags()) {
+ static QRegExp numberRegEx("^\\d+$"); // Numbers to flags
+ if (numberRegEx.exactMatch(value)) {
+ QString typeName = translateTypeForWrapperMethod(arg->type(), func->implementingClass());
+ if (arg->type()->isConstant())
+ typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
+ if (arg->type()->isReference())
+ typeName.chop(1);
+ prefix = typeName + '(';
+ suffix = ')';
+ }
+
+ static QRegExp enumCombinationRegEx("^([A-Za-z_][\\w:]*)\\(([^,\\(\\)]*)\\)$"); // FlagName(EnumItem|EnumItem|...)
+ if (prefix.isEmpty() && enumCombinationRegEx.indexIn(value) != -1) {
+ QString flagName = enumCombinationRegEx.cap(1);
+ QStringList enumItems = enumCombinationRegEx.cap(2).split("|");
+ QString scope = searchForEnumScope(func->implementingClass(), enumItems.first());
+ if (!scope.isEmpty())
+ scope.append("::");
+
+ QStringList fixedEnumItems;
+ foreach (const QString& enumItem, enumItems)
+ fixedEnumItems << QString(scope + enumItem);
+
+ if (!fixedEnumItems.isEmpty()) {
+ prefix = flagName + '(';
+ value = fixedEnumItems.join("|");
+ suffix = ')';
+ }
+ }
+ } else if (arg->type()->typeEntry()->isValue()) {
+ const AbstractMetaClass* metaClass = classes().findClass(arg->type()->typeEntry());
+ if (enumValueRegEx.exactMatch(value))
+ prefix = resolveScopePrefix(metaClass, value);
+ } else if (arg->type()->isPrimitive() && arg->type()->name() == "int") {
+ if (enumValueRegEx.exactMatch(value) && func->implementingClass())
+ prefix = resolveScopePrefix(func->implementingClass(), value);
+ } else if(arg->type()->isPrimitive()) {
+ static QRegExp unknowArgumentRegEx("^(?:[A-Za-z_][\\w:]*\\()?([A-Za-z_]\\w*)(?:\\))?$"); // [PrimitiveType(] DESIREDNAME [)]
+ if (unknowArgumentRegEx.indexIn(value) != -1 && func->implementingClass()) {
+ foreach (const AbstractMetaField* field, func->implementingClass()->fields()) {
+ if (unknowArgumentRegEx.cap(1).trimmed() == field->name()) {
+ QString fieldName = field->name();
+ if (field->isStatic()) {
+ prefix = resolveScopePrefix(func->implementingClass(), value);
+ fieldName.prepend(prefix);
+ prefix= "";
+ } else {
+ fieldName.prepend(CPP_SELF_VAR "->");
+ }
+ value.replace(unknowArgumentRegEx.cap(1), fieldName);
+ break;
+ }
+ }
+ }
+ }
+
+ if (!prefix.isEmpty())
+ value.prepend(prefix);
+ if (!suffix.isEmpty())
+ value.append(suffix);
+
+ return value;
+}
+
+QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntry* enumEntry)
+{
+ return cpythonEnumFlagsName(enumEntry->targetLangPackage().replace(".", "_"), enumEntry->qualifiedCppName());
+}
+
+QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntry* flagsEntry)
+{
+ return cpythonEnumFlagsName(flagsEntry->targetLangPackage().replace(".", "_"), flagsEntry->originalName());
+}
+
+QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass->typeEntry())+"SpecialCastFunction";
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName)
+{
+ return cpythonWrapperCPtr(metaClass->typeEntry(), argName);
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType* metaType, QString argName)
+{
+ return cpythonWrapperCPtr(metaType->typeEntry(), argName);
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName)
+{
+ if (type->isValue() || type->isObject())
+ return baseConversionString(type->qualifiedCppName() + '*') + "toCpp(" + argName + ')';
+ return QString();
+}
+
+QString ShibokenGenerator::getFunctionReturnType(const AbstractMetaFunction* func, Options options) const
+{
+ if (func->ownerClass() && (func->isConstructor() || func->isCopyConstructor()))
+ return func->ownerClass()->qualifiedCppName() + '*';
+
+ return translateTypeForWrapperMethod(func->type(), func->implementingClass());
+
+ //TODO: check these lines
+ //QString modifiedReturnType = QString(func->typeReplaced(0));
+ //return modifiedReturnType.isNull() ?
+ //translateType(func->type(), func->implementingClass()) : modifiedReturnType;
+}
+
+static QString baseConversionString(QString typeName)
+{
+ return QString("Shiboken::Converter<%1 >::").arg(typeName);
+}
+
+void ShibokenGenerator::writeBaseConversion(QTextStream& s, const TypeEntry* type)
+{
+ 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);
+}
+
+void ShibokenGenerator::writeBaseConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, Options options)
+{
+ QString typeName;
+ if (type->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type->typeEntry();
+ if (ptype->basicAliasedTypeEntry())
+ ptype = ptype->basicAliasedTypeEntry();
+ typeName = ptype->name();
+ } else {
+ if (type->isObject() || (type->isValue() && !type->isReference()))
+ options |= Generator::ExcludeConst;
+ if (type->isContainer() )
+ options |= Generator::ExcludeReference | Generator::ExcludeConst;
+ typeName = translateTypeForWrapperMethod(type, context, options);
+ }
+
+ s << baseConversionString(typeName);
+}
+
+void ShibokenGenerator::writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, const QString& argumentName)
+{
+ if (!type)
+ return;
+
+ writeBaseConversion(s, type, context);
+ s << "toPython";
+
+ if (!argumentName.isEmpty())
+ s << '(' << argumentName << ')';
+}
+
+void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass,
+ const QString& argumentName)
+{
+ writeBaseConversion(s, metaClass->typeEntry());
+ s << "toCpp(" << argumentName << ')';
+}
+
+void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, const QString& argumentName,
+ Options options)
+{
+ writeBaseConversion(s, type, context, options);
+ s << "toCpp(" << argumentName << ')';
+}
+
+QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction* func, bool incRef) const
+{
+ QString result;
+ const char objType = (incRef ? 'O' : 'N');
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ if (!func->typeReplaced(arg->argumentIndex() + 1).isEmpty()) {
+ result += objType;
+ } else if (arg->type()->isQObject()
+ || arg->type()->isObject()
+ || arg->type()->isValue()
+ || arg->type()->isValuePointer()
+ || arg->type()->isNativePointer()
+ || arg->type()->isEnum()
+ || arg->type()->isFlags()
+ || arg->type()->isContainer()
+ || arg->type()->isReference()) {
+ result += objType;
+ } else if (arg->type()->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) arg->type()->typeEntry();
+ if (ptype->basicAliasedTypeEntry())
+ ptype = ptype->basicAliasedTypeEntry();
+ if (m_formatUnits.contains(ptype->name()))
+ result += m_formatUnits[ptype->name()];
+ else
+ result += objType;
+ } else if (isCString(arg->type())) {
+ result += 'z';
+ } else {
+ QString report;
+ QTextStream(&report) << "Method: " << func->ownerClass()->qualifiedCppName()
+ << "::" << func->signature() << " => Arg:"
+ << arg->name() << "index: " << arg->argumentIndex()
+ << " - cannot be handled properly. Use an inject-code to fix it!";
+ ReportHandler::warning(report);
+ result += '?';
+ }
+ }
+ return result;
+}
+
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType* type)
+{
+ if (isCString(type))
+ return QString("PyString");
+ return cpythonBaseName(type->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type)
+{
+ QString baseName;
+ if ((type->isObject() || type->isValue() || type->isNamespace())) { // && !type->isReference()) {
+ baseName = QString("Sbk") + type->name();
+ } else if (type->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type;
+ while (ptype->basicAliasedTypeEntry())
+ ptype = ptype->basicAliasedTypeEntry();
+ if (ptype->targetLangApiName() == ptype->name())
+ baseName = m_pythonPrimitiveTypeName[ptype->name()];
+ else
+ baseName = ptype->targetLangApiName();
+ } else if (type->isEnum()) {
+ baseName = cpythonEnumName((const EnumTypeEntry*) type);
+ } else if (type->isFlags()) {
+ baseName = cpythonFlagsName((const FlagsTypeEntry*) type);
+ } else if (type->isContainer()) {
+ const ContainerTypeEntry* ctype = (const ContainerTypeEntry*) type;
+ switch (ctype->type()) {
+ case ContainerTypeEntry::ListContainer:
+ case ContainerTypeEntry::StringListContainer:
+ case ContainerTypeEntry::LinkedListContainer:
+ case ContainerTypeEntry::VectorContainer:
+ case ContainerTypeEntry::StackContainer:
+ case ContainerTypeEntry::QueueContainer:
+ //baseName = "PyList";
+ //break;
+ case ContainerTypeEntry::PairContainer:
+ //baseName = "PyTuple";
+ baseName = "PySequence";
+ break;
+ case ContainerTypeEntry::SetContainer:
+ baseName = "PySet";
+ break;
+ case ContainerTypeEntry::MapContainer:
+ case ContainerTypeEntry::MultiMapContainer:
+ case ContainerTypeEntry::HashContainer:
+ case ContainerTypeEntry::MultiHashContainer:
+ baseName = "PyDict";
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ } else {
+ baseName = "PyObject";
+ }
+ return baseName.replace("::", "_");
+}
+
+QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass)
+{
+ return cpythonTypeName(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonTypeName(const TypeEntry* type)
+{
+ return cpythonBaseName(type) + "_Type";
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type)
+{
+ return cppApiVariableName(type->targetLangPackage()) + '[' + getTypeIndexVariableName(type) + ']';
+}
+
+QString ShibokenGenerator::cpythonOperatorFunctionName(const AbstractMetaFunction* func)
+{
+ if (!func->isOperatorOverload())
+ return QString();
+ return QString("Sbk") + func->ownerClass()->name()
+ + '_' + pythonOperatorFunctionName(func->originalName());
+}
+
+QString ShibokenGenerator::pythonPrimitiveTypeName(const QString& cppTypeName)
+{
+ return ShibokenGenerator::m_pythonPrimitiveTypeName.value(cppTypeName, QString());
+}
+
+QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry* type)
+{
+ while (type->basicAliasedTypeEntry())
+ type = type->basicAliasedTypeEntry();
+ return pythonPrimitiveTypeName(type->name());
+}
+
+QString ShibokenGenerator::pythonOperatorFunctionName(QString cppOpFuncName)
+{
+ QString value = m_pythonOperators.value(cppOpFuncName);
+ if (value.isEmpty()) {
+ ReportHandler::warning("Unknown operator: "+cppOpFuncName);
+ value = "UNKNOWN_OPERATOR";
+ }
+ value.prepend("__").append("__");
+ return value;
+}
+
+QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction* func)
+{
+ QString op = pythonOperatorFunctionName(func->originalName());
+ if (func->arguments().isEmpty()) {
+ if (op == "__sub__")
+ op = QString("__neg__");
+ else if (op == "__add__")
+ op = QString("__pos__");
+ } else if (func->isStatic() && func->arguments().size() == 2) {
+ // If a operator overload function has 2 arguments and
+ // is static we assume that it is a reverse operator.
+ op = op.insert(2, 'r');
+ }
+ return op;
+}
+
+QString ShibokenGenerator::pythonRichCompareOperatorId(QString cppOpFuncName)
+{
+ return QString("Py_%1").arg(m_pythonOperators.value(cppOpFuncName).toUpper());
+}
+
+QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunction* func)
+{
+ return pythonRichCompareOperatorId(func->originalName());
+}
+
+bool ShibokenGenerator::isNumber(QString cpythonApiName)
+{
+ return cpythonApiName == "PyInt"
+ || cpythonApiName == "PyFloat"
+ || cpythonApiName == "PyLong"
+ || cpythonApiName == "PyBool";
+}
+
+bool ShibokenGenerator::isNumber(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ return isNumber(pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type));
+}
+
+bool ShibokenGenerator::isNumber(const AbstractMetaType* type)
+{
+ return isNumber(type->typeEntry());
+}
+
+bool ShibokenGenerator::isPyInt(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ return pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type) == "PyInt";
+}
+
+bool ShibokenGenerator::isPyInt(const AbstractMetaType* type)
+{
+ return isPyInt(type->typeEntry());
+}
+
+bool ShibokenGenerator::isCString(const AbstractMetaType* type)
+{
+ return type->isNativePointer() && type->name() == "char";
+}
+
+bool ShibokenGenerator::isPairContainer(const AbstractMetaType* type)
+{
+ return type->isContainer()
+ && ((ContainerTypeEntry*)type->typeEntry())->type() == ContainerTypeEntry::PairContainer;
+}
+
+bool ShibokenGenerator::shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg)
+{
+ return shouldDereferenceAbstractMetaTypePointer(arg->type());
+}
+
+bool ShibokenGenerator::shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType* metaType)
+{
+ const TypeEntry* type = metaType->typeEntry();
+ bool isPointer = metaType->indirections() > 0;
+ bool isCppClass = type->isValue() || type->isObject();
+ return isCppClass && !isPointer && (metaType->isValue() || metaType->isReference());
+}
+
+bool ShibokenGenerator::visibilityModifiedToPrivate(const AbstractMetaFunction* func)
+{
+ foreach (FunctionModification mod, func->modifications()) {
+ if (mod.modifiers & Modification::Private)
+ return true;
+ }
+ return false;
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType, bool genericNumberType)
+{
+ QString baseName = cpythonBaseName(metaType);
+ if (metaType->typeEntry()->isCustom()) {
+ return guessCPythonCheckFunction(metaType->typeEntry()->name());
+ } else if (isNumber(baseName)) {
+ return genericNumberType ? "SbkNumber_Check" : baseName+"_Check";
+ } else {
+ QString str;
+ QTextStream s(&str);
+ writeBaseConversion(s, metaType, 0);
+ s.flush();
+ return str + "checkType";
+ }
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool genericNumberType)
+{
+ QString baseName = cpythonBaseName(type);
+ if (type->isCustom()) {
+ return guessCPythonCheckFunction(type->name());
+ } else if (isNumber(baseName)) {
+ return genericNumberType ? "SbkNumber_Check" : baseName+"_Check";
+ } else {
+ QString str;
+ QTextStream s(&str);
+ writeBaseConversion(s, type);
+ s.flush();
+ return str + "checkType";
+ }
+}
+
+QString ShibokenGenerator::guessCPythonCheckFunction(const QString& type)
+{
+ QString retval;
+ AbstractMetaType* metaType = buildAbstractMetaTypeFromString(type);
+ if (metaType && (metaType->name() != type)) {
+ retval = cpythonCheckFunction(metaType);
+ delete metaType;
+ metaType = 0;
+ } else if (type == "PyTypeObject") {
+ retval = "PyType_Check";
+ } else {
+ retval = QString("%1_Check").arg(type);
+ }
+ if(metaType)
+ delete metaType;
+ return retval;
+}
+
+QString ShibokenGenerator::guessCPythonIsConvertible(const QString& type)
+{
+ QString retval;
+ AbstractMetaType* metaType = buildAbstractMetaTypeFromString(type);
+ if (metaType) {
+ retval = cpythonIsConvertibleFunction(metaType);
+ delete metaType;
+ } else if (type == "PyTypeObject") {
+ retval = "PyType_Check";
+ } else {
+ retval = QString("%1_Check").arg(type);
+ }
+ return retval;
+}
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type, bool genericNumberType, bool checkExact)
+{
+ if (checkExact)
+ return cpythonCheckFunction(type, genericNumberType);
+ if (type->isCustom())
+ return guessCPythonIsConvertible(type->name());
+ QString baseName;
+ QTextStream s(&baseName);
+ writeBaseConversion(s, type);
+ s << "isConvertible";
+ s.flush();
+ return baseName;
+}
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType* metaType, bool genericNumberType)
+{
+
+ QString baseName = cpythonBaseName(metaType);
+ if (metaType->typeEntry()->isCustom()) {
+ return guessCPythonCheckFunction(metaType->typeEntry()->name());
+ } else if (isNumber(baseName)) {
+ return genericNumberType ? "SbkNumber_Check" : baseName+"_Check";
+ } else {
+ QString str;
+ QTextStream s(&str);
+ writeBaseConversion(s, metaType, 0);
+ s.flush();
+ return str + "isConvertible";
+ }
+ return baseName;
+}
+
+QString ShibokenGenerator::argumentString(const AbstractMetaFunction *func,
+ const AbstractMetaArgument *argument,
+ Options options) const
+{
+ QString modified_type;
+ if (!(options & OriginalTypeDescription))
+ modified_type = func->typeReplaced(argument->argumentIndex() + 1);
+ QString arg;
+
+ if (modified_type.isEmpty())
+ arg = translateType(argument->type(), func->implementingClass(), options);
+ else
+ arg = modified_type.replace('$', '.');
+
+ if (!(options & Generator::SkipName)) {
+ arg += " ";
+ arg += argument->name();
+ }
+
+ QList<ReferenceCount> referenceCounts;
+ referenceCounts = func->referenceCounts(func->implementingClass(), argument->argumentIndex() + 1);
+ if ((options & Generator::SkipDefaultValues) != Generator::SkipDefaultValues &&
+ !argument->originalDefaultValueExpression().isEmpty())
+ {
+ QString default_value = argument->originalDefaultValueExpression();
+ if (default_value == "NULL")
+ default_value = NULL_VALUE;
+
+ //WORKAROUND: fix this please
+ if (default_value.startsWith("new "))
+ default_value.remove(0, 4);
+
+ arg += " = " + default_value;
+ }
+
+ return arg;
+}
+
+void ShibokenGenerator::writeArgument(QTextStream &s,
+ const AbstractMetaFunction *func,
+ const AbstractMetaArgument *argument,
+ Options options) const
+{
+ s << argumentString(func, argument, options);
+}
+
+void ShibokenGenerator::writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction *func,
+ Options options) const
+{
+ AbstractMetaArgumentList arguments = func->arguments();
+
+ if (options & Generator::WriteSelf) {
+ s << func->implementingClass()->name() << '&';
+ if (!(options & SkipName))
+ s << " self";
+ }
+
+ int argUsed = 0;
+ for (int i = 0; i < arguments.size(); ++i) {
+ if ((options & Generator::SkipRemovedArguments) && func->argumentRemoved(i+1))
+ continue;
+
+ if ((options & Generator::WriteSelf) || argUsed != 0)
+ s << ", ";
+ writeArgument(s, func, arguments[i], options);
+ argUsed++;
+ }
+}
+
+QString ShibokenGenerator::functionReturnType(const AbstractMetaFunction* func, Options options) const
+{
+ QString modifiedReturnType = QString(func->typeReplaced(0));
+ if (!modifiedReturnType.isNull() && !(options & OriginalTypeDescription))
+ return modifiedReturnType;
+ else
+ return translateType(func->type(), func->implementingClass(), options);
+}
+
+QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func,
+ QString prepend,
+ QString append,
+ Options options,
+ int argCount) const
+{
+ QString result;
+ QTextStream s(&result);
+ // The actual function
+ if (!(func->isEmptyFunction() ||
+ func->isNormal() ||
+ func->isSignal())) {
+ options |= Generator::SkipReturnType;
+ } else {
+ s << functionReturnType(func, options) << ' ';
+ }
+
+ // name
+ QString name(func->originalName());
+ if (func->isConstructor())
+ name = wrapperName(func->ownerClass());
+
+ s << prepend << name << append << '(';
+ writeFunctionArguments(s, func, options);
+ s << ')';
+
+ if (func->isConstant() && !(options & Generator::ExcludeMethodConst))
+ s << " const";
+
+ return result;
+}
+
+void ShibokenGenerator::writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction *func,
+ Options options) const
+{
+ AbstractMetaArgumentList arguments = func->arguments();
+ int argCount = 0;
+ for (int j = 0, max = arguments.size(); j < max; j++) {
+
+ if ((options & Generator::SkipRemovedArguments) &&
+ (func->argumentRemoved(arguments.at(j)->argumentIndex() +1)))
+ continue;
+
+ if (argCount > 0)
+ s << ", ";
+ s << arguments.at(j)->name();
+
+ if (((options & Generator::VirtualCall) == 0) &&
+ (!func->conversionRule(TypeSystem::NativeCode, arguments.at(j)->argumentIndex() + 1).isEmpty() ||
+ !func->conversionRule(TypeSystem::TargetLangCode, arguments.at(j)->argumentIndex() + 1).isEmpty())
+ )
+ s << "_out";
+
+ argCount++;
+ }
+}
+
+void ShibokenGenerator::writeFunctionCall(QTextStream& s,
+ const AbstractMetaFunction* func,
+ Options options) const
+{
+ if (!(options & Generator::SkipName))
+ s << (func->isConstructor() ? func->ownerClass()->qualifiedCppName() : func->originalName());
+ s << '(';
+ writeArgumentNames(s, func, options);
+ s << ')';
+}
+
+AbstractMetaFunctionList ShibokenGenerator::filterFunctions(const AbstractMetaClass* metaClass)
+{
+ 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
+ continue;
+ }
+ result << func;
+ }
+ return result;
+}
+
+ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverters() const
+{
+ ExtendedConverterData extConvs;
+ foreach (const AbstractMetaClass* metaClass, classes()) {
+ // Use only the classes for the current module.
+ if (!shouldGenerate(metaClass))
+ continue;
+ foreach (AbstractMetaFunction* convOp, metaClass->operatorOverloads(AbstractMetaClass::ConversionOp)) {
+ // Get only the conversion operators that return a type from another module,
+ // that are value-types and were not removed in the type system.
+ const TypeEntry* convType = convOp->type()->typeEntry();
+ if ((convType->codeGeneration() & TypeEntry::GenerateTargetLang)
+ || !convType->isValue()
+ || convOp->isModifiedRemoved())
+ continue;
+ extConvs[convType].append(convOp->ownerClass());
+ }
+ }
+ return extConvs;
+}
+
+void ShibokenGenerator::writeCodeSnips(QTextStream& s,
+ const CodeSnipList& codeSnips,
+ CodeSnip::Position position,
+ TypeSystem::Language language,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* lastArg,
+ const AbstractMetaClass* context)
+{
+ static QRegExp toPythonRegex("%CONVERTTOPYTHON\\[([^\\[]*)\\]");
+ static QRegExp toCppRegex("%CONVERTTOCPP\\[([^\\[]*)\\]");
+ static QRegExp pyArgsRegex("%PYARG_(\\d+)");
+
+ // detect is we should use pyargs instead of args as variable name for python arguments
+ bool usePyArgs = false;
+ int numArgs = 0;
+ if (func) {
+ // calc num of real arguments.
+ int argsRemoved = 0;
+ for (int i = 0; i < func->arguments().size(); i++) {
+ if (func->argumentRemoved(i+1))
+ argsRemoved++;
+ }
+ numArgs = func->arguments().size() - argsRemoved;
+ usePyArgs = pythonFunctionWrapperUsesListOfArguments(OverloadData(getFunctionGroups(func->implementingClass())[func->name()], this));
+ }
+
+ foreach (CodeSnip snip, codeSnips) {
+ if ((position != CodeSnip::Any && snip.position != position) || !(snip.language & language))
+ continue;
+
+ QString code;
+ QTextStream tmpStream(&code);
+ formatCode(tmpStream, snip.code(), INDENT);
+
+ if (context) {
+ // replace template variable for the Python Type object for the
+ // class context in which the variable is used
+ code.replace("%PYTHONTYPEOBJECT", cpythonTypeName(context) + ".super.ht_type");
+ }
+
+ // replace "toPython "converters
+ code.replace(toPythonRegex, "Shiboken::Converter<\\1 >::toPython");
+
+ // replace "toCpp "converters
+ code.replace(toCppRegex, "Shiboken::Converter<\\1 >::toCpp");
+
+ if (func) {
+ // replace %PYARG_# variables
+ code.replace("%PYARG_0", PYTHON_RETURN_VAR);
+ if (snip.language == TypeSystem::TargetLangCode) {
+ if (usePyArgs) {
+ code.replace(pyArgsRegex, "pyargs[\\1-1]");
+ } else {
+ static QRegExp pyArgsRegexCheck("%PYARG_([2-9]+)");
+ if (pyArgsRegexCheck.indexIn(code) != -1)
+ ReportHandler::warning("Wrong index for %PYARG variable ("+pyArgsRegexCheck.cap(1)+") on "+func->signature());
+ else
+ code.replace("%PYARG_1", usePyArgs ? "pyargs[0]" : "arg");
+ }
+ } else {
+ // Replaces the simplest case of attribution to a Python argument
+ // on the binding virtual method.
+ static QRegExp pyArgsAttributionRegex("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)");
+ code.replace(pyArgsAttributionRegex, "PyTuple_SET_ITEM(pyargs, \\1-1, \\2)");
+
+ code.replace(pyArgsRegex, "PyTuple_GET_ITEM(pyargs, \\1-1)");
+ }
+
+ // replace %ARG#_TYPE variables
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ QString argTypeVar = QString("%ARG%1_TYPE").arg(arg->argumentIndex() + 1);
+ QString argTypeVal = arg->type()->cppSignature();
+ code.replace(argTypeVar, argTypeVal);
+ }
+
+ static QRegExp cppArgTypeRegexCheck("%ARG(\\d+)_TYPE");
+ int pos = 0;
+ while ((pos = cppArgTypeRegexCheck.indexIn(code, pos)) != -1) {
+ ReportHandler::warning("Wrong index for %ARG#_TYPE variable ("+cppArgTypeRegexCheck.cap(1)+") on "+func->signature());
+ pos += cppArgTypeRegexCheck.matchedLength();
+ }
+
+ // replace template variable for return variable name
+ if (func->isConstructor()) {
+ code.replace("%0.", QString("%1->").arg("cptr"));
+ code.replace("%0", "cptr");
+ } else if (func->type()) {
+ QString returnValueOp = func->type()->isObject() || func->type()->isQObject() ? "%1->" : "%1.";
+ if (func->type()->typeEntry()->isValue() || func->type()->typeEntry()->isObject())
+ code.replace("%0.", returnValueOp.arg(CPP_RETURN_VAR));
+ code.replace("%0", CPP_RETURN_VAR);
+ }
+
+ // replace template variable for self Python object
+ QString pySelf;
+ if (snip.language == TypeSystem::NativeCode)
+ pySelf = "pySelf";
+ else
+ pySelf = "self";
+ code.replace("%PYSELF", pySelf);
+
+ // replace template variable for pointer to C++ this object
+ if (func->implementingClass()) {
+ QString cppSelf;
+ QString replacement("%1->");
+ if (func->isStatic()) {
+ cppSelf = func->ownerClass()->qualifiedCppName();
+ replacement = "%1::";
+ } else if (snip.language == TypeSystem::NativeCode) {
+ cppSelf = "this";
+ } else {
+ cppSelf = "cppSelf";
+ }
+ code.replace("%CPPSELF.", replacement.arg(cppSelf));
+ code.replace("%CPPSELF", cppSelf);
+
+ // 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()) + ".super.ht_type");
+ } else {
+ code.replace("%PYTHONTYPEOBJECT.", QString("%1->ob_type->").arg(pySelf));
+ code.replace("%PYTHONTYPEOBJECT", QString("%1->ob_type").arg(pySelf));
+ }
+ }
+
+ // replace template variables %# for individual arguments
+ int removed = 0;
+ for (int i = 0; i < func->arguments().size(); i++) {
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+ QString argReplacement;
+ if (snip.language == TypeSystem::TargetLangCode) {
+ if (!lastArg || func->argumentRemoved(i+1)) {
+ if (!arg->defaultValueExpression().isEmpty())
+ argReplacement = arg->defaultValueExpression();
+ removed++;
+ } else if (lastArg && (arg->argumentIndex() > lastArg->argumentIndex())) {
+ argReplacement = arg->defaultValueExpression();
+ }
+
+ if (argReplacement.isEmpty()) {
+ if (arg->type()->typeEntry()->isCustom()) {
+ argReplacement = usePyArgs ? QString("pyargs[%1]").arg(i - removed) : "arg";
+ } else {
+ argReplacement = QString("cpp_arg%1").arg(i - removed);
+ if (shouldDereferenceArgumentPointer(arg))
+ argReplacement.prepend("(*").append(')');
+ }
+ }
+ } else {
+ argReplacement = arg->name();
+ }
+ code.replace("%" + QString::number(i+1), argReplacement);
+ }
+
+ // replace template %ARGUMENT_NAMES variable for a list of arguments
+ removed = 0;
+ QStringList argumentNames;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (snip.language == TypeSystem::TargetLangCode) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1)) {
+ if (!arg->defaultValueExpression().isEmpty())
+ argumentNames << arg->defaultValueExpression();
+ removed++;
+ continue;
+ }
+
+ QString argName;
+ if (lastArg && arg->argumentIndex() > lastArg->argumentIndex()) {
+ argName = arg->defaultValueExpression();
+ } else {
+ argName = QString("cpp_arg%1").arg(arg->argumentIndex() - removed);
+ if (shouldDereferenceArgumentPointer(arg))
+ argName.prepend('*');
+ }
+ argumentNames << argName;
+ } else {
+ argumentNames << arg->name();
+ }
+ }
+ code.replace("%ARGUMENT_NAMES", argumentNames.join(", "));
+
+ if (snip.language == TypeSystem::NativeCode) {
+ // replace template %PYTHON_ARGUMENTS variable for a pointer to the Python tuple
+ // containing the converted virtual method arguments received from C++ to be passed
+ // to the Python override
+ code.replace("%PYTHON_ARGUMENTS", "pyargs");
+
+ // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method
+ // override for the C++ virtual method in which this piece of code was inserted
+ 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 (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()));
+
+ replaceTemplateVariables(code, func);
+ }
+
+ if (!code.isEmpty()) {
+ s << INDENT << "// Begin code injection" << endl;
+ s << code;
+ s << INDENT << "// End of code injection" << endl;
+ }
+ }
+}
+
+bool ShibokenGenerator::injectedCodeUsesCppSelf(const AbstractMetaFunction* func)
+{
+ CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::TargetLangCode);
+ foreach (CodeSnip snip, snips) {
+ if (snip.code().contains("%CPPSELF"))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeUsesPySelf(const AbstractMetaFunction* func)
+{
+ CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::NativeCode);
+ foreach (CodeSnip snip, snips) {
+ if (snip.code().contains("%PYSELF"))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeCallsCppFunction(const AbstractMetaFunction* func)
+{
+ QString funcCall = QString("%1(").arg(func->originalName());
+ QString wrappedCtorCall;
+ if (func->isConstructor()) {
+ funcCall.prepend("new ");
+ wrappedCtorCall = QString("new %1(").arg(wrapperName(func->ownerClass()));
+ }
+ CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::TargetLangCode);
+ foreach (CodeSnip snip, snips) {
+ if (snip.code().contains("%FUNCTION_NAME(") || snip.code().contains(funcCall)
+ || (func->isConstructor()
+ && ((func->ownerClass()->isPolymorphic() && snip.code().contains(wrappedCtorCall))
+ || snip.code().contains("new %TYPE(")))
+ )
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeCallsPythonOverride(const AbstractMetaFunction* func)
+{
+ static QRegExp overrideCallRegexCheck("PyObject_Call\\s*\\(\\s*%PYTHON_METHOD_OVERRIDE\\s*,");
+ CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::NativeCode);
+ foreach (CodeSnip snip, snips) {
+ if (overrideCallRegexCheck.indexIn(snip.code()) != -1)
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func, TypeSystem::Language language)
+{
+ static QRegExp retValAttributionRegexCheck_native("%0\\s*=[^=]\\s*.+");
+ static QRegExp retValAttributionRegexCheck_target("%PYARG_0\\s*=[^=]\\s*.+");
+ CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, language);
+ foreach (CodeSnip snip, snips) {
+ if (language == TypeSystem::TargetLangCode) {
+ if (retValAttributionRegexCheck_target.indexIn(snip.code()) != -1)
+ return true;
+ } else {
+ if (retValAttributionRegexCheck_native.indexIn(snip.code()) != -1)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ShibokenGenerator::hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass || metaClass->baseClassNames().isEmpty())
+ return false;
+ if (metaClass->baseClassNames().size() > 1)
+ return true;
+ return hasMultipleInheritanceInAncestry(metaClass->baseClass());
+}
+
+bool ShibokenGenerator::classNeedsGetattroFunction(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return false;
+ foreach (AbstractMetaFunctionList allOverloads, getFunctionGroups(metaClass).values()) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, allOverloads) {
+ if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved()
+ || func->isPrivate() || func->ownerClass() != func->implementingClass()
+ || func->isConstructor() || func->isOperatorOverload())
+ continue;
+ overloads.append(func);
+ }
+ if (overloads.isEmpty())
+ continue;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads))
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass)
+{
+ AbstractMetaFunctionList methods;
+ if (metaClass) {
+ foreach (AbstractMetaFunctionList allOverloads, getFunctionGroups(metaClass).values()) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, allOverloads) {
+ if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved()
+ || func->isPrivate() || func->ownerClass() != func->implementingClass()
+ || func->isConstructor() || func->isOperatorOverload())
+ continue;
+ overloads.append(func);
+ }
+ if (overloads.isEmpty())
+ continue;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads))
+ methods.append(overloads.first());
+ }
+ }
+ return methods;
+}
+
+AbstractMetaClassList ShibokenGenerator::getBaseClasses(const AbstractMetaClass* metaClass)
+{
+ AbstractMetaClassList baseClasses;
+ foreach (QString parent, metaClass->baseClassNames()) {
+ AbstractMetaClass* clazz = classes().findClass(parent);
+ if (clazz)
+ baseClasses << clazz;
+ }
+ 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());
+}
+
+AbstractMetaClassList ShibokenGenerator::getAllAncestors(const AbstractMetaClass* metaClass)
+{
+ AbstractMetaClassList result;
+ AbstractMetaClassList baseClasses = getBaseClasses(metaClass);
+ foreach (AbstractMetaClass* base, baseClasses) {
+ result.append(base);
+ result.append(getAllAncestors(base));
+ }
+ return result;
+}
+
+QString ShibokenGenerator::getModuleHeaderFileName(const QString& moduleName) const
+{
+ QString result = moduleName.isEmpty() ? packageName() : moduleName;
+ result.replace(".", "_");
+ return QString("%1_python.h").arg(result.toLower());
+}
+
+QString ShibokenGenerator::extendedIsConvertibleFunctionName(const TypeEntry* targetType) const
+{
+ return QString("ExtendedIsConvertible_%1_%2").arg(targetType->targetLangPackage().replace('.', '_')).arg(targetType->name());
+}
+
+QString ShibokenGenerator::extendedToCppFunctionName(const TypeEntry* targetType) const
+{
+ return QString("ExtendedToCpp_%1_%2").arg(targetType->targetLangPackage().replace('.', '_')).arg(targetType->name());
+}
+
+bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass)
+
+{
+ if (metaClass->isNamespace() || metaClass->typeEntry()->isObject())
+ return false;
+ else if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown)
+ return metaClass->hasCloneOperator();
+ else
+ return (metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet);
+
+ return false;
+}
+
+AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeString)
+{
+ typeString = typeString.trimmed();
+ bool isConst = typeString.startsWith("const ");
+ if (isConst)
+ typeString.remove(0, sizeof("const ") / sizeof(char) - 1);
+
+ int indirections = typeString.count("*");
+ while (typeString.endsWith("*")) {
+ typeString.chop(1);
+ typeString = typeString.trimmed();
+ }
+
+ bool isReference = typeString.endsWith("&");
+ if (isReference) {
+ typeString.chop(1);
+ typeString = typeString.trimmed();
+ }
+
+ TypeEntry* typeEntry = TypeDatabase::instance()->findType(typeString);
+ AbstractMetaType* metaType = 0;
+ if (typeEntry) {
+ metaType = new AbstractMetaType();
+ metaType->setTypeEntry(typeEntry);
+ metaType->setIndirections(indirections);
+ metaType->setReference(isReference);
+ metaType->setConstant(isConst);
+ if (metaType->name() == "char" && metaType->indirections() == 1)
+ metaType->setTypeUsagePattern(AbstractMetaType::NativePointerPattern);
+ }
+ return metaType;
+}
+
+/*
+static void dumpFunction(AbstractMetaFunctionList lst)
+{
+ qDebug() << "DUMP FUNCTIONS: ";
+ foreach (AbstractMetaFunction *func, lst)
+ qDebug() << "*" << func->ownerClass()->name()
+ << func->signature()
+ << "Private: " << func->isPrivate()
+ << "Empty: " << func->isEmptyFunction()
+ << "Static:" << func->isStatic()
+ << "Signal:" << func->isSignal()
+ << "ClassImplements: " << (func->ownerClass() != func->implementingClass())
+ << "is operator:" << func->isOperatorOverload()
+ << "is global:" << func->isInGlobalScope();
+}
+*/
+
+static bool isGroupable(const AbstractMetaFunction* func)
+{
+ if (func->isSignal() || func->isDestructor() || (func->isModifiedRemoved() && !func->isAbstract()))
+ return false;
+ // weird operator overloads
+ if (func->name() == "operator[]" || func->name() == "operator->") // FIXME: what about cast operators?
+ return false;;
+ return true;
+}
+
+QMap< QString, AbstractMetaFunctionList > ShibokenGenerator::getFunctionGroups(const AbstractMetaClass* scope)
+{
+ AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions();
+
+ QMap<QString, AbstractMetaFunctionList> results;
+ foreach (AbstractMetaFunction* func, lst) {
+ if (isGroupable(func))
+ results[func->name()].append(func);
+ }
+ return results;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName)
+{
+ AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions();
+
+ AbstractMetaFunctionList results;
+ foreach (AbstractMetaFunction* func, lst) {
+ if (func->name() != functionName)
+ continue;
+ if (isGroupable(func))
+ results << func;
+ }
+ return results;
+
+}
+
+QPair< int, int > ShibokenGenerator::getMinMaxArguments(const AbstractMetaFunction* metaFunction)
+{
+ AbstractMetaFunctionList overloads = getFunctionOverloads(metaFunction->ownerClass(), metaFunction->name());
+
+ int minArgs = std::numeric_limits<int>::max();
+ int maxArgs = 0;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ int numArgs = 0;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (!func->argumentRemoved(arg->argumentIndex() + 1))
+ numArgs++;
+ }
+ maxArgs = std::max(maxArgs, numArgs);
+ minArgs = std::min(minArgs, numArgs);
+ }
+ return qMakePair(minArgs, maxArgs);
+}
+
+QMap<QString, QString> ShibokenGenerator::options() const
+{
+ QMap<QString, QString> opts(Generator::options());
+ 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.");
+ opts.insert(DISABLE_VERBOSE_ERROR_MESSAGES, "Disable verbose error messages. Turn the python code hard to debug but safe few kB on the generated bindings.");
+ return opts;
+}
+
+bool ShibokenGenerator::doSetup(const QMap<QString, QString>& args)
+{
+ m_useCtorHeuristic = args.contains(PARENT_CTOR_HEURISTIC);
+ m_usePySideExtensions = args.contains(ENABLE_PYSIDE_EXTENSIONS);
+ m_userReturnValueHeuristic = args.contains(RETURN_VALUE_HEURISTIC);
+ m_verboseErrorMessagesDisabled = args.contains(DISABLE_VERBOSE_ERROR_MESSAGES);
+ return true;
+}
+
+bool ShibokenGenerator::useCtorHeuristic() const
+{
+ return m_useCtorHeuristic;
+}
+
+bool ShibokenGenerator::useReturnValueHeuristic() const
+{
+ return m_userReturnValueHeuristic;
+}
+
+bool ShibokenGenerator::usePySideExtensions() const
+{
+ return m_usePySideExtensions;
+}
+
+QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const
+{
+ QString result = moduleName.isEmpty() ? ShibokenGenerator::packageName() : moduleName;
+ result.replace(".", "_");
+ result.prepend("Sbk");
+ result.append("Types");
+ return result;
+}
+
+QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* metaType)
+{
+ QString res("SBK_");
+ res += metaType->qualifiedCppName();
+ res.replace("::", "_");
+ res.replace("<", "_");
+ res.replace(">", "_");
+ res += "_IDX";
+ return res.toUpper();
+}
+
+bool ShibokenGenerator::verboseErrorMessagesDisabled() const
+{
+ return m_verboseErrorMessagesDisabled;
+}
+
+
+bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const OverloadData& overloadData)
+{
+ int maxArgs = overloadData.maxArgs();
+ int minArgs = overloadData.minArgs();
+ bool usePyArgs = (minArgs != maxArgs)
+ || (maxArgs > 1)
+ || overloadData.referenceFunction()->isConstructor()
+ || overloadData.hasArgumentWithDefaultValue();
+ return usePyArgs;
+}
+
diff --git a/generator/shibokengenerator.h b/generator/shibokengenerator.h
new file mode 100644
index 00000000..1a7c5a63
--- /dev/null
+++ b/generator/shibokengenerator.h
@@ -0,0 +1,364 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 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 General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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
+ *
+ */
+
+#ifndef SHIBOKENGENERATOR_H
+#define SHIBOKENGENERATOR_H
+
+#define PYTHON_RETURN_VAR "pyResult"
+#define CPP_RETURN_VAR "cppResult"
+#define THREAD_STATE_SAVER_VAR "threadStateSaver"
+#define CPP_SELF_VAR "cppSelf"
+
+#include <generator.h>
+#include <QtCore/QTextStream>
+
+#include "overloaddata.h"
+
+class DocParser;
+
+/**
+ * Abstract generator that contains common methods used in CppGenerator and HeaderGenerator.
+ */
+class ShibokenGenerator : public Generator
+{
+public:
+ ShibokenGenerator();
+
+ QString translateTypeForWrapperMethod(const AbstractMetaType* cType,
+ const AbstractMetaClass* context, Options opt = NoOption) const;
+
+ /**
+ * Returns a map with all functions grouped, the function name is used as key.
+ * Example ofg return value: { "foo" -> ["foo(int)", "foo(int, long)], "bar" -> "bar(double)"}
+ * \param scope Where to search for functions, null means all global functions.
+ */
+ QMap<QString, AbstractMetaFunctionList> getFunctionGroups(const AbstractMetaClass* scope = 0);
+ /**
+ * Returns all overloads for a function named \p functionName.
+ * \param scope scope used to search for overloads.
+ * \param functionName the function name.
+ */
+ AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName);
+ /**
+ * Returns the minimun and maximun number of arguments which this function and all overloads
+ * can accept. Arguments removed by typesystem are considered as well.
+ */
+ QPair<int, int> getMinMaxArguments(const AbstractMetaFunction* metaFunction);
+ /**
+ * Write a function argument in the C++ in the text stream \p s.
+ * This function just call \code s << argumentString(); \endcode
+ * \param s text stream used to write the output.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ void writeArgument(QTextStream &s,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ Options options = NoOption) const;
+ /**
+ * Create a QString in the C++ format to an function argument.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ QString argumentString(const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ Options options = NoOption) const;
+
+ void writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction* func,
+ Options options = NoOption) const;
+
+ /**
+ * Function used to write the fucntion arguments on the class buffer.
+ * \param s the class output buffer
+ * \param func the pointer to metafunction information
+ * \param count the number of function arguments
+ * \param options some extra options used during the parser
+ */
+ void writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction* func,
+ Options options = NoOption) const;
+ QString functionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
+ /**
+ * Write a code snip into the buffer \p s.
+ * CodeSnip are codes inside inject-code tags.
+ * \param s the buffer
+ * \param code_snips a list of code snips
+ * \param position the position to insert the code snip
+ * \param language the kind of code snip
+ * \param func the cpp function
+ * \param lastArg last argument whose value is available, usually the last;
+ * a NULL pointer indicates that no argument will be available,
+ * i.e. a call without arguments.
+ * \param context the class context for the place where the code snip will be written
+ */
+ void writeCodeSnips(QTextStream &s,
+ const CodeSnipList &code_snips,
+ CodeSnip::Position position,
+ TypeSystem::Language language,
+ const AbstractMetaFunction* func = 0,
+ const AbstractMetaArgument* lastArg = 0,
+ const AbstractMetaClass* context = 0);
+
+ /**
+ * Verifies if any of the function's code injections of the "target"
+ * type needs the type system variable "%CPPSELF".
+ * \param func the function to check
+ * \return true if the function's target code snippets use "%CPPSELF"
+ */
+ bool injectedCodeUsesCppSelf(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections of the "native"
+ * type needs the type system variable "%PYSELF".
+ * \param func the function to check
+ * \return true if the function's native code snippets use "%PYSELF"
+ */
+ bool injectedCodeUsesPySelf(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections makes a call
+ * to the C++ method. This is used by the generator to avoid writing calls
+ * to C++ when the user custom code already does this.
+ * \param func the function to check
+ * \return true if the function's code snippets call the wrapped C++ function
+ */
+ bool injectedCodeCallsCppFunction(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections of the "native" class makes a
+ * call to the C++ method. This is used by the generator to avoid writing calls to
+ * Python overrides of C++ virtual methods when the user custom code already does this.
+ * \param func the function to check
+ * \return true if the function's code snippets call the Python override for a C++ virtual method
+ */
+ bool injectedCodeCallsPythonOverride(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections attributes values to
+ * the return variable (%0 or %PYARG_0).
+ * \param func the function to check
+ * \param language the kind of code snip
+ * \return true if the function's code attributes values to "%0" or "%PYARG_0"
+ */
+ bool injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func, TypeSystem::Language language = TypeSystem::TargetLangCode);
+
+ /**
+ * Function which parse the metafunction information
+ * \param func the function witch will be parserd
+ * \param option some extra options
+ * \param arg_count the number of function arguments
+ */
+ QString functionSignature(const AbstractMetaFunction* func,
+ QString prepend = "",
+ QString append = "",
+ Options options = NoOption,
+ int arg_count = -1) const;
+
+ /// Returns true if there are cases of multiple inheritance in any of its ancestors.
+ bool hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the class needs to have a getattro function.
+ bool classNeedsGetattroFunction(const AbstractMetaClass* metaClass);
+
+ /// Returns a list of methods of the given class where each one is part of a different overload with both static and non-static method.
+ AbstractMetaFunctionList getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass);
+
+ /// Returns a list of parent classes for a given class.
+ AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass);
+
+ /// Returns a list of all ancestor classes for the given class.
+ AbstractMetaClassList getAllAncestors(const AbstractMetaClass* metaClass);
+
+ const AbstractMetaClass* getMultipleInheritingClass(const AbstractMetaClass* metaClass);
+
+ void writeBaseConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, Options options = NoOption);
+ /// Simpler version of writeBaseConversion, uses only the base name of the type.
+ void writeBaseConversion(QTextStream& s, const TypeEntry* type);
+ void writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, const QString& argumentName = QString());
+ void writeToCppConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, const QString& argumentName, Options options = NoOption);
+ 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);
+
+ static QString wrapperName(const AbstractMetaClass* metaClass);
+
+ static QString fullPythonFunctionName(const AbstractMetaFunction* func);
+ static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum);
+ static QString protectedFieldGetterName(const AbstractMetaField* field);
+ static QString protectedFieldSetterName(const AbstractMetaField* field);
+
+ static QString pythonPrimitiveTypeName(const QString& cppTypeName);
+ static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry* type);
+
+ static QString pythonOperatorFunctionName(QString cppOpFuncName);
+ static QString pythonOperatorFunctionName(const AbstractMetaFunction* func);
+ static QString pythonRichCompareOperatorId(QString cppOpFuncName);
+ static QString pythonRichCompareOperatorId(const AbstractMetaFunction* func);
+
+ static QString cpythonOperatorFunctionName(const AbstractMetaFunction* func);
+
+ static bool isNumber(QString cpythonApiName);
+ static bool isNumber(const TypeEntry* type);
+ static bool isNumber(const AbstractMetaType* type);
+ static bool isPyInt(const TypeEntry* type);
+ static bool isPyInt(const AbstractMetaType* type);
+ static bool isCString(const AbstractMetaType* type);
+ static bool isPairContainer(const AbstractMetaType* type);
+
+ /// Checks if an argument type should be dereferenced by the Python method wrapper before calling the C++ method.
+ static bool shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg);
+ /// Checks if a meta type should be dereferenced by the Python method wrapper passing it to C++.
+ static bool shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType* metaType);
+
+ static bool visibilityModifiedToPrivate(const AbstractMetaFunction* func);
+
+ QString cpythonBaseName(const AbstractMetaClass* metaClass);
+ QString cpythonBaseName(const TypeEntry* type);
+ QString cpythonBaseName(const AbstractMetaType* type);
+ QString cpythonTypeName(const AbstractMetaClass* metaClass);
+ QString cpythonTypeName(const TypeEntry* type);
+ QString cpythonTypeNameExt(const TypeEntry* type);
+ QString cpythonCheckFunction(const TypeEntry* type, bool genericNumberType = false);
+ QString cpythonCheckFunction(const AbstractMetaType* metaType, bool genericNumberType = false);
+ QString guessCPythonCheckFunction(const QString& type);
+ QString cpythonIsConvertibleFunction(const TypeEntry* type, bool genericNumberType = false, bool checkExact = false);
+ QString cpythonIsConvertibleFunction(const AbstractMetaType* metaType, bool genericNumberType = false);
+ QString cpythonIsConvertibleFunction(const AbstractMetaArgument* metaArg, bool genericNumberType = false)
+ {
+ return cpythonIsConvertibleFunction(metaArg->type(), genericNumberType);
+ }
+ QString guessCPythonIsConvertible(const QString& type);
+ QString cpythonFunctionName(const AbstractMetaFunction* func);
+ QString cpythonMethodDefinitionName(const AbstractMetaFunction* func);
+ QString cpythonGettersSettersDefinitionName(const AbstractMetaClass* metaClass);
+ QString cpythonGetattroFunctionName(const AbstractMetaClass* metaClass);
+ QString cpythonSetattroFunctionName(const AbstractMetaClass* metaClass);
+ QString cpythonGetterFunctionName(const AbstractMetaField* metaField);
+ QString cpythonSetterFunctionName(const AbstractMetaField* metaField);
+ QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName = "self");
+ QString cpythonWrapperCPtr(const AbstractMetaType* metaType, QString argName);
+ QString cpythonWrapperCPtr(const TypeEntry* type, QString argName);
+
+ /// Guesses the scope to where belongs an argument's default value.
+ QString guessScopeForDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
+
+ QString cpythonEnumName(const EnumTypeEntry* enumEntry);
+ QString cpythonEnumName(const AbstractMetaEnum* metaEnum)
+ {
+ return cpythonEnumName(metaEnum->typeEntry());
+ }
+
+ QString cpythonFlagsName(const FlagsTypeEntry* flagsEntry);
+ QString cpythonFlagsName(const AbstractMetaEnum* metaEnum)
+ {
+ FlagsTypeEntry* flags = metaEnum->typeEntry()->flags();
+ if (!flags)
+ return QString();
+ return cpythonFlagsName(flags);
+ }
+ /// Returns the special cast function name, the function used to proper cast class with multiple inheritance.
+ QString cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass);
+
+ QString getFunctionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
+ QString getFormatUnitString(const AbstractMetaFunction* func, bool incRef = false) const;
+
+ /// Returns the file name for the module global header. If no module name is provided the current will be used.
+ QString getModuleHeaderFileName(const QString& moduleName = QString()) const;
+
+ QString extendedIsConvertibleFunctionName(const TypeEntry* targetType) const;
+ QString extendedToCppFunctionName(const TypeEntry* targetType) const;
+
+ QMap< QString, QString > options() const;
+
+ /// Returns true if the user enabled the so called "parent constructor heuristic".
+ bool useCtorHeuristic() const;
+ /// Returns true if the user enabled the so called "return value heuristic".
+ bool useReturnValueHeuristic() const;
+ /// Returns true if the user enabled PySide extensions.
+ bool usePySideExtensions() 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.
+ bool verboseErrorMessagesDisabled() const;
+
+ /**
+ * Builds an AbstractMetaType object from a QString.
+ * Returns NULL if no type could be built from the string.
+ * \param typeString The string describing the type to be built.
+ * \return A new AbstractMetaType object that must be deleted by the caller, or a NULL pointer in case of failure.
+ */
+ AbstractMetaType* buildAbstractMetaTypeFromString(QString typeString);
+
+protected:
+ bool doSetup(const QMap<QString, QString>& args);
+ // verify whether the class is copyable
+ bool isCopyable(const AbstractMetaClass* metaClass);
+
+ bool m_native_jump_table;
+ static QHash<QString, QString> m_pythonPrimitiveTypeName;
+ static QHash<QString, QString> m_pythonOperators;
+ static QHash<QString, QString> m_formatUnits;
+ static QHash<QString, QString> m_tpFuncs;
+
+ void clearTpFuncs();
+
+ const char* name() const { return "Shiboken"; }
+
+ /**
+ * Initialize correspondences between primitive and Python types
+ */
+ static void initPrimitiveTypesCorrespondences();
+
+ void writeFunctionCall(QTextStream& s,
+ const AbstractMetaFunction* metaFunc,
+ Options options = NoOption) const;
+
+ static 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.
+ typedef QHash<const TypeEntry*, QList<const AbstractMetaClass*> > ExtendedConverterData;
+ /// Returns all extended conversions for the current module.
+ ExtendedConverterData getExtendedConverters() const;
+
+ /// Returns true if the Python wrapper for the received OverloadData must accept a list of arguments.
+ static bool pythonFunctionWrapperUsesListOfArguments(const OverloadData& overloadData);
+
+ Indentor INDENT;
+private:
+ bool m_useCtorHeuristic;
+ bool m_userReturnValueHeuristic;
+ bool m_usePySideExtensions;
+ bool m_verboseErrorMessagesDisabled;
+};
+
+
+#endif // SHIBOKENGENERATOR_H
+