diff options
author | Alexandru Croitor <alexandru.croitor@qt.io> | 2017-01-12 13:05:56 +0100 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2017-03-17 15:34:50 +0000 |
commit | 4d76c6e2c9870ce3928425682e7f091396592206 (patch) | |
tree | 1ce3c7d28b44653859fa651abb711bd5476f58a1 /generator | |
parent | 2ab4062e9d07a821e4d205dde7dead85e4c69161 (diff) |
Implement partial QSharedPointer support
This change introduces a new XML tag called smart-pointer-type which
currently only supports implementations of C++ shared pointers.
This allows using objects pointed to by a shared pointer inside python
code.
There is one known limitation at the moment. Python shared pointer
objects are only created as a result of using C++ API with shared
pointers in the method signature (either the return type or argument
type). Thus is it is not currently possible to instantiate shared
pointer objects directly, e.g. p = ModuleName.SharedPointer() will
not work.
Task-number: PYSIDE-454
Change-Id: Iacf9fcc8613fbf9bd94e179169d78da8aac58f45
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'generator')
-rw-r--r-- | generator/generator.cpp | 175 | ||||
-rw-r--r-- | generator/generator.h | 70 | ||||
-rw-r--r-- | generator/qtdoc/qtdocgenerator.cpp | 21 | ||||
-rw-r--r-- | generator/qtdoc/qtdocgenerator.h | 5 | ||||
-rw-r--r-- | generator/shiboken2/cppgenerator.cpp | 582 | ||||
-rw-r--r-- | generator/shiboken2/cppgenerator.h | 84 | ||||
-rw-r--r-- | generator/shiboken2/headergenerator.cpp | 66 | ||||
-rw-r--r-- | generator/shiboken2/headergenerator.h | 6 | ||||
-rw-r--r-- | generator/shiboken2/overloaddata.cpp | 2 | ||||
-rw-r--r-- | generator/shiboken2/shibokengenerator.cpp | 35 | ||||
-rw-r--r-- | generator/shiboken2/shibokengenerator.h | 7 |
11 files changed, 812 insertions, 241 deletions
diff --git a/generator/generator.cpp b/generator/generator.cpp index 772ab43..e4d27c0 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp @@ -47,14 +47,19 @@ struct Generator::GeneratorPrivate { QString packageName; int numGenerated; QStringList instantiatedContainersNames; - QList<const AbstractMetaType*> instantiatedContainers; + QStringList instantiatedSmartPointerNames; + QList<const AbstractMetaType *> instantiatedContainers; + QList<const AbstractMetaType *> instantiatedSmartPointers; + }; Generator::Generator() : m_d(new GeneratorPrivate) { m_d->numGenerated = 0; - m_d->instantiatedContainers = QList<const AbstractMetaType*>(); + m_d->instantiatedContainers = QList<const AbstractMetaType *>(); + m_d->instantiatedSmartPointers = QList<const AbstractMetaType *>(); m_d->instantiatedContainersNames = QStringList(); + m_d->instantiatedSmartPointerNames = QStringList(); } Generator::~Generator() @@ -82,16 +87,17 @@ bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QStrin else qCWarning(lcShiboken) << "Couldn't find the package name!!"; - collectInstantiatedContainers(); + collectInstantiatedContainersAndSmartPointers(); return doSetup(args); } QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type) { - if (!type->typeEntry()->isContainer()) - return type->cppSignature(); - QString typeName = type->cppSignature(); + const QString signature = type->cppSignature(); + if (!type->typeEntry()->isContainer() && !type->typeEntry()->isSmartPointer()) + return signature; + QString typeName = signature; if (type->isConstant()) typeName.remove(0, sizeof("const ") / sizeof(char) - 1); switch (type->referenceType()) { @@ -109,18 +115,21 @@ QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type) return typeName; } -void Generator::addInstantiatedContainers(const AbstractMetaType *type, const QString &context) +void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type, + const QString &context) { if (!type) return; foreach (const AbstractMetaType* t, type->instantiations()) - addInstantiatedContainers(t, context); - if (!type->typeEntry()->isContainer()) + addInstantiatedContainersAndSmartPointers(t, context); + if (!type->typeEntry()->isContainer() && !type->typeEntry()->isSmartPointer()) return; + bool isContainer = type->typeEntry()->isContainer(); if (type->hasTemplateChildren()) { + QString piece = isContainer ? QStringLiteral("container") : QStringLiteral("smart pointer"); QString warning = - QString::fromLatin1("Skipping instantiation of container '%1' because it has template" - " arguments.").arg(type->originalTypeDescription()); + QString::fromLatin1("Skipping instantiation of %1 '%2' because it has template" + " arguments.").arg(piece).arg(type->originalTypeDescription()); if (!context.isEmpty()) warning.append(QStringLiteral(" Calling context: %1").arg(context)); @@ -129,37 +138,46 @@ void Generator::addInstantiatedContainers(const AbstractMetaType *type, const QS } QString typeName = getSimplifiedContainerTypeName(type); - if (!m_d->instantiatedContainersNames.contains(typeName)) { - m_d->instantiatedContainersNames.append(typeName); - m_d->instantiatedContainers.append(type); + if (isContainer) { + if (!m_d->instantiatedContainersNames.contains(typeName)) { + m_d->instantiatedContainersNames.append(typeName); + m_d->instantiatedContainers.append(type); + } + } else { + // Is smart pointer. + if (!m_d->instantiatedSmartPointerNames.contains(typeName)) { + m_d->instantiatedSmartPointerNames.append(typeName); + m_d->instantiatedSmartPointers.append(type); + } } + } -void Generator::collectInstantiatedContainers(const AbstractMetaFunction* func) +void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction *func) { - addInstantiatedContainers(func->type(), func->signature()); + addInstantiatedContainersAndSmartPointers(func->type(), func->signature()); foreach (const AbstractMetaArgument* arg, func->arguments()) - addInstantiatedContainers(arg->type(), func->signature()); + addInstantiatedContainersAndSmartPointers(arg->type(), func->signature()); } -void Generator::collectInstantiatedContainers(const AbstractMetaClass* metaClass) +void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass) { if (!metaClass->typeEntry()->generateCode()) return; foreach (const AbstractMetaFunction* func, metaClass->functions()) - collectInstantiatedContainers(func); + collectInstantiatedContainersAndSmartPointers(func); foreach (const AbstractMetaField* field, metaClass->fields()) - addInstantiatedContainers(field->type(), field->name()); + addInstantiatedContainersAndSmartPointers(field->type(), field->name()); foreach (AbstractMetaClass* innerClass, metaClass->innerClasses()) - collectInstantiatedContainers(innerClass); + collectInstantiatedContainersAndSmartPointers(innerClass); } -void Generator::collectInstantiatedContainers() +void Generator::collectInstantiatedContainersAndSmartPointers() { foreach (const AbstractMetaFunction* func, globalFunctions()) - collectInstantiatedContainers(func); + collectInstantiatedContainersAndSmartPointers(func); foreach (const AbstractMetaClass* metaClass, classes()) - collectInstantiatedContainers(metaClass); + collectInstantiatedContainersAndSmartPointers(metaClass); } QList<const AbstractMetaType*> Generator::instantiatedContainers() const @@ -167,6 +185,11 @@ QList<const AbstractMetaType*> Generator::instantiatedContainers() const return m_d->instantiatedContainers; } +QList<const AbstractMetaType*> Generator::instantiatedSmartPointers() const +{ + return m_d->instantiatedSmartPointers; +} + QMap< QString, QString > Generator::options() const { return QMap<QString, QString>(); @@ -278,37 +301,68 @@ inline void touchFile(const QString &filePath) toucher.close(); } -bool Generator::generate() +bool Generator::generateFileForContext(GeneratorContext &context) { - foreach (AbstractMetaClass *cls, m_d->apiextractor->classes()) { - if (!shouldGenerate(cls)) - continue; + AbstractMetaClass *cls = context.metaClass(); - QString fileName = fileNameForClass(cls); - if (fileName.isNull()) - continue; - if (ReportHandler::isDebug(ReportHandler::SparseDebug)) - qCDebug(lcShiboken) << "generating: " << fileName; + if (!shouldGenerate(cls)) + return true; + + const QString fileName = fileNameForContext(context); + if (fileName.isEmpty()) + return true; + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) + qCDebug(lcShiboken) << "generating: " << fileName; - QString filePath = outputDirectory() + QLatin1Char('/') + subDirectoryForClass(cls) - + QLatin1Char('/') + fileName; - FileOut fileOut(filePath); - generateClass(fileOut.stream, cls); + QString filePath = outputDirectory() + QLatin1Char('/') + subDirectoryForClass(cls) + + QLatin1Char('/') + fileName; + FileOut fileOut(filePath); - FileOut::State state = fileOut.done(); - switch (state) { - case FileOut::Failure: + generateClass(fileOut.stream, context); + + FileOut::State state = fileOut.done(); + switch (state) { + case FileOut::Failure: + return false; + case FileOut::Unchanged: + // Even if contents is unchanged, the last file modification time should be updated, + // so that the build system can rely on the fact the generated file is up-to-date. + touchFile(filePath); + break; + case FileOut::Success: + break; + } + + ++m_d->numGenerated; + return true; +} + +QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType, + const AbstractMetaClass *smartPointerClass) const +{ + const AbstractMetaType *innerType = smartPointerType->getSmartPointerInnerType(); + QString fileName = smartPointerClass->qualifiedCppName().toLower(); + fileName.replace(QLatin1String("::"), QLatin1String("_")); + fileName.append(QLatin1String("_")); + fileName.append(innerType->name().toLower()); + + return fileName; +} + +bool Generator::generate() +{ + foreach (AbstractMetaClass *cls, m_d->apiextractor->classes()) { + GeneratorContext context(cls); + if (!generateFileForContext(context)) return false; - case FileOut::Unchanged: - // Even if contents is unchanged, the last file modification time should be updated, - // so that the build system can rely on the fact the generated file is up-to-date. - touchFile(filePath); - break; - case FileOut::Success: - break; - } + } - ++m_d->numGenerated; + foreach (const AbstractMetaType *type, instantiatedSmartPointers()) { + AbstractMetaClass *smartPointerClass = + AbstractMetaClass::findClass(m_d->apiextractor->smartPointers(), type->name()); + GeneratorContext context(smartPointerClass, type, true); + if (!generateFileForContext(context)) + return false; } return finishGeneration(); } @@ -770,3 +824,26 @@ QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePac { return getClassTargetFullName_(metaEnum, includePackageName); } + +QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePackageName) +{ + QString name = metaType->cppSignature(); + name.replace(QLatin1String("::"), QLatin1String("_")); + name.replace(QLatin1Char('<'), QLatin1Char('_')); + name.remove(QLatin1Char('>')); + name.remove(QLatin1Char(' ')); + if (includePackageName) { + name.prepend(QLatin1Char('.')); + name.prepend(metaType->package()); + } + return name; +} + +QString getFilteredCppSignatureString(QString signature) +{ + signature.replace(QLatin1String("::"), QLatin1String("_")); + signature.replace(QLatin1Char('<'), QLatin1Char('_')); + signature.replace(QLatin1Char('>'), QLatin1Char('_')); + signature.replace(QLatin1Char(' '), QLatin1Char('_')); + return signature; +} diff --git a/generator/generator.h b/generator/generator.h index ac78d62..386b9d5 100644 --- a/generator/generator.h +++ b/generator/generator.h @@ -60,6 +60,44 @@ void verifyDirectoryFor(const QFile &file); QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName = true); QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName = true); +QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePackageName = true); +QString getFilteredCppSignatureString(QString signature); + + +/** + * A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized + * AbstractMetaType, for which code is currently being generated. + * + * The main case is when the context contains only an AbstractMetaClass pointer, which is used + * by different methods to generate appropriate expressions, functions, type names, etc. + * + * The second case is for generation of code for smart pointers. In this case the m_metaClass member + * contains the generic template class of the smart pointer, and the m_preciseClassType member + * contains the instantiated template type, e.g. a concrete shared_ptr<int>. To + * distinguish this case, the member m_forSmartPointer is set to true. + * + * In the future the second case might be generalized for all template type instantiations. + */ +class GeneratorContext { +public: + GeneratorContext() : m_metaClass(0), m_preciseClassType(0), m_forSmartPointer(false) {} + GeneratorContext(AbstractMetaClass *metaClass, + const AbstractMetaType *preciseType = 0, + bool forSmartPointer = false) + : m_metaClass(metaClass), + m_preciseClassType(preciseType), + m_forSmartPointer(forSmartPointer) {} + + + AbstractMetaClass *metaClass() const { return m_metaClass; } + bool forSmartPointer() const { return m_forSmartPointer; } + const AbstractMetaType *preciseType() const { return m_preciseClassType; } + +private: + AbstractMetaClass *m_metaClass; + const AbstractMetaType *m_preciseClassType; + bool m_forSmartPointer; +}; /** * Base class for all generators. The default implementations does nothing, @@ -161,6 +199,14 @@ public: */ bool generate(); + + /// Generates a file for given AbstractMetaClass or AbstractMetaType (smart pointer case). + bool generateFileForContext(GeneratorContext &context); + + /// Returns the file base name for a smart pointer. + QString getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType, + const AbstractMetaClass *smartPointerClass) const; + /// Returns the number of generated items int numGenerated() const; @@ -278,14 +324,16 @@ public: QString minimalConstructor(const TypeEntry* type) const; QString minimalConstructor(const AbstractMetaType* type) const; QString minimalConstructor(const AbstractMetaClass* metaClass) const; + protected: /** - * Returns the file name used to write the binding code of an AbstractMetaClass. - * \param metaClass the AbstractMetaClass for which the file name must be - * returned + * Returns the file name used to write the binding code of an AbstractMetaClass/Type. + * \param context the GeneratorContext which contains an AbstractMetaClass or AbstractMetaType + * for which the file name must be returned * \return the file name used to write the binding code for the class */ - virtual QString fileNameForClass(const AbstractMetaClass* metaClass) const = 0; + virtual QString fileNamePrefix() const = 0; + virtual QString fileNameForContext(GeneratorContext &context) const = 0; virtual bool doSetup(const QMap<QString, QString>& args) = 0; @@ -296,7 +344,7 @@ protected: * \param s text stream to write the generated output * \param metaClass the class that should be generated */ - virtual void generateClass(QTextStream& s, const AbstractMetaClass* metaClass) = 0; + virtual void generateClass(QTextStream& s, GeneratorContext &classContext) = 0; virtual bool finishGeneration() = 0; /** @@ -311,16 +359,18 @@ protected: virtual QString subDirectoryForPackage(QString packageName = QString()) const; QList<const AbstractMetaType*> instantiatedContainers() const; + QList<const AbstractMetaType*> instantiatedSmartPointers() const; - static QString getSimplifiedContainerTypeName(const AbstractMetaType* type); - void addInstantiatedContainers(const AbstractMetaType *type, const QString &context); + static QString getSimplifiedContainerTypeName(const AbstractMetaType *type); + void addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type, + const QString &context); private: struct GeneratorPrivate; GeneratorPrivate* m_d; - void collectInstantiatedContainers(const AbstractMetaFunction* func); - void collectInstantiatedContainers(const AbstractMetaClass* metaClass); - void collectInstantiatedContainers(); + void collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction* func); + void collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass); + void collectInstantiatedContainersAndSmartPointers(); }; Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options) diff --git a/generator/qtdoc/qtdocgenerator.cpp b/generator/qtdoc/qtdocgenerator.cpp index 3e6f113..a7a1769 100644 --- a/generator/qtdoc/qtdocgenerator.cpp +++ b/generator/qtdoc/qtdocgenerator.cpp @@ -990,9 +990,21 @@ QtDocGenerator::~QtDocGenerator() delete m_docParser; } -QString QtDocGenerator::fileNameForClass(const AbstractMetaClass* cppClass) const +QString QtDocGenerator::fileNamePrefix() const { - return getClassTargetFullName(cppClass, false) + QLatin1String(".rst"); + return QLatin1String(".rst"); +} + +QString QtDocGenerator::fileNameForContext(GeneratorContext &context) const +{ + const AbstractMetaClass *metaClass = context.metaClass(); + if (!context.forSmartPointer()) { + return getClassTargetFullName(metaClass, false) + fileNamePrefix(); + } else { + const AbstractMetaType *smartPointerType = context.preciseType(); + QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass); + return fileNameBase + fileNamePrefix(); + } } void QtDocGenerator::writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaClass) @@ -1040,11 +1052,12 @@ static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaCl s << classes.join(QLatin1String(", ")) << endl << endl; } -void QtDocGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass) +void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) { + AbstractMetaClass *metaClass = classContext.metaClass(); qCDebug(lcShiboken).noquote().nospace() << "Generating Documentation for " << metaClass->fullName(); - m_packages[metaClass->package()] << fileNameForClass(metaClass); + m_packages[metaClass->package()] << fileNameForContext(classContext); m_docParser->setPackageName(metaClass->package()); m_docParser->fillDocumentation(const_cast<AbstractMetaClass*>(metaClass)); diff --git a/generator/qtdoc/qtdocgenerator.h b/generator/qtdoc/qtdocgenerator.h index ec815ad..fa8524b 100644 --- a/generator/qtdoc/qtdocgenerator.h +++ b/generator/qtdoc/qtdocgenerator.h @@ -194,8 +194,9 @@ public: } protected: - QString fileNameForClass(const AbstractMetaClass* cppClass) const; - void generateClass(QTextStream& s, const AbstractMetaClass* metaClass); + QString fileNamePrefix() const; + QString fileNameForContext(GeneratorContext &context) const; + void generateClass(QTextStream &s, GeneratorContext &classContext); bool finishGeneration(); void writeFunctionArguments(QTextStream&, const AbstractMetaFunction*, Options) const {} diff --git a/generator/shiboken2/cppgenerator.cpp b/generator/shiboken2/cppgenerator.cpp index 7ff280a..c8e919c 100644 --- a/generator/shiboken2/cppgenerator.cpp +++ b/generator/shiboken2/cppgenerator.cpp @@ -134,11 +134,23 @@ CppGenerator::CppGenerator() m_mpFuncs.insert(QLatin1String("__msetitem__"), QLatin1String("mp_ass_subscript")); } -QString CppGenerator::fileNameForClass(const AbstractMetaClass *metaClass) const +QString CppGenerator::fileNamePrefix() const { - QString result = metaClass->qualifiedCppName().toLower(); - result.replace(QLatin1String("::"), QLatin1String("_")); - return result + QLatin1String("_wrapper.cpp"); + return QLatin1String("_wrapper.cpp"); +} + +QString CppGenerator::fileNameForContext(GeneratorContext &context) const +{ + const AbstractMetaClass *metaClass = context.metaClass(); + if (!context.forSmartPointer()) { + QString fileNameBase = metaClass->qualifiedCppName().toLower(); + fileNameBase.replace(QLatin1String("::"), QLatin1String("_")); + return fileNameBase + fileNamePrefix(); + } else { + const AbstractMetaType *smartPointerType = context.preciseType(); + QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass); + return fileNameBase + fileNamePrefix(); + } } QList<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass, @@ -148,8 +160,11 @@ QList<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(con QMap<QPair<QString, int >, AbstractMetaFunctionList> results; const AbstractMetaClass::OperatorQueryOptions query(queryIn); foreach (AbstractMetaFunction* func, metaClass->operatorOverloads(query)) { - if (func->isModifiedRemoved() || func->usesRValueReferences() - || func->name() == QLatin1String("operator[]") || func->name() == QLatin1String("operator->")) { + if (func->isModifiedRemoved() + || func->usesRValueReferences() + || func->name() == QLatin1String("operator[]") + || func->name() == QLatin1String("operator->") + || func->name() == QLatin1String("operator!")) { continue; } int args; @@ -193,8 +208,9 @@ static const char includeQDebug[] = \param s the output buffer \param metaClass the pointer to metaclass information */ -void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaClass) +void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) { + AbstractMetaClass *metaClass = classContext.metaClass(); if (ReportHandler::isDebug(ReportHandler::SparseDebug)) qCDebug(lcShiboken) << "Generating wrapper implementation for " << metaClass->fullName(); @@ -231,12 +247,13 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl s << "#include \"" << getModuleHeaderFileName() << '"' << endl << endl; - QString headerfile = fileNameForClass(metaClass); + QString headerfile = fileNameForContext(classContext); headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h")); s << "#include \"" << headerfile << '"' << endl; foreach (AbstractMetaClass* innerClass, metaClass->innerClasses()) { + GeneratorContext innerClassContext(innerClass); if (shouldGenerate(innerClass)) { - QString headerfile = fileNameForClass(innerClass); + QString headerfile = fileNameForContext(innerClassContext); headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h")); s << "#include \"" << headerfile << '"' << endl; } @@ -259,18 +276,29 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated) s << "#Deprecated" << endl; - //Use class base namespace - const AbstractMetaClass *context = metaClass->enclosingClass(); - while(context) { - if (context->isNamespace() && !context->enclosingClass()) { - s << "using namespace " << context->qualifiedCppName() << ";" << endl; - break; + // 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(); } - context = context->enclosingClass(); } s << endl; + // Create string literal for smart pointer getter method. + if (classContext.forSmartPointer()) { + const SmartPointerTypeEntry *typeEntry = + static_cast<const SmartPointerTypeEntry *>(classContext.preciseType() + ->typeEntry()); + QString rawGetter = typeEntry->getter(); + s << "static const char * " SMART_POINTER_GETTER " = \"" << rawGetter << "\";"; + } + // class inject-code native/beginning if (!metaClass->typeEntry()->codeSnips().isEmpty()) { writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, metaClass); @@ -290,7 +318,7 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl if (avoidProtectedHack() && usePySideExtensions()) { s << "void " << wrapperName(metaClass) << "::pysideInitQtMetaTypes()\n{\n"; Indentation indent(INDENT); - writeInitQtMetaTypeFunctionBody(s, metaClass); + writeInitQtMetaTypeFunctionBody(s, classContext); s << "}\n\n"; } @@ -342,13 +370,46 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl if (m_sequenceProtocol.contains(rfunc->name()) || m_mappingProtocol.contains(rfunc->name())) continue; - if (rfunc->isConstructor()) - writeConstructorWrapper(s, overloads); + if (rfunc->isConstructor()) { + // @TODO: Implement constructor support for smart pointers, so that they can be + // instantiated in python code. + if (classContext.forSmartPointer()) + continue; + writeConstructorWrapper(s, overloads, classContext); + } // call operators else if (rfunc->name() == QLatin1String("operator()")) - writeMethodWrapper(s, overloads); + writeMethodWrapper(s, overloads, classContext); else if (!rfunc->isOperatorOverload()) { - writeMethodWrapper(s, overloads); + + if (classContext.forSmartPointer()) { + const SmartPointerTypeEntry *smartPointerTypeEntry = + static_cast<const SmartPointerTypeEntry *>( + classContext.preciseType()->typeEntry()); + + if (smartPointerTypeEntry->getter() == rfunc->name()) { + // Replace the return type of the raw pointer getter method with the actual + // return type. + QString innerTypeName = + classContext.preciseType()->getSmartPointerInnerType()->name(); + QString pointerToInnerTypeName = innerTypeName + QLatin1Char('*'); + // @TODO: This possibly leaks, but there are a bunch of other places where this + // is done, so this will be fixed in bulk with all the other cases, because the + // ownership of the pointers is not clear at the moment. + AbstractMetaType *pointerToInnerType = + buildAbstractMetaTypeFromString(pointerToInnerTypeName); + + AbstractMetaFunction *mutableRfunc = overloads.first(); + mutableRfunc->replaceType(pointerToInnerType); + } else if (smartPointerTypeEntry->refCountMethodName().isEmpty() + || smartPointerTypeEntry->refCountMethodName() != rfunc->name()) { + // Skip all public methods of the smart pointer except for the raw getter and + // the ref count method. + continue; + } + } + + writeMethodWrapper(s, overloads, classContext); if (OverloadData::hasStaticAndInstanceFunctions(overloads)) { QString methDefName = cpythonMethodDefinitionName(rfunc); smd << "static PyMethodDef " << methDefName << " = {" << endl; @@ -363,8 +424,8 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl QString className = cpythonTypeName(metaClass); className.remove(QRegExp(QLatin1String("_Type$"))); - if (metaClass->typeEntry()->isValue()) - writeCopyFunction(s, metaClass); + if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) + writeCopyFunction(s, classContext); // Write single method definitions s << singleMethodDefinitions; @@ -372,27 +433,33 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl // Write methods definition s << "static PyMethodDef " << className << "_methods[] = {" << endl; s << methodsDefinitions << endl; - if (metaClass->typeEntry()->isValue()) + if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) s << INDENT << "{\"__copy__\", (PyCFunction)" << className << "___copy__" << ", METH_NOARGS}," << endl; s << INDENT << "{0} // Sentinel" << endl; s << "};" << endl << endl; // Write tp_getattro function - if (usePySideExtensions() && metaClass->qualifiedCppName() == QLatin1String("QObject")) { - writeGetattroFunction(s, metaClass); + if ((usePySideExtensions() && metaClass->qualifiedCppName() == QLatin1String("QObject"))) { + writeGetattroFunction(s, classContext); s << endl; - writeSetattroFunction(s, metaClass); - s << endl; - } else if (classNeedsGetattroFunction(metaClass)) { - writeGetattroFunction(s, metaClass); + writeSetattroFunction(s, classContext); s << endl; + } else { + if (classNeedsGetattroFunction(metaClass)) { + writeGetattroFunction(s, classContext); + s << endl; + } + if (classNeedsSetattroFunction(metaClass)) { + writeSetattroFunction(s, classContext); + s << endl; + } } if (hasBoolCast(metaClass)) { ErrorCode errorCode(-1); s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* " PYTHON_SELF_VAR ")" << endl; s << '{' << endl; - writeCppSelfDefinition(s, metaClass); + writeCppSelfDefinition(s, classContext); s << INDENT << "int result;" << endl; s << INDENT << BEGIN_ALLOW_THREADS << endl; s << INDENT << "result = !" CPP_SELF_VAR "->isNull();" << endl; @@ -401,7 +468,7 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl s << '}' << endl << endl; } - if (supportsNumberProtocol(metaClass)) { + if (supportsNumberProtocol(metaClass) && !metaClass->typeEntry()->isSmartPointer()) { QList<AbstractMetaFunctionList> opOverloads = filterGroupedOperatorFunctions( metaClass, AbstractMetaClass::ArithmeticOp @@ -420,30 +487,30 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl if (overloads.isEmpty()) continue; - writeMethodWrapper(s, overloads); + writeMethodWrapper(s, overloads, classContext); } } if (supportsSequenceProtocol(metaClass)) { - writeSequenceMethods(s, metaClass); + writeSequenceMethods(s, metaClass, classContext); } if (supportsMappingProtocol(metaClass)) { - writeMappingMethods(s, metaClass); + writeMappingMethods(s, metaClass, classContext); } if (metaClass->hasComparisonOperatorOverload()) { s << "// Rich comparison" << endl; - writeRichCompareFunction(s, metaClass); + writeRichCompareFunction(s, classContext); } - if (shouldGenerateGetSetList(metaClass)) { + if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer()) { foreach (const AbstractMetaField* metaField, metaClass->fields()) { if (metaField->isStatic()) continue; - writeGetterFunction(s, metaField); + writeGetterFunction(s, metaField, classContext); if (!metaField->type()->isConstant()) - writeSetterFunction(s, metaField); + writeSetterFunction(s, metaField, classContext); s << endl; } @@ -466,13 +533,13 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl s << "} // extern \"C\"" << endl << endl; if (!metaClass->typeEntry()->hashFunction().isEmpty()) - writeHashFunction(s, metaClass); + writeHashFunction(s, classContext); // Write tp_traverse and tp_clear functions. writeTpTraverseFunction(s, metaClass); writeTpClearFunction(s, metaClass); - writeClassDefinition(s, metaClass); + writeClassDefinition(s, metaClass, classContext); s << endl; if (metaClass->isPolymorphic() && metaClass->baseClass()) @@ -492,8 +559,8 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl } s << endl; - writeConverterFunctions(s, metaClass); - writeClassRegister(s, metaClass); + writeConverterFunctions(s, metaClass, classContext); + writeClassRegister(s, metaClass, classContext); // class inject-code native/end if (!metaClass->typeEntry()->codeSnips().isEmpty()) { @@ -997,7 +1064,8 @@ void CppGenerator::writeEnumConverterFunctions(QTextStream& s, const TypeEntry* QLatin1String("PyNumber_Check(pyIn)")); } -void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass, + GeneratorContext &classContext) { s << "// Type conversion functions." << endl << endl; @@ -1012,7 +1080,12 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla if (metaClass->isNamespace()) return; - QString typeName = getFullTypeName(metaClass); + QString typeName; + if (!classContext.forSmartPointer()) + typeName = getFullTypeName(metaClass); + else + typeName = getFullTypeName(classContext.preciseType()); + QString cpythonType = cpythonTypeName(metaClass); // Returns the C++ pointer of the Python wrapper. @@ -1053,29 +1126,52 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); // The conversions for an Object Type end here. - if (!metaClass->typeEntry()->isValue()) { + if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer()) { s << endl; return; } // Always copies C++ value (not pointer, and not reference) to a new Python wrapper. s << endl << "// C++ to Python copy conversion." << endl; - targetTypeName = metaClass->name(); + if (!classContext.forSmartPointer()) + targetTypeName = metaClass->name(); + else + targetTypeName = classContext.preciseType()->name(); + sourceTypeName = targetTypeName + QLatin1String("_COPY"); code.clear(); - c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << wrapperName(metaClass); + + QString computedWrapperName; + if (!classContext.forSmartPointer()) + computedWrapperName = wrapperName(metaClass); + else + computedWrapperName = wrapperName(classContext.preciseType()); + + c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << computedWrapperName; c << "(*((" << typeName << "*)cppIn)), true, true);"; writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); s << endl; // Python to C++ copy conversion. s << "// Python to C++ copy conversion." << endl; - sourceTypeName = metaClass->name(); + if (!classContext.forSmartPointer()) + sourceTypeName = metaClass->name(); + else + sourceTypeName = classContext.preciseType()->name(); + targetTypeName = QStringLiteral("%1_COPY").arg(sourceTypeName); code.clear(); + + QString pyInVariable = QLatin1String("pyIn"); + QString wrappedCPtrExpression; + if (!classContext.forSmartPointer()) + wrappedCPtrExpression = cpythonWrapperCPtr(metaClass->typeEntry(), pyInVariable); + else + wrappedCPtrExpression = cpythonWrapperCPtr(classContext.preciseType(), pyInVariable); + c << INDENT << "*((" << typeName << "*)cppOut) = *" - << cpythonWrapperCPtr(metaClass->typeEntry(), QLatin1String("pyIn")) << ';'; + << wrappedCPtrExpression << ';'; writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); // "Is convertible" function for the Python object to C++ value copy conversion. @@ -1177,7 +1273,8 @@ void CppGenerator::writeCustomConverterFunctions(QTextStream& s, const CustomCon s << endl; } -void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass, + GeneratorContext &classContext) { if (metaClass->isNamespace()) return; @@ -1192,7 +1289,7 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas s << INDENT << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl; std::swap(targetTypeName, sourceTypeName); s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName); - if (metaClass->typeEntry()->isValue()) { + if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) { s << ',' << endl; sourceTypeName = metaClass->name() + QLatin1String("_COPY"); s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName); @@ -1202,7 +1299,14 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas s << endl; - QStringList cppSignature = metaClass->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts); + QStringList cppSignature; + if (!classContext.forSmartPointer()) { + cppSignature = metaClass->qualifiedCppName().split(QLatin1String("::"), + QString::SkipEmptyParts); + } else { + cppSignature = classContext.preciseType()->cppSignature().split(QLatin1String("::"), + QString::SkipEmptyParts); + } while (!cppSignature.isEmpty()) { QString signature = cppSignature.join(QLatin1String("::")); s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "\");" << endl; @@ -1212,7 +1316,14 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas } s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::"; - s << metaClass->qualifiedCppName() << ").name());" << endl; + QString qualifiedCppNameInvocation; + if (!classContext.forSmartPointer()) + qualifiedCppNameInvocation = metaClass->qualifiedCppName(); + else + qualifiedCppNameInvocation = classContext.preciseType()->cppSignature(); + + s << qualifiedCppNameInvocation << ").name());" << endl; + if (shouldGenerateCppWrapper(metaClass)) { s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::"; s << wrapperName(metaClass) << ").name());" << endl; @@ -1220,7 +1331,7 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas s << endl; - if (!metaClass->typeEntry()->isValue()) + if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer()) return; // Python to C++ copy (value, not pointer neither reference) conversion. @@ -1297,7 +1408,8 @@ void CppGenerator::writeContainerConverterFunctions(QTextStream& s, const Abstra writePythonToCppConversionFunctions(s, containerType); } -void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& overloadData) +void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData, + GeneratorContext &context) { const AbstractMetaFunction* rfunc = overloadData.referenceFunction(); const AbstractMetaClass* ownerClass = rfunc->ownerClass(); @@ -1312,13 +1424,24 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& over if (!ownerClass->hasPrivateDestructor()) { s << INDENT; s << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ") && !Shiboken::ObjectType::canCallConstructor(" PYTHON_SELF_VAR "->ob_type, Shiboken::SbkType< ::"; - s << ownerClass->qualifiedCppName() << " >()))" << endl; + QString qualifiedCppName; + if (!context.forSmartPointer()) + qualifiedCppName = ownerClass->qualifiedCppName(); + else + qualifiedCppName = context.preciseType()->cppSignature(); + + s << qualifiedCppName << " >()))" << endl; Indentation indent(INDENT); s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl; } // Declare pointer for the underlying C++ object. s << INDENT << "::"; - s << (shouldGenerateCppWrapper(ownerClass) ? wrapperName(ownerClass) : ownerClass->qualifiedCppName()); + if (!context.forSmartPointer()) { + s << (shouldGenerateCppWrapper(ownerClass) ? wrapperName(ownerClass) + : ownerClass->qualifiedCppName()); + } else { + s << context.preciseType()->cppSignature(); + } s << "* cptr = 0;" << endl; initPythonArguments = maxArgs > 0; @@ -1327,7 +1450,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& over } else { if (rfunc->implementingClass() && (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) { - writeCppSelfDefinition(s, rfunc, overloadData.hasStaticFunction()); + writeCppSelfDefinition(s, rfunc, context, overloadData.hasStaticFunction()); } if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType()) s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl; @@ -1357,7 +1480,8 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& over } } -void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFunctionList overloads) +void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, + GeneratorContext &classContext) { ErrorCode errorCode(-1); OverloadData overloadData(overloads, this); @@ -1424,14 +1548,14 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun s << INDENT << '}' << endl << endl; } - writeMethodWrapperPreamble(s, overloadData); + writeMethodWrapperPreamble(s, overloadData, classContext); s << endl; if (overloadData.maxArgs() > 0) writeOverloadedFunctionDecisor(s, overloadData); - writeFunctionCalls(s, overloadData); + writeFunctionCalls(s, overloadData, classContext); s << endl; s << INDENT << "if (PyErr_Occurred() || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< ::" << metaClass->qualifiedCppName() << " >(), cptr)) {" << endl; @@ -1505,7 +1629,8 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun s << '}' << endl << endl; } -void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunctionList overloads) +void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, + GeneratorContext &classContext) { OverloadData overloadData(overloads, this); const AbstractMetaFunction* rfunc = overloadData.referenceFunction(); @@ -1521,7 +1646,7 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction } s << ')' << endl << '{' << endl; - writeMethodWrapperPreamble(s, overloadData); + writeMethodWrapperPreamble(s, overloadData, classContext); s << endl; @@ -1579,7 +1704,7 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction if (maxArgs > 0) writeOverloadedFunctionDecisor(s, overloadData); - writeFunctionCalls(s, overloadData); + writeFunctionCalls(s, overloadData, classContext); if (callExtendedReverseOperator) s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl; @@ -1697,26 +1822,42 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl s << endl; } -void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaClass* metaClass, bool hasStaticOverload, bool cppSelfAsReference) +void CppGenerator::writeCppSelfDefinition(QTextStream &s, + GeneratorContext &context, + bool hasStaticOverload, + bool cppSelfAsReference) { + const AbstractMetaClass *metaClass = context.metaClass(); bool useWrapperClass = avoidProtectedHack() && metaClass->hasProtectedMembers(); - QString className = useWrapperClass - ? wrapperName(metaClass) - : (QLatin1String("::") + metaClass->qualifiedCppName()); + QString className; + if (!context.forSmartPointer()) { + className = useWrapperClass + ? wrapperName(metaClass) + : (QLatin1String("::") + metaClass->qualifiedCppName()); + } else { + className = context.preciseType()->cppSignature(); + } QString cppSelfAttribution; + QString pythonSelfVar = QLatin1String(PYTHON_SELF_VAR); + QString cpythonWrapperCPtrResult; + if (!context.forSmartPointer()) + cpythonWrapperCPtrResult = cpythonWrapperCPtr(metaClass, pythonSelfVar); + else + cpythonWrapperCPtrResult = cpythonWrapperCPtr(context.preciseType(), pythonSelfVar); + if (cppSelfAsReference) { QString cast = useWrapperClass ? QString::fromLatin1("(%1*)").arg(className) : QString(); cppSelfAttribution = QString::fromLatin1("%1& %2 = *(%3%4)") .arg(className, QLatin1String(CPP_SELF_VAR), cast, - cpythonWrapperCPtr(metaClass, QLatin1String(PYTHON_SELF_VAR))); + cpythonWrapperCPtrResult); } else { s << INDENT << className << "* " CPP_SELF_VAR " = 0;" << endl; writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR)); cppSelfAttribution = QString::fromLatin1("%1 = %2%3") .arg(QLatin1String(CPP_SELF_VAR), (useWrapperClass ? QString::fromLatin1("(%1*)").arg(className) : QString()), - cpythonWrapperCPtr(metaClass, QLatin1String(PYTHON_SELF_VAR))); + cpythonWrapperCPtrResult); } // Checks if the underlying C++ object is valid. @@ -1735,7 +1876,10 @@ void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaClas s << INDENT << cppSelfAttribution << ';' << endl; } -void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunction* func, bool hasStaticOverload) +void CppGenerator::writeCppSelfDefinition(QTextStream &s, + const AbstractMetaFunction *func, + GeneratorContext &context, + bool hasStaticOverload) { if (!func->ownerClass() || func->isConstructor()) return; @@ -1755,7 +1899,7 @@ void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunc s << INDENT << "std::swap(" PYTHON_SELF_VAR ", " PYTHON_ARG ");" << endl; } - writeCppSelfDefinition(s, func->ownerClass(), hasStaticOverload); + writeCppSelfDefinition(s, context, hasStaticOverload); } void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData) @@ -2056,7 +2200,7 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s, s << "(long)" << defaultValue; } else if (isUserPrimitive(type) || typeEntry->isEnum() || typeEntry->isFlags()) { writeMinimalConstructorExpression(s, typeEntry, defaultValue); - } else if (!type->isContainer()) { + } else if (!type->isContainer() && !type->isSmartPointer()) { writeMinimalConstructorExpression(s, type, defaultValue); } } @@ -2326,7 +2470,8 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const Ov s << endl; } -void CppGenerator::writeFunctionCalls(QTextStream& s, const OverloadData& overloadData) +void CppGenerator::writeFunctionCalls(QTextStream &s, const OverloadData &overloadData, + GeneratorContext &context) { QList<const AbstractMetaFunction*> overloads = overloadData.overloadsWithoutRepetition(); s << INDENT << "// Call function/method" << endl; @@ -2334,7 +2479,7 @@ void CppGenerator::writeFunctionCalls(QTextStream& s, const OverloadData& overlo { Indentation indent(INDENT); if (overloads.count() == 1) { - writeSingleFunctionCall(s, overloadData, overloads.first()); + writeSingleFunctionCall(s, overloadData, overloads.first(), context); } else { for (int i = 0; i < overloads.count(); i++) { const AbstractMetaFunction* func = overloads.at(i); @@ -2342,7 +2487,7 @@ void CppGenerator::writeFunctionCalls(QTextStream& s, const OverloadData& overlo s << INDENT << '{' << endl; { Indentation indent(INDENT); - writeSingleFunctionCall(s, overloadData, func); + writeSingleFunctionCall(s, overloadData, func, context); s << INDENT << "break;" << endl; } s << INDENT << '}' << endl; @@ -2352,7 +2497,10 @@ void CppGenerator::writeFunctionCalls(QTextStream& s, const OverloadData& overlo s << INDENT << '}' << endl; } -void CppGenerator::writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func) +void CppGenerator::writeSingleFunctionCall(QTextStream &s, + const OverloadData &overloadData, + const AbstractMetaFunction *func, + GeneratorContext &context) { if (func->isDeprecated()) { s << INDENT << "Shiboken::warning(PyExc_DeprecationWarning, 1, \"Function: '" @@ -2413,7 +2561,7 @@ void CppGenerator::writeSingleFunctionCall(QTextStream& s, const OverloadData& o s << INDENT << "if (!PyErr_Occurred()) {" << endl; { Indentation indentation(INDENT); - writeMethodCall(s, func, func->arguments().size() - numRemovedArgs); + writeMethodCall(s, func, context, func->arguments().size() - numRemovedArgs); if (!func->isConstructor()) writeNoneReturn(s, func, overloadData.hasNonVoidReturnType()); } @@ -2772,7 +2920,8 @@ QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, in return pyArgName; } -void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* func, int maxArgs) +void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *func, + GeneratorContext &context, int maxArgs) { s << INDENT << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << endl; if (func->isConstructor()) { @@ -2946,10 +3095,16 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f } } } else { + QString methodCallClassName; + if (context.forSmartPointer()) + methodCallClassName = context.preciseType()->cppSignature(); + else if (func->ownerClass()) + methodCallClassName = func->ownerClass()->qualifiedCppName(); + if (func->ownerClass()) { if (!avoidProtectedHack() || !func->isProtected()) { if (func->isStatic()) { - mc << "::" << func->ownerClass()->qualifiedCppName() << "::"; + mc << "::" << methodCallClassName << "::"; } else { if (func->isConstant()) { if (avoidProtectedHack()) { @@ -2957,10 +3112,10 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f if (func->ownerClass()->hasProtectedMembers()) mc << wrapperName(func->ownerClass()); else - mc << func->ownerClass()->qualifiedCppName(); + mc << methodCallClassName; mc << "*>(" CPP_SELF_VAR ")->"; } else { - mc << "const_cast<const ::" << func->ownerClass()->qualifiedCppName(); + mc << "const_cast<const ::" << methodCallClassName; mc << "*>(" CPP_SELF_VAR ")->"; } } else { @@ -2977,7 +3132,9 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f mc << "((::" << wrapperName(func->ownerClass()) << "*) " << CPP_SELF_VAR << ")->"; if (!func->isAbstract()) - mc << (func->isProtected() ? wrapperName(func->ownerClass()) : QLatin1String("::") + func->ownerClass()->qualifiedCppName()) << "::"; + mc << (func->isProtected() ? wrapperName(func->ownerClass()) : + QLatin1String("::") + + methodCallClassName) << "::"; mc << func->originalName() << "_protected"; } } else { @@ -2989,7 +3146,8 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f if (!avoidProtectedHack() || !func->isProtected()) { QString virtualCall(methodCall); QString normalCall(methodCall); - virtualCall = virtualCall.replace(QLatin1String("%CLASS_NAME"), func->ownerClass()->qualifiedCppName()); + virtualCall = virtualCall.replace(QLatin1String("%CLASS_NAME"), + methodCallClassName); normalCall.remove(QLatin1String("::%CLASS_NAME::")); methodCall.clear(); mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")) ? "; @@ -3398,7 +3556,9 @@ bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass* metaClass) return false; } -void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeClassDefinition(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &classContext) { QString tp_flags; QString tp_init; @@ -3412,7 +3572,7 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* QString baseClassName(QLatin1Char('0')); AbstractMetaFunctionList ctors; foreach (AbstractMetaFunction* f, metaClass->queryFunctions(AbstractMetaClass::Constructors)) { - if (!f->isPrivate() && !f->isModifiedRemoved()) + if (!f->isPrivate() && !f->isModifiedRemoved() && !classContext.forSmartPointer()) ctors.append(f); } @@ -3447,8 +3607,11 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* if (usePySideExtensions() && (metaClass->qualifiedCppName() == QLatin1String("QObject"))) { tp_getattro = cpythonGetattroFunctionName(metaClass); tp_setattro = cpythonSetattroFunctionName(metaClass); - } else if (classNeedsGetattroFunction(metaClass)) { - tp_getattro = cpythonGetattroFunctionName(metaClass); + } else { + if (classNeedsGetattroFunction(metaClass)) + tp_getattro = cpythonGetattroFunctionName(metaClass); + if (classNeedsSetattroFunction(metaClass)) + tp_setattro = cpythonSetattroFunctionName(metaClass); } if (metaClass->hasPrivateDestructor() || onlyPrivCtor) @@ -3461,7 +3624,7 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* tp_richcompare = cpythonBaseName(metaClass) + QLatin1String("_richcompare"); QString tp_getset = QString(QLatin1Char('0')); - if (shouldGenerateGetSetList(metaClass)) + if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer()) tp_getset = cpythonGettersSettersDefinitionName(metaClass); // search for special functions @@ -3473,7 +3636,7 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* if (m_tpFuncs[QLatin1String("__repr__")] == QLatin1String("0") && !metaClass->isQObject() && metaClass->hasToStringCapability()) { - m_tpFuncs[QLatin1String("__repr__")] = writeReprFunction(s, metaClass); + m_tpFuncs[QLatin1String("__repr__")] = writeReprFunction(s, classContext); } // class or some ancestor has multiple inheritance @@ -3512,7 +3675,13 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* s << "static SbkObjectType " << className + QLatin1String("_Type") << " = { { {" << endl; s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl; - s << INDENT << "/*tp_name*/ \"" << getClassTargetFullName(metaClass) << "\"," << endl; + QString computedClassTargetFullName; + if (!classContext.forSmartPointer()) + computedClassTargetFullName = getClassTargetFullName(metaClass); + else + computedClassTargetFullName = getClassTargetFullName(classContext.preciseType()); + + s << INDENT << "/*tp_name*/ \"" << computedClassTargetFullName << "\"," << endl; s << INDENT << "/*tp_basicsize*/ sizeof(SbkObject)," << endl; s << INDENT << "/*tp_itemsize*/ 0," << endl; s << INDENT << "/*tp_dealloc*/ " << tp_dealloc << ',' << endl; @@ -3565,7 +3734,9 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* s << "} //extern" << endl; } -void CppGenerator::writeMappingMethods(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeMappingMethods(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &context) { QMap<QString, QString> funcs; @@ -3583,7 +3754,7 @@ void CppGenerator::writeMappingMethods(QTextStream& s, const AbstractMetaClass* s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl; writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); - writeCppSelfDefinition(s, func); + writeCppSelfDefinition(s, func, context); const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg); @@ -3591,7 +3762,9 @@ void CppGenerator::writeMappingMethods(QTextStream& s, const AbstractMetaClass* } } -void CppGenerator::writeSequenceMethods(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeSequenceMethods(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &context) { QMap<QString, QString> funcs; @@ -3611,7 +3784,7 @@ void CppGenerator::writeSequenceMethods(QTextStream& s, const AbstractMetaClass* s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl; writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); - writeCppSelfDefinition(s, func); + writeCppSelfDefinition(s, func, context); const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); writeCodeSnips(s, snips,TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg); @@ -3619,7 +3792,7 @@ void CppGenerator::writeSequenceMethods(QTextStream& s, const AbstractMetaClass* } if (!injectedCode) - writeStdListWrapperMethods(s, metaClass); + writeStdListWrapperMethods(s, context); } void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass) @@ -3775,14 +3948,21 @@ void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass* s << '}' << endl; } -void CppGenerator::writeCopyFunction(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeCopyFunction(QTextStream &s, GeneratorContext &context) { + const AbstractMetaClass *metaClass = context.metaClass(); QString className = cpythonTypeName(metaClass); className.remove(QRegExp(QLatin1String("_Type$"))); s << "static PyObject* " << className << "___copy__(PyObject* " PYTHON_SELF_VAR ")" << endl; s << "{" << endl; - writeCppSelfDefinition(s, metaClass, false, true); - s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << cpythonToPythonConversionFunction(metaClass); + writeCppSelfDefinition(s, context, false, true); + QString conversionCode; + if (!context.forSmartPointer()) + conversionCode = cpythonToPythonConversionFunction(metaClass); + else + conversionCode = cpythonToPythonConversionFunction(context.preciseType()); + + s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << conversionCode; s << CPP_SELF_VAR ");" << endl; writeFunctionReturnErrorCheckSection(s); s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl; @@ -3790,13 +3970,15 @@ void CppGenerator::writeCopyFunction(QTextStream& s, const AbstractMetaClass* me s << endl; } -void CppGenerator::writeGetterFunction(QTextStream& s, const AbstractMetaField* metaField) +void CppGenerator::writeGetterFunction(QTextStream &s, + const AbstractMetaField *metaField, + GeneratorContext &context) { ErrorCode errorCode(0); s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", void*)" << endl; s << '{' << endl; - writeCppSelfDefinition(s, metaField->enclosingClass()); + writeCppSelfDefinition(s, context); AbstractMetaType* fieldType = metaField->type(); // Force use of pointer to return internal variable memory @@ -3819,7 +4001,7 @@ void CppGenerator::writeGetterFunction(QTextStream& s, const AbstractMetaField* cppField = QLatin1String("cppOut_local"); } else if (avoidProtectedHack() && metaField->isProtected()) { s << INDENT << getFullTypeNameWithoutModifiers(fieldType); - if (fieldType->isContainer() || fieldType->isFlags()) { + if (fieldType->isContainer() || fieldType->isFlags() || fieldType->isSmartPointer()) { s << '&'; cppField.prepend(QLatin1Char('*')); } else if ((!fieldType->isConstant() && !fieldType->isEnum() && !fieldType->isPrimitive()) || fieldType->indirections() == 1) { @@ -3843,13 +4025,15 @@ void CppGenerator::writeGetterFunction(QTextStream& s, const AbstractMetaField* s << '}' << endl; } -void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField* metaField) +void CppGenerator::writeSetterFunction(QTextStream &s, + const AbstractMetaField *metaField, + GeneratorContext &context) { ErrorCode errorCode(0); s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* pyIn, void*)" << endl; s << '{' << endl; - writeCppSelfDefinition(s, metaField->enclosingClass()); + writeCppSelfDefinition(s, context); s << INDENT << "if (pyIn == 0) {" << endl; { @@ -3904,13 +4088,14 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField* s << '}' << endl; } -void CppGenerator::writeRichCompareFunction(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &context) { + const AbstractMetaClass *metaClass = context.metaClass(); QString baseName = cpythonBaseName(metaClass); s << "static PyObject* "; s << baseName << "_richcompare(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ", int op)" << endl; s << '{' << endl; - writeCppSelfDefinition(s, metaClass, false, true); + writeCppSelfDefinition(s, context, false, true); writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR)); s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl; s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR << ';' << endl; @@ -4350,7 +4535,21 @@ void CppGenerator::writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnu s << '}' << endl << endl; } -void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* metaClass) +QString CppGenerator::getInitFunctionName(GeneratorContext &context) const +{ + QString initFunctionName; + if (!context.forSmartPointer()) { + initFunctionName = context.metaClass()->qualifiedCppName(); + initFunctionName.replace(QLatin1String("::"), QLatin1String("_")); + } else { + initFunctionName = getFilteredCppSignatureString(context.preciseType()->cppSignature()); + } + return initFunctionName; +} + +void CppGenerator::writeClassRegister(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &classContext) { const ComplexTypeEntry* classTypeEntry = metaClass->typeEntry(); @@ -4359,7 +4558,8 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m QString enclosingObjectVariable = hasEnclosingClass ? QLatin1String("enclosingClass") : QLatin1String("module"); QString pyTypeName = cpythonTypeName(metaClass); - s << "void init_" << metaClass->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_")); + QString initFunctionName = getInitFunctionName(classContext); + s << "void init_" << initFunctionName; s << "(PyObject* " << enclosingObjectVariable << ")" << endl; s << '{' << endl; @@ -4384,7 +4584,11 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m s << endl; } - s << INDENT << cpythonTypeNameExt(classTypeEntry); + if (!classContext.forSmartPointer()) + s << INDENT << cpythonTypeNameExt(classTypeEntry); + else + s << INDENT << cpythonTypeNameExt(classContext.preciseType()); + s << " = reinterpret_cast<PyTypeObject*>(&" << pyTypeName << ");" << endl; s << endl; @@ -4405,9 +4609,20 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m // Create type and insert it in the module or enclosing class. s << INDENT << "if (!Shiboken::ObjectType::introduceWrapperType(" << enclosingObjectVariable; - s << ", \"" << metaClass->name() << "\", \""; + QString typeName; + if (!classContext.forSmartPointer()) + typeName = metaClass->name(); + else + typeName = classContext.preciseType()->cppSignature(); + + s << ", \"" << typeName << "\", \""; + // Original name - s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : ""); + if (!classContext.forSmartPointer()) + s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : ""); + else + s << classContext.preciseType()->cppSignature(); + s << "\"," << endl; { Indentation indent(INDENT); @@ -4418,6 +4633,9 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m QString dtorClassName = metaClass->qualifiedCppName(); if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue()) dtorClassName = wrapperName(metaClass); + if (classContext.forSmartPointer()) + dtorClassName = wrapperName(classContext.preciseType()); + s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >"; } else if (metaClass->baseClass() || hasEnclosingClass) { s << ", 0"; @@ -4442,7 +4660,7 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m s << INDENT << '}' << endl << endl; // Register conversions for the type. - writeConverterRegister(s, metaClass); + writeConverterRegister(s, metaClass, classContext); s << endl; // class inject-code target/beginning @@ -4504,7 +4722,7 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m if (avoidProtectedHack() && shouldGenerateCppWrapper(metaClass)) s << INDENT << wrapperName(metaClass) << "::pysideInitQtMetaTypes();\n"; else - writeInitQtMetaTypeFunctionBody(s, metaClass); + writeInitQtMetaTypeFunctionBody(s, classContext); } if (usePySideExtensions() && metaClass->isQObject()) { @@ -4516,11 +4734,16 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m s << '}' << endl; } -void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream& s, const AbstractMetaClass* metaClass) const +void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const { + const AbstractMetaClass* metaClass = context.metaClass(); // Gets all class name variants used on different possible scopes QStringList nameVariants; - nameVariants << metaClass->name(); + if (!context.forSmartPointer()) + nameVariants << metaClass->name(); + else + nameVariants << context.preciseType()->cppSignature(); + const AbstractMetaClass* enclosingClass = metaClass->enclosingClass(); while (enclosingClass) { if (enclosingClass->typeEntry()->generateCode()) @@ -4528,7 +4751,12 @@ void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream& s, const Abstrac enclosingClass = enclosingClass->enclosingClass(); } - const QString className = metaClass->qualifiedCppName(); + QString className; + if (!context.forSmartPointer()) + className = metaClass->qualifiedCppName(); + else + className = context.preciseType()->cppSignature(); + if (!metaClass->isNamespace() && !metaClass->isAbstract()) { // Qt metatypes are registered only on their first use, so we do this now. bool canBeValue = false; @@ -4610,8 +4838,13 @@ void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMeta s << "}\n\n"; } -void CppGenerator::writeSetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass) +QString CppGenerator::writeSmartPointerGetterCast() { + return QStringLiteral("const_cast<char *>(" SMART_POINTER_GETTER ")"); +} + +void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &context) { + const AbstractMetaClass* metaClass = context.metaClass(); s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name, PyObject* value)" << endl; s << '{' << endl; if (usePySideExtensions()) { @@ -4620,6 +4853,27 @@ void CppGenerator::writeSetattroFunction(QTextStream& s, const AbstractMetaClass Indentation indent(INDENT); s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty*>(pp.object()), " PYTHON_SELF_VAR ", value);" << endl; } + + if (context.forSmartPointer()) { + s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for the corresponding C++ object held by the smart pointer." << endl; + s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", " + << writeSmartPointerGetterCast() << ", 0);" << endl; + s << INDENT << "if (rawObj) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "int hasAttribute = PyObject_HasAttr(rawObj, name);" << endl; + s << INDENT << "if (hasAttribute) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return PyObject_GenericSetAttr(rawObj, name, value);" << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "Py_DECREF(rawObj);" << endl; + } + s << INDENT << '}' << endl; + + } + s << INDENT << "return PyObject_GenericSetAttr(" PYTHON_SELF_VAR ", name, value);" << endl; s << '}' << endl; } @@ -4627,8 +4881,9 @@ void CppGenerator::writeSetattroFunction(QTextStream& s, const AbstractMetaClass static inline QString qObjectClassName() { return QStringLiteral("QObject"); } static inline QString qMetaObjectClassName() { return QStringLiteral("QMetaObject"); } -void CppGenerator::writeGetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &context) { + const AbstractMetaClass* metaClass = context.metaClass(); s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name)" << endl; s << '{' << endl; @@ -4690,7 +4945,59 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, const AbstractMetaClass } s << INDENT << '}' << endl; } - s << INDENT << "return " << getattrFunc << ';' << endl; + + if (context.forSmartPointer()) { + s << INDENT << "PyObject *tmp = " << getattrFunc << ';' << endl; + s << INDENT << "if (tmp) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return tmp;" << endl; + } + s << INDENT << "} else {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "if (!PyErr_ExceptionMatches(PyExc_AttributeError)) return NULL;" << endl; + s << INDENT << "PyErr_Clear();" << endl; + + s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for " + "the corresponding C++ object held by the smart pointer." << endl; + s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", " + << writeSmartPointerGetterCast() << ", 0);" << endl; + s << INDENT << "if (rawObj) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyObject *attribute = PyObject_GetAttr(rawObj, name);" << endl; + s << INDENT << "if (attribute) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "tmp = attribute;" << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "Py_DECREF(rawObj);" << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "if (!tmp) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "PyTypeObject *tp = Py_TYPE(self);" << endl; + s << INDENT << "PyErr_Format(PyExc_AttributeError," << endl; + s << INDENT << " \"'%.50s' object has no attribute '%.400s'\"," << endl; + s << INDENT << " tp->tp_name, PyBytes_AS_STRING(name));" << endl; + s << INDENT << "return NULL;" << endl; + } + s << INDENT << "} else {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "return tmp;" << endl; + } + s << INDENT << '}' << endl; + + } + s << INDENT << '}' << endl; + + } else { + s << INDENT << "return " << getattrFunc << ';' << endl; + } s << '}' << endl; } @@ -4724,7 +5031,9 @@ bool CppGenerator::finishGeneration() if (overloads.isEmpty()) continue; - writeMethodWrapper(s_globalFunctionImpl, overloads); + // Dummy context to satisfy the API. + GeneratorContext classContext; + writeMethodWrapper(s_globalFunctionImpl, overloads, classContext); writeMethodDefinition(s_globalFunctionDef, overloads); } @@ -4756,6 +5065,16 @@ bool CppGenerator::finishGeneration() s_classPythonDefines << INDENT << defineStr << endl; } + // Initialize smart pointer types. + foreach (const AbstractMetaType *metaType, instantiatedSmartPointers()) { + GeneratorContext context(0, metaType, true); + QString initFunctionName = getInitFunctionName(context); + s_classInitDecl << "void init_" << initFunctionName << "(PyObject* module);" << endl; + QString defineStr = QLatin1String("init_") + initFunctionName; + defineStr += QLatin1String("(module);"); + s_classPythonDefines << INDENT << defineStr << endl; + } + QString moduleFileName(outputDirectory() + QLatin1Char('/') + subDirectoryForPackage(packageName())); moduleFileName += QLatin1Char('/') + moduleName().toLower() + QLatin1String("_module_wrapper.cpp"); @@ -4968,7 +5287,7 @@ bool CppGenerator::finishGeneration() s << INDENT << "}" << endl << endl; } - int maxTypeIndex = getMaxTypeIndex(); + int maxTypeIndex = getMaxTypeIndex() + instantiatedSmartPointers().size(); if (maxTypeIndex) { s << INDENT << "// Create an array of wrapper types for the current module." << endl; s << INDENT << "static PyTypeObject* cppApi[SBK_" << moduleName() << "_IDX_COUNT];" << endl; @@ -5191,30 +5510,32 @@ void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMeta } } -void CppGenerator::writeHashFunction(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeHashFunction(QTextStream &s, GeneratorContext &context) { + const AbstractMetaClass *metaClass = context.metaClass(); s << "static Py_hash_t " << cpythonBaseName(metaClass) << "_HashFunc(PyObject* self) {" << endl; - writeCppSelfDefinition(s, metaClass); + writeCppSelfDefinition(s, context); s << INDENT << "return " << metaClass->typeEntry()->hashFunction() << '('; s << (isObjectType(metaClass) ? "" : "*") << CPP_SELF_VAR << ");" << endl; s << '}' << endl << endl; } -void CppGenerator::writeStdListWrapperMethods(QTextStream& s, const AbstractMetaClass* metaClass) +void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context) { + const AbstractMetaClass *metaClass = context.metaClass(); ErrorCode errorCode(0); // __len__ s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* " PYTHON_SELF_VAR ")" << endl; s << '{' << endl; - writeCppSelfDefinition(s, metaClass); + writeCppSelfDefinition(s, context); s << INDENT << "return " CPP_SELF_VAR "->size();" << endl; s << '}' << endl; // __getitem__ s << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i)" << endl; s << '{' << endl; - writeCppSelfDefinition(s, metaClass); + writeCppSelfDefinition(s, context); writeIndexError(s, QLatin1String("index out of bounds")); s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl; @@ -5231,7 +5552,7 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream& s, const AbstractMeta ErrorCode errorCode2(-1); s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* pyArg)" << endl; s << '{' << endl; - writeCppSelfDefinition(s, metaClass); + writeCppSelfDefinition(s, context); writeIndexError(s, QLatin1String("list assignment index out of range")); s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl; @@ -5264,14 +5585,15 @@ void CppGenerator::writeIndexError(QTextStream& s, const QString& errorMsg) s << INDENT << '}' << endl; } -QString CppGenerator::writeReprFunction(QTextStream& s, const AbstractMetaClass* metaClass) +QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &context) { + const AbstractMetaClass *metaClass = context.metaClass(); QString funcName = cpythonBaseName(metaClass) + QLatin1String("__repr__"); s << "extern \"C\"" << endl; s << '{' << endl; s << "static PyObject* " << funcName << "(PyObject* self)" << endl; s << '{' << endl; - writeCppSelfDefinition(s, metaClass); + writeCppSelfDefinition(s, context); s << INDENT << "QBuffer buffer;" << endl; s << INDENT << "buffer.open(QBuffer::ReadWrite);" << endl; s << INDENT << "QDebug dbg(&buffer);" << endl; diff --git a/generator/shiboken2/cppgenerator.h b/generator/shiboken2/cppgenerator.h index 104ab41..5dc3f5a 100644 --- a/generator/shiboken2/cppgenerator.h +++ b/generator/shiboken2/cppgenerator.h @@ -39,10 +39,11 @@ class CppGenerator : public ShibokenGenerator public: CppGenerator(); protected: - QString fileNameForClass(const AbstractMetaClass* metaClass) const; + QString fileNamePrefix() const; + QString fileNameForContext(GeneratorContext &context) const; QList<AbstractMetaFunctionList> filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass, uint query); - void generateClass(QTextStream& s, const AbstractMetaClass* metaClass); + void generateClass(QTextStream& s, GeneratorContext &classContext); bool finishGeneration(); private: @@ -57,21 +58,31 @@ private: void writeEnumConverterFunctions(QTextStream& s, const TypeEntry* enumType); void writeEnumConverterFunctions(QTextStream& s, const AbstractMetaEnum* metaEnum); - void writeConverterFunctions(QTextStream& s, const AbstractMetaClass* metaClass); + void writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass, + GeneratorContext &classContext); void writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion); - void writeConverterRegister(QTextStream& s, const AbstractMetaClass* metaClass); + void writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass, + GeneratorContext &classContext); void writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar); void writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar); void writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType); - void writeMethodWrapperPreamble(QTextStream& s, OverloadData& overloadData); - void writeConstructorWrapper(QTextStream& s, const AbstractMetaFunctionList overloads); + void writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData, + GeneratorContext &context); + void writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, GeneratorContext &classContext); void writeDestructorWrapper(QTextStream& s, const AbstractMetaClass* metaClass); - void writeMethodWrapper(QTextStream& s, const AbstractMetaFunctionList overloads); + void writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, + GeneratorContext &classContext); void writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData); - void writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunction* func, bool hasStaticOverload = false); - void writeCppSelfDefinition(QTextStream& s, const AbstractMetaClass* metaClass, bool hasStaticOverload = false, bool cppSelfAsReference = false); + void writeCppSelfDefinition(QTextStream &s, + const AbstractMetaFunction *func, + GeneratorContext &context, + bool hasStaticOverload = false); + void writeCppSelfDefinition(QTextStream &s, + GeneratorContext &context, + bool hasStaticOverload = false, + bool cppSelfAsReference = false); void writeErrorSection(QTextStream& s, OverloadData& overloadData); void writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue = true); @@ -84,8 +95,9 @@ private: void writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass); - void writeSetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass); - void writeGetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass); + void writeSetattroFunction(QTextStream &s, GeneratorContext &context); + void writeGetattroFunction(QTextStream &s, GeneratorContext &context); + QString writeSmartPointerGetterCast(); /** * Writes Python to C++ conversions for arguments on Python wrappers. @@ -152,10 +164,15 @@ private: void writeOverloadedFunctionDecisorEngine(QTextStream& s, const OverloadData* parentOverloadData); /// Writes calls to all the possible method/function overloads. - void writeFunctionCalls(QTextStream& s, const OverloadData& overloadData); + void writeFunctionCalls(QTextStream &s, + const OverloadData &overloadData, + GeneratorContext &context); /// Writes the call to a single function usually from a collection of overloads. - void writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func); + void writeSingleFunctionCall(QTextStream &s, + const OverloadData &overloadData, + const AbstractMetaFunction *func, + GeneratorContext &context); /// Returns the name of a C++ to Python conversion function. static QString cppToPythonFunctionName(const QString& sourceTypeName, QString targetTypeName = QString()); @@ -207,32 +224,47 @@ private: /// 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 writeMethodCall(QTextStream &s, const AbstractMetaFunction *func, + GeneratorContext &context, int maxArgs = 0); - void writeClassRegister(QTextStream& s, const AbstractMetaClass* metaClass); - void writeClassDefinition(QTextStream& s, const AbstractMetaClass* metaClass); + QString getInitFunctionName(GeneratorContext &context) const; + + void writeClassRegister(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &classContext); + void writeClassDefinition(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &classContext); 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); + void writeSequenceMethods(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &context); void writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass); /// Writes the PyMappingMethods structure for types that supports the python mapping protocol. void writeTypeAsMappingDefinition(QTextStream& s, const AbstractMetaClass* metaClass); - void writeMappingMethods(QTextStream& s, const AbstractMetaClass* metaClass); + void writeMappingMethods(QTextStream &s, + const AbstractMetaClass *metaClass, + GeneratorContext &context); void writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass); void writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass); void writeTpClearFunction(QTextStream& s, const AbstractMetaClass* metaClass); - void writeCopyFunction(QTextStream& s, const AbstractMetaClass *metaClass); + void writeCopyFunction(QTextStream &s, GeneratorContext &context); - void writeGetterFunction(QTextStream& s, const AbstractMetaField* metaField); - void writeSetterFunction(QTextStream& s, const AbstractMetaField* metaField); + void writeGetterFunction(QTextStream &s, + const AbstractMetaField *metaField, + GeneratorContext &context); + void writeSetterFunction(QTextStream &s, + const AbstractMetaField *metaField, + GeneratorContext &context); - void writeRichCompareFunction(QTextStream& s, const AbstractMetaClass* metaClass); + void writeRichCompareFunction(QTextStream &s, GeneratorContext &context); void writeToPythonFunction(QTextStream& s, const AbstractMetaClass* metaClass); void writeEnumsInitialization(QTextStream& s, AbstractMetaEnumList& enums); @@ -263,7 +295,7 @@ private: 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 = QLatin1String(PYTHON_SELF_VAR)); - void writeInitQtMetaTypeFunctionBody(QTextStream& s, const AbstractMetaClass* metaClass) const; + void writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const; /** * Returns the multiple inheritance initializer function for the given class. @@ -288,14 +320,14 @@ private: /// 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 writeHashFunction(QTextStream &s, GeneratorContext &context); /// Write default implementations for sequence protocol - void writeStdListWrapperMethods(QTextStream& s, const AbstractMetaClass* metaClass); + void writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context); /// Helper function for writeStdListWrapperMethods. void writeIndexError(QTextStream& s, const QString& errorMsg); - QString writeReprFunction(QTextStream& s, const AbstractMetaClass* metaClass); + QString writeReprFunction(QTextStream &s, GeneratorContext &context); bool hasBoolCast(const AbstractMetaClass* metaClass) const; diff --git a/generator/shiboken2/headergenerator.cpp b/generator/shiboken2/headergenerator.cpp index 950e938..ea308f5 100644 --- a/generator/shiboken2/headergenerator.cpp +++ b/generator/shiboken2/headergenerator.cpp @@ -38,11 +38,23 @@ #include <QtCore/QRegExp> #include <QtCore/QDebug> -QString HeaderGenerator::fileNameForClass(const AbstractMetaClass* metaClass) const +QString HeaderGenerator::fileNamePrefix() const { - QString result = metaClass->qualifiedCppName().toLower(); - result.replace(QLatin1String("::"), QLatin1String("_")); - return result + QLatin1String("_wrapper.h"); + return QLatin1String("_wrapper.h"); +} + +QString HeaderGenerator::fileNameForContext(GeneratorContext &context) const +{ + const AbstractMetaClass *metaClass = context.metaClass(); + if (!context.forSmartPointer()) { + QString fileNameBase = metaClass->qualifiedCppName().toLower(); + fileNameBase.replace(QLatin1String("::"), QLatin1String("_")); + return fileNameBase + fileNamePrefix(); + } else { + const AbstractMetaType *smartPointerType = context.preciseType(); + QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass); + return fileNameBase + fileNamePrefix(); + } } void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const @@ -78,8 +90,9 @@ void HeaderGenerator::writeProtectedFieldAccessors(QTextStream& s, const Abstrac << " { " << fieldName << " = value; }" << endl; } -void HeaderGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass) +void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) { + AbstractMetaClass *metaClass = classContext.metaClass(); if (ReportHandler::isDebug(ReportHandler::SparseDebug)) qCDebug(lcShiboken) << "Generating header for " << metaClass->fullName(); m_inheritedOverloads.clear(); @@ -88,8 +101,13 @@ void HeaderGenerator::generateClass(QTextStream& s, const AbstractMetaClass* met // write license comment s << licenseComment(); - QString wrapperName = HeaderGenerator::wrapperName(metaClass); - QString headerGuard = wrapperName.replace(QLatin1String("::"), QLatin1String("_")).toUpper(); + QString wrapperName; + if (!classContext.forSmartPointer()) { + wrapperName = HeaderGenerator::wrapperName(metaClass); + } else { + wrapperName = HeaderGenerator::wrapperName(classContext.preciseType()); + } + QString headerGuard = getFilteredCppSignatureString(wrapperName).toUpper(); // Header s << "#ifndef SBK_" << headerGuard << "_H" << endl; @@ -297,17 +315,35 @@ bool HeaderGenerator::finishGeneration() writeTypeIndexDefine(macrosStream, metaClass); lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass); } + foreach (const AbstractMetaEnum* metaEnum, globalEnums) writeTypeIndexDefineLine(macrosStream, metaEnum->typeEntry()); + + // Write the smart pointer define indexes. + int smartPointerCountIndex = getMaxTypeIndex(); + int smartPointerCount = 0; + foreach (const AbstractMetaType *metaType, instantiatedSmartPointers()) { + QString variableName = getTypeIndexVariableName(metaType); + macrosStream << "#define "; + macrosStream.setFieldWidth(60); + macrosStream << variableName; + macrosStream.setFieldWidth(0); + macrosStream << ' ' << smartPointerCountIndex << " // " << metaType->cppSignature() + << endl; + ++smartPointerCountIndex; + ++smartPointerCount; + } + + macrosStream << "#define "; macrosStream.setFieldWidth(60); macrosStream << QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT"); macrosStream.setFieldWidth(0); - macrosStream << ' ' << getMaxTypeIndex() << endl << endl; + macrosStream << ' ' << getMaxTypeIndex() + smartPointerCount << endl << endl; macrosStream << "// This variable stores all Python types exported by this module." << endl; macrosStream << "extern PyTypeObject** " << cppApiVariableName() << ';' << endl << endl; macrosStream << "// This variable stores all type converters exported by this module." << endl; - macrosStream << "extern SbkConverter** " << convertersVariableName() << ';' << endl << endl;; + macrosStream << "extern SbkConverter** " << convertersVariableName() << ';' << endl << endl; // TODO-CONVERTER ------------------------------------------------------------------------------ // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex(). @@ -375,6 +411,12 @@ bool HeaderGenerator::finishGeneration() writeSbkTypeFunction(typeFunctions, metaClass); } + foreach (const AbstractMetaType *metaType, instantiatedSmartPointers()) { + const TypeEntry *classType = metaType->typeEntry(); + includes << classType->include(); + writeSbkTypeFunction(typeFunctions, metaType); + } + QString moduleHeaderFileName(outputDirectory() + QDir::separator() + subDirectoryForPackage(packageName()) + QDir::separator() + getModuleHeaderFileName()); @@ -480,6 +522,12 @@ void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaCla << "{ return reinterpret_cast<PyTypeObject*>(" << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n"; } +void HeaderGenerator::writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType) +{ + s << "template<> inline PyTypeObject* SbkType< ::" << metaType->cppSignature() << " >() " + << "{ return reinterpret_cast<PyTypeObject*>(" << cpythonTypeNameExt(metaType) << "); }\n"; +} + void HeaderGenerator::writeInheritedOverloads(QTextStream& s) { foreach (const AbstractMetaFunction* func, m_inheritedOverloads) { diff --git a/generator/shiboken2/headergenerator.h b/generator/shiboken2/headergenerator.h index 3652ee4..72dcbf6 100644 --- a/generator/shiboken2/headergenerator.h +++ b/generator/shiboken2/headergenerator.h @@ -43,8 +43,9 @@ 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); + QString fileNamePrefix() const; + QString fileNameForContext(GeneratorContext &context) const; + void generateClass(QTextStream& s, GeneratorContext &classContext); bool finishGeneration(); private: @@ -53,6 +54,7 @@ private: void writeFunction(QTextStream& s, const AbstractMetaFunction* func); void writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum); void writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass); + void writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType); void writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry); void writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass); void writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum); diff --git a/generator/shiboken2/overloaddata.cpp b/generator/shiboken2/overloaddata.cpp index 6258488..8731fe9 100644 --- a/generator/shiboken2/overloaddata.cpp +++ b/generator/shiboken2/overloaddata.cpp @@ -70,7 +70,7 @@ static QString getTypeName(const OverloadData* ov) static bool typesAreEqual(const AbstractMetaType* typeA, const AbstractMetaType* typeB) { if (typeA->typeEntry() == typeB->typeEntry()) { - if (typeA->isContainer()) { + if (typeA->isContainer() || typeA->isSmartPointer()) { if (typeA->instantiations().size() != typeB->instantiations().size()) return false; diff --git a/generator/shiboken2/shibokengenerator.cpp b/generator/shiboken2/shibokengenerator.cpp index 8985891..ca98441 100644 --- a/generator/shiboken2/shibokengenerator.cpp +++ b/generator/shiboken2/shibokengenerator.cpp @@ -305,6 +305,11 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const } } +QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const +{ + return metaType->cppSignature(); +} + QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func) { QString funcName; @@ -549,9 +554,12 @@ QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass return cpythonWrapperCPtr(metaClass->typeEntry(), argName); } -QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType* metaType, QString argName) +QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName) { - return cpythonWrapperCPtr(metaType->typeEntry(), argName); + if (!ShibokenGenerator::isWrapperType(metaType->typeEntry())) + return QString(); + return QStringLiteral("((::%1*)Shiboken::Conversions::cppPointer(%2, (SbkObject*)%3))") + .arg(metaType->cppSignature(), cpythonTypeNameExt(metaType), argName); } QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName) @@ -631,6 +639,7 @@ QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction* func, || arg->type()->isEnum() || arg->type()->isFlags() || arg->type()->isContainer() + || arg->type()->isSmartPointer() || arg->type()->referenceType() == LValueReference) { result += QLatin1Char(objType); } else if (arg->type()->isPrimitive()) { @@ -937,16 +946,17 @@ bool ShibokenGenerator::isWrapperType(const TypeEntry* type) { if (type->isComplex()) return ShibokenGenerator::isWrapperType((const ComplexTypeEntry*)type); - return type->isObject() || type->isValue(); + return type->isObject() || type->isValue() || type->isSmartPointer(); } bool ShibokenGenerator::isWrapperType(const ComplexTypeEntry* type) { - return isObjectType(type) || type->isValue(); + return isObjectType(type) || type->isValue() || type->isSmartPointer(); } bool ShibokenGenerator::isWrapperType(const AbstractMetaType* metaType) { return isObjectType(metaType) - || metaType->typeEntry()->isValue(); + || metaType->typeEntry()->isValue() + || metaType->typeEntry()->isSmartPointer(); } bool ShibokenGenerator::isPointerToWrapperType(const AbstractMetaType* type) @@ -1227,7 +1237,7 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaT QString conversion; if (type->referenceType() == LValueReference && !(type->isValue() && type->isConstant()) && !isPointer(type)) conversion = QLatin1String("reference"); - else if (type->isValue()) + else if (type->isValue() || type->isSmartPointer()) conversion = QLatin1String("copy"); else conversion = QLatin1String("pointer"); @@ -2048,6 +2058,8 @@ bool ShibokenGenerator::classNeedsGetattroFunction(const AbstractMetaClass* meta { if (!metaClass) return false; + if (metaClass->typeEntry()->isSmartPointer()) + return true; const FunctionGroupMap &functionGroup = getFunctionGroups(metaClass); for (FunctionGroupMapIt it = functionGroup.cbegin(), end = functionGroup.cend(); it != end; ++it) { AbstractMetaFunctionList overloads; @@ -2066,6 +2078,15 @@ bool ShibokenGenerator::classNeedsGetattroFunction(const AbstractMetaClass* meta return false; } +bool ShibokenGenerator::classNeedsSetattroFunction(const AbstractMetaClass *metaClass) +{ + if (!metaClass) + return false; + if (metaClass->typeEntry()->isSmartPointer()) + return true; + return false; +} + AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass) { AbstractMetaFunctionList methods; @@ -2416,7 +2437,7 @@ void ShibokenGenerator::collectContainerTypesFromConverterMacros(const QString& if (code.at(start) != QLatin1Char('%')) { QString typeString = code.mid(start, end - start); AbstractMetaType* type = buildAbstractMetaTypeFromString(typeString); - addInstantiatedContainers(type, type->originalTypeDescription()); + addInstantiatedContainersAndSmartPointers(type, type->originalTypeDescription()); } start = end; } diff --git a/generator/shiboken2/shibokengenerator.h b/generator/shiboken2/shibokengenerator.h index 5dc2a29..327ca12 100644 --- a/generator/shiboken2/shibokengenerator.h +++ b/generator/shiboken2/shibokengenerator.h @@ -46,6 +46,7 @@ #define MIN_CTOR_ERROR_MSG "Could not find a minimal constructor for type '%1'. "\ "This will result in a compilation error." #define PYTHON_TO_CPP_VAR "pythonToCpp" +#define SMART_POINTER_GETTER "kSmartPointerGetter" #define CHECKTYPE_REGEX "%CHECKTYPE\\[([^\\[]*)\\]\\(" #define ISCONVERTIBLE_REGEX "%ISCONVERTIBLE\\[([^\\[]*)\\]\\(" @@ -245,6 +246,9 @@ public: /// Returns true if the class needs to have a getattro function. bool classNeedsGetattroFunction(const AbstractMetaClass* metaClass); + /// Returns true if the class needs to have a setattro function. + bool classNeedsSetattroFunction(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); @@ -273,6 +277,7 @@ public: const AbstractMetaClass* getProperEnclosingClassForEnum(const AbstractMetaEnum* metaEnum); QString wrapperName(const AbstractMetaClass* metaClass) const; + QString wrapperName(const AbstractMetaType *metaType) const; static QString fullPythonFunctionName(const AbstractMetaFunction* func); static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum); @@ -384,7 +389,7 @@ public: QString cpythonGetterFunctionName(const AbstractMetaField* metaField); QString cpythonSetterFunctionName(const AbstractMetaField* metaField); QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName = QLatin1String(PYTHON_SELF_VAR)); - QString cpythonWrapperCPtr(const AbstractMetaType* metaType, QString argName); + 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. |