/* * This file is part of the Shiboken Python Bindings Generator project. * * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). * * Contact: PySide team * * 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 #include #include #include #include #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 ShibokenGenerator::m_pythonPrimitiveTypeName = QHash(); QHash ShibokenGenerator::m_pythonOperators = QHash(); QHash ShibokenGenerator::m_formatUnits = QHash(); QHash ShibokenGenerator::m_tpFuncs = QHash(); 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 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 = getMinMaxArguments(func).second > 1; } 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 (numArgs > 1) { 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 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::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 ShibokenGenerator::options() const { QMap 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& 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; }