// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CPPGENERATOR_H #define CPPGENERATOR_H #include "shibokengenerator.h" #include "include.h" #include "modifications_typedefs.h" #include #include #include #include #include class OverloadDataNode; class OverloadDataRootNode; struct PyMethodDefEntry; /** * The CppGenerator generate the implementations of C++ bindings classes. */ class CppGenerator : public ShibokenGenerator { public: enum class ErrorReturn { Default, // "{}" Zero, MinusOne, Void }; enum CppSelfDefinitionFlag { HasStaticOverload = 0x1, HasClassMethodOverload = 0x2, CppSelfAsReference = 0x4 }; Q_DECLARE_FLAGS(CppSelfDefinitionFlags, CppSelfDefinitionFlag) CppGenerator(); const char *name() const override { return "Source generator"; } protected: QString fileNameForContext(const GeneratorContext &context) const override; void generateClass(TextStream &s, const GeneratorContext &classContext) override; bool finishGeneration() override; private: struct VirtualMethodReturn { QString statement; bool needsReference = false; }; void generateSmartPointerClass(TextStream &s, const GeneratorContext &classContext); void generateIncludes(TextStream &s, const GeneratorContext &classContext, const IncludeGroupList &includes = {}, const AbstractMetaClassCList &innerClasses = {}) const; static void writeInitFunc(TextStream &declStr, TextStream &callStr, const QString &initFunctionName, const TypeEntryCPtr &enclosingEntry, const QString &pythonName, bool lazy = true); static void writeCacheResetNative(TextStream &s, const GeneratorContext &classContext); void writeConstructorNative(TextStream &s, const GeneratorContext &classContext, const AbstractMetaFunctionCPtr &func) const; static void writeDestructorNative(TextStream &s, const GeneratorContext &classContext); QString getVirtualFunctionReturnTypeName(const AbstractMetaFunctionCPtr &func) const; static std::pair virtualMethodNativeArg(const AbstractMetaFunctionCPtr &func, const AbstractMetaArgument &arg); static void writeVirtualMethodNativeVectorCallArgs(TextStream &s, const AbstractMetaFunctionCPtr &func, const AbstractMetaArgumentList &arguments, const QList &invalidateArgs); static void writeVirtualMethodNativeArgs(TextStream &s, const AbstractMetaFunctionCPtr &func, const AbstractMetaArgumentList &arguments, const QList &invalidateArgs); void writeVirtualMethodNative(TextStream &s, const AbstractMetaFunctionCPtr &func, int cacheIndex) const; void writeVirtualMethodPythonOverride(TextStream &s, const AbstractMetaFunctionCPtr &func, const CodeSnipList &snips, const VirtualMethodReturn &returnStatement) const; void writeUserAddedPythonOverride(TextStream &s, const AbstractMetaFunctionCPtr &func) const; void writeVirtualMethodCppCall(TextStream &s, const AbstractMetaFunctionCPtr &func, const QString &funcName, const QList &snips, const AbstractMetaArgument *lastArg, const TypeEntryCPtr &retType, const QString &returnStatement, bool hasGil) const; static VirtualMethodReturn virtualMethodReturn(const ApiExtractorResult &api, const AbstractMetaFunctionCPtr &func, const FunctionModificationList &functionModifications); void writeMetaObjectMethod(TextStream &s, const GeneratorContext &classContext) const; static void writeMetaCast(TextStream &s, const GeneratorContext &classContext); void writeEnumConverterFunctions(TextStream &s, const AbstractMetaEnum &metaEnum) const; void writeConverterFunctions(TextStream &s, const AbstractMetaClassCPtr &metaClass, const GeneratorContext &classContext) const; void writeCustomConverterFunctions(TextStream &s, const CustomConversionPtr &customConversion) const; void writeConverterRegister(TextStream &s, const AbstractMetaClassCPtr &metaClass, const GeneratorContext &classContext) const; static void writeCustomConverterRegister(TextStream &s, const CustomConversionPtr &customConversion, const QString &converterVar); void writeContainerConverterFunctions(TextStream &s, const AbstractMetaType &containerType) const; struct OpaqueContainerData { QString name; QString checkFunctionName; QString converterCheckFunctionName; QString pythonToConverterFunctionName; QString registrationCode; }; OpaqueContainerData writeOpaqueContainerConverterFunctions(TextStream &s, const AbstractMetaType &containerType, QSet *valueTypes) const; void writeOpaqueContainerValueConverter(TextStream &s, const AbstractMetaType &valueType) const; void writeSmartPointerConverterFunctions(TextStream &s, const AbstractMetaType &smartPointerType) const; static bool needsArgumentErrorHandling(const OverloadData &overloadData); static void writeMethodWrapperPreamble(TextStream &s, const OverloadData &overloadData, const GeneratorContext &context, ErrorReturn errorReturn = ErrorReturn::Default); void writeConstructorWrapper(TextStream &s, const OverloadData &overloadData, const GeneratorContext &classContext) const; void writeMethodWrapper(TextStream &s, const OverloadData &overloadData, const GeneratorContext &classContext) const; void writeMethodWrapper(TextStream &s, TextStream &definitionStream, TextStream &signatureStream, const AbstractMetaFunctionCList &overloads, const GeneratorContext &classContext) const; static void writeArgumentsInitializer(TextStream &s, const OverloadData &overloadData, ErrorReturn errorReturn = ErrorReturn::Default); static void writeCppSelfConversion(TextStream &s, const GeneratorContext &context, const QString &className, bool useWrapperClass); static void writeSmartPointerCppSelfConversion(TextStream &s, const GeneratorContext &context); static void writeCppSelfVarDef(TextStream &s, CppSelfDefinitionFlags flags = {}); static void writeSmartPointerCppSelfDefinition(TextStream &s, const GeneratorContext &, ErrorReturn errorReturn = ErrorReturn::Default, CppSelfDefinitionFlags flags = {}); static void writeCppSelfDefinition(TextStream &s, const AbstractMetaFunctionCPtr &func, const GeneratorContext &context, ErrorReturn errorReturn = ErrorReturn::Default, CppSelfDefinitionFlags flags = {}); static void writeCppSelfDefinition(TextStream &s, const GeneratorContext &context, ErrorReturn errorReturn = ErrorReturn::Default, CppSelfDefinitionFlags flags = {}); static void writeErrorSection(TextStream &s, const OverloadData &overloadData, ErrorReturn errorReturn); static QString returnErrorWrongArguments(const OverloadData &overloadData, ErrorReturn errorReturn); static void writeFunctionReturnErrorCheckSection(TextStream &s, ErrorReturn errorReturn, bool hasReturnValue = true); /// Writes the check section for the validity of wrapped C++ objects. static void writeInvalidPyObjectCheck(TextStream &s, const QString &pyObj, ErrorReturn errorReturn); static void writeTypeCheck(TextStream &s, const AbstractMetaType &argType, const QString &argumentName, bool isNumber = false, bool rejectNull = false); static void writeTypeCheck(TextStream &s, const QString &customType, const QString &argumentName); static void writeTypeCheck(TextStream& s, const std::shared_ptr &overloadData, const QString &argumentName); static void replacePolymorphicIdPlaceHolders(const AbstractMetaClassCPtr &metaClass, QString *id); static void writeTypeDiscoveryFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass); static void writeSetattroDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass); static void writeSetattroDefaultReturn(TextStream &s); static void writeSmartPointerSetattroFunction(TextStream &s, const GeneratorContext &context); void writeSetattroFunction(TextStream &s, AttroCheck attroCheck, const GeneratorContext &context) const; static void writeGetattroDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass); static void writeSmartPointerGetattroFunction(TextStream &s, const GeneratorContext &context, const BoolCastFunctionOptional &boolCast); void writeGetattroFunction(TextStream &s, AttroCheck attroCheck, const GeneratorContext &context) const; QString qObjectGetAttroFunction() const; static void writeNbBoolFunction(const GeneratorContext &context, const BoolCastFunction &f, TextStream &s); static void writeNbBoolExpression(TextStream &s, const BoolCastFunction &f, bool invert = false); /** * 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 * \param castArgumentAsUnused if true the converted argument is cast as unused to avoid compiler warnings */ qsizetype writeArgumentConversion(TextStream &s, const AbstractMetaType &argType, const QString &argName, const QString &pyArgName, ErrorReturn errorReturn, const AbstractMetaClassCPtr &context = {}, const QString &defaultValue = QString(), bool castArgumentAsUnused = false) const; /** * Returns the AbstractMetaType for a function argument. * If the argument type was modified in the type system, this method will * try to build a new type based on the type name defined in the type system. * \param func The function which owns the argument. * \param index Argument index in the function signature. * \return The type of the argument indicated by \p index. */ static AbstractMetaType getArgumentType(const AbstractMetaFunctionCPtr &func, int index); /// Writes the Python to C++ Conversion for function arguments and return /// values of virtual methods for wrappers. /// \return The number of indirections in case of return types qsizetype writePythonToCppTypeConversion(TextStream &s, const AbstractMetaType &type, const QString &pyIn, const QString &cppOut, const AbstractMetaClassCPtr &context = {}, const QString &defaultValue = {}) const; /// Writes the conversion rule for arguments of regular and virtual methods. void writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func, TypeSystem::Language language, bool usesPyArgs) const; /// Writes the conversion rule for the return value of a method. void writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func, TypeSystem::Language language, const QString &outputVar) const; /** * 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' */ static void writeNoneReturn(TextStream &s, const AbstractMetaFunctionCPtr &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(TextStream &s, const OverloadData &overloadData, ErrorReturn errorReturn) const; /// Recursive auxiliar method to the other writeOverloadedFunctionDecisor. void writeOverloadedFunctionDecisorEngine(TextStream &s, const OverloadData &overloadData, const OverloadDataRootNode *node) const; /// Writes calls to all the possible method/function overloads. void writeFunctionCalls(TextStream &s, const OverloadData &overloadData, const GeneratorContext &context, ErrorReturn errorReturn) const; /// Writes the call to a single function usually from a collection of overloads. void writeSingleFunctionCall(TextStream &s, const OverloadData &overloadData, const AbstractMetaFunctionCPtr &func, const GeneratorContext &context, ErrorReturn errorReturn) const; /// Returns the name of a C++ to Python conversion function. static QString cppToPythonFunctionName(const QString &sourceTypeName, QString targetTypeName = QString()); /// Returns the name of a Python to C++ conversion function. static QString pythonToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName); static QString pythonToCppFunctionName(const AbstractMetaType &sourceType, const AbstractMetaType &targetType); static QString pythonToCppFunctionName(const TargetToNativeConversion &toNative, const TypeEntryCPtr &targetType); /// Returns the name of a Python to C++ convertible check function. static QString convertibleToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName); static QString convertibleToCppFunctionName(const AbstractMetaType &sourceType, const AbstractMetaType &targetType); static QString convertibleToCppFunctionName(const TargetToNativeConversion &toNative, const TypeEntryCPtr &targetType); /// Writes a C++ to Python conversion function. void writeCppToPythonFunction(TextStream &s, const QString &code, const QString &sourceTypeName, QString targetTypeName = QString()) const; void writeCppToPythonFunction(TextStream &s, const CustomConversionPtr &customConversion) const; void writeCppToPythonFunction(TextStream &s, const AbstractMetaType &containerType) const; /// Main target type name of a container (for naming the functions). static QString containerNativeToTargetTypeName(const ContainerTypeEntryCPtr &type); /// Writes a Python to C++ conversion function. void writePythonToCppFunction(TextStream &s, const QString &code, const QString &sourceTypeName, const QString &targetTypeName) const; /// Writes a Python to C++ convertible check function. static void writeIsPythonConvertibleToCppFunction(TextStream &s, const QString &sourceTypeName, const QString &targetTypeName, const QString &condition, QString pythonToCppFuncName = QString(), bool acceptNoneAsCppNull = false); /// Writes a pair of Python to C++ conversion and check functions. void writePythonToCppConversionFunctions(TextStream &s, const AbstractMetaType &sourceType, const AbstractMetaType &targetType, QString typeCheck = QString(), QString conversion = QString(), const QString &preConversion = QString()) const; /// Writes a pair of Python to C++ conversion and check functions for implicit conversions. void writePythonToCppConversionFunctions(TextStream &s, const TargetToNativeConversion &toNative, const TypeEntryCPtr &targetType) const; /// Writes a pair of Python to C++ conversion and check functions for instantiated container types. void writePythonToCppConversionFunctions(TextStream &s, const AbstractMetaType &containerType) const; void writePythonToCppConversionFunction(TextStream &s, const AbstractMetaType &containerType, const TargetToNativeConversion &conv) const; static void writeAddPythonToCppConversion(TextStream &s, const QString &converterVar, const QString &pythonToCppFunc, const QString &isConvertibleFunc); static void writeSetPythonToCppPointerConversion(TextStream &s, const QString &converterVar, const QString &pythonToCppFunc, const QString &isConvertibleFunc); static void writeNamedArgumentResolution(TextStream &s, const AbstractMetaFunctionCPtr &func, bool usePyArgs, const OverloadData &overloadData, ErrorReturn errorReturn); /// Returns a string containing the name of an argument for the given function and argument index. static QString argumentNameFromIndex(const ApiExtractorResult &api, const AbstractMetaFunctionCPtr &func, int argIndex); /// Returns the class for an ownership modification of the argument. /// Throws if the argument is not a class or cannot be found. static AbstractMetaClassCPtr argumentClassFromIndex(const ApiExtractorResult &api, const AbstractMetaFunctionCPtr &func, int argIndex); void writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr &func, const GeneratorContext &context, bool usesPyArgs, int maxArgs, const QList &argumentIndirections, ErrorReturn errorReturn) const; static QString getInitFunctionName(const GeneratorContext &context) ; static QString getSimpleClassInitFunctionName(const AbstractMetaClassCPtr &metaClass); static QString getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClassCPtr &metaClass); static void writeSignatureStrings(TextStream &s, const QString &signatures, const QString &arrayName, const char *comment); void writeClassRegister(TextStream &s, const AbstractMetaClassCPtr &metaClass, const GeneratorContext &classContext, const QString &signatures) const; static QStringList pyBaseTypes(const AbstractMetaClassCPtr &metaClass); static QString destructorClassName(const AbstractMetaClassCPtr &metaClass, const GeneratorContext &classContext); static void writeStaticFieldInitialization(TextStream &s, const AbstractMetaClassCPtr &metaClass); void writeClassDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass, const GeneratorContext &classContext); QByteArrayList methodDefinitionParameters(const OverloadData &overloadData) const; QList methodDefinitionEntries(const OverloadData &overloadData) const; void writeSignatureInfo(TextStream &s, const OverloadData &overloads) const; QString signatureParameter(const AbstractMetaArgument &arg) const; /// Writes the implementation of all methods part of python sequence protocol void writeSequenceMethods(TextStream &s, const AbstractMetaClassCPtr &metaClass, const GeneratorContext &context) const; static void writeTypeAsSequenceDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass); /// Writes the PyMappingMethods structure for types that supports the python mapping protocol. static void writeTypeAsMappingDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass); void writeMappingMethods(TextStream &s, const AbstractMetaClassCPtr &metaClass, const GeneratorContext &context) const; void writeTypeAsNumberDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass) const; static void writeTpTraverseFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass); static void writeTpClearFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass); static QString writeCopyFunction(TextStream &s, TextStream &definitionStream, TextStream &signatureStream, const GeneratorContext &context); static QString cppFieldAccess(const AbstractMetaField &metaField, const GeneratorContext &context); static void writeGetterFunction(TextStream &s, const AbstractMetaField &metaField, const GeneratorContext &context); static void writeGetterFunction(TextStream &s, const QPropertySpec &property, const GeneratorContext &context); static void writeSetterFunctionPreamble(TextStream &s, const QString &name, const QString &funcName, const AbstractMetaType &type, const GeneratorContext &context); static void writeSetterFunction(TextStream &s, const AbstractMetaField &metaField, const GeneratorContext &context); static void writeSetterFunction(TextStream &s, const QPropertySpec &property, const GeneratorContext &context); static void writeRichCompareFunctionHeader(TextStream &s, const QString &baseName, const GeneratorContext &context); void writeRichCompareFunction(TextStream &s, const GeneratorContext &context) const; void writeSmartPointerRichCompareFunction(TextStream &s, const GeneratorContext &context) const; static void writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums); static bool writeEnumInitialization(TextStream &s, const AbstractMetaEnum &metaEnum); static void writeSignalInitialization(TextStream &s, const AbstractMetaClassCPtr &metaClass); /// Writes the function that registers the multiple inheritance information /// for the classes that need it. static void writeMultipleInheritanceInitializerFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass); /// Writes the implementation of special cast functions, used when we need /// to cast a class with multiple inheritance. static void writeSpecialCastFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass); static void writePrimitiveConverterInitialization(TextStream &s, const CustomConversionPtr &customConversion); static void writeEnumConverterInitialization(TextStream &s, const AbstractMetaEnum &metaEnum); static QString writeContainerConverterInitialization(TextStream &s, const AbstractMetaType &type, const ApiExtractorResult &api); void writeSmartPointerConverterInitialization(TextStream &s, const AbstractMetaType &ype) const; static void writeExtendedConverterInitialization(TextStream &s, const TypeEntryCPtr &externalType, const AbstractMetaClassCList &conversions); void writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func, bool usesPyArgs, bool userHeuristicForReturn) const; bool writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func, int argIndex, bool usePyArgs, bool userHeuristicPolicy) const; void writeReturnValueHeuristics(TextStream &s, const AbstractMetaFunctionCPtr &func) const; static void writeInitQtMetaTypeFunctionBody(TextStream &s, const GeneratorContext &context); /** * 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. */ static QString multipleInheritanceInitializerFunctionName(const AbstractMetaClassCPtr &metaClass); /// Returns a list of all classes to which the given class could be cast. static QStringList getAncestorMultipleInheritance(const AbstractMetaClassCPtr &metaClass); /// Returns true if the given class supports the python number protocol static bool supportsNumberProtocol(const AbstractMetaClassCPtr &metaClass); /// Returns true if the given class supports the python sequence protocol static bool supportsSequenceProtocol(const AbstractMetaClassCPtr &metaClass) ; /// Returns true if the given class supports the python mapping protocol static bool supportsMappingProtocol(const AbstractMetaClassCPtr &metaClass) ; /// Returns true if generator should produce getters and setters for the given class. static bool shouldGenerateGetSetList(const AbstractMetaClassCPtr &metaClass); static bool hasHashFunction(const AbstractMetaClassCPtr &c); static void writeHashFunction(TextStream &s, const GeneratorContext &context); /// Write default implementations for sequence protocol void writeDefaultSequenceMethods(TextStream &s, const GeneratorContext &context) const; /// Helper function for writeStdListWrapperMethods. static void writeIndexError(TextStream &s, const QString &errorMsg, ErrorReturn errorReturn); static QString writeReprFunctionHeader(TextStream &s, const GeneratorContext &context); static QString writeReprFunction(TextStream &s, const GeneratorContext &context, uint indirections); static QString writeSmartPointerReprFunction(TextStream &s, const GeneratorContext &context); static QString writeSmartPointerDirFunction(TextStream &s, TextStream &definitionStream, TextStream &signatureStream, const GeneratorContext &context); static void writeReprFunctionFooter(TextStream &s); static void writePyMethodDefs(TextStream &s, const QString &className, const QString &methodsDefinitions); void writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips, TypeSystem::CodeSnipPosition position, TypeSystem::Language language) const; static bool hasBoolCast(const AbstractMetaClassCPtr &metaClass) { return boolCast(metaClass).has_value(); } std::optional findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer, const TypeEntryCPtr &pointee) const; void clearTpFuncs(); static QString chopType(QString s); QHash m_tpFuncs; QHash m_nbFuncs; }; Q_DECLARE_OPERATORS_FOR_FLAGS(CppGenerator::CppSelfDefinitionFlags) TextStream &operator<<(TextStream &s, CppGenerator::ErrorReturn r); #endif // CPPGENERATOR_H