aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6')
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp235
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.h7
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h28
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h1
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetatype.cpp1
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractor.cpp22
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractor.h3
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractorflags.h8
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractorresult.cpp13
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractorresult.h3
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp7
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangparser.h4
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp34
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/compilersupport.h2
-rw-r--r--sources/shiboken6/ApiExtractor/messages.cpp22
-rw-r--r--sources/shiboken6/ApiExtractor/messages.h7
-rw-r--r--sources/shiboken6/ApiExtractor/typedatabase.cpp3
-rw-r--r--sources/shiboken6/cmake/ShibokenHelpers.cmake17
-rw-r--r--sources/shiboken6/doc/shibokenmodule.rst5
-rw-r--r--sources/shiboken6/doc/typediscovery.rst145
-rw-r--r--sources/shiboken6/doc/typesystem.rst1
-rw-r--r--sources/shiboken6/doc/typesystem_converters.rst58
-rw-r--r--sources/shiboken6/doc/typesystem_specifying_types.rst36
-rw-r--r--sources/shiboken6/generator/generator.cpp5
-rw-r--r--sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp29
-rw-r--r--sources/shiboken6/generator/qtdoc/qtdocgenerator.h1
-rw-r--r--sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp54
-rw-r--r--sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h9
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp164
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.h12
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp22
-rw-r--r--sources/shiboken6/generator/shiboken/headergenerator.cpp7
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.cpp3
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.cpp146
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.h45
-rw-r--r--sources/shiboken6/libshiboken/pep384impl.cpp70
-rw-r--r--sources/shiboken6/libshiboken/pep384impl.h11
-rw-r--r--sources/shiboken6/libshiboken/sbkcontainer.h66
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter.cpp147
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter_p.h6
-rw-r--r--sources/shiboken6/libshiboken/sbkcpptonumpy.cpp6
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.cpp3
-rw-r--r--sources/shiboken6/libshiboken/sbkerrors.cpp47
-rw-r--r--sources/shiboken6/libshiboken/sbkerrors.h5
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.cpp21
-rw-r--r--sources/shiboken6/libshiboken/sbkmodule.cpp182
-rw-r--r--sources/shiboken6/libshiboken/sbkmodule.h12
-rw-r--r--sources/shiboken6/libshiboken/sbknumpy.cpp4
-rw-r--r--sources/shiboken6/libshiboken/sbkstring.cpp6
-rw-r--r--sources/shiboken6/libshiboken/sbkstring.h2
-rw-r--r--sources/shiboken6/libshiboken/voidptr.cpp7
-rw-r--r--sources/shiboken6/shibokenmodule/shibokenmodule.cpp4
-rw-r--r--sources/shiboken6/shibokenmodule/typesystem_shiboken.xml5
-rw-r--r--sources/shiboken6/tests/libother/othermultiplederived.h3
-rw-r--r--sources/shiboken6/tests/libsample/derived.h2
-rw-r--r--sources/shiboken6/tests/libsample/point.cpp2
-rw-r--r--sources/shiboken6/tests/libsample/point.h2
-rw-r--r--sources/shiboken6/tests/libsample/pointf.cpp2
-rw-r--r--sources/shiboken6/tests/libsample/pointf.h2
-rw-r--r--sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp40
-rw-r--r--sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h9
-rw-r--r--sources/shiboken6/tests/otherbinding/typediscovery_test.py17
-rw-r--r--sources/shiboken6/tests/qtxmltosphinx/main.cpp10
-rw-r--r--sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp6
-rw-r--r--sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h1
-rw-r--r--sources/shiboken6/tests/smartbinding/CMakeLists.txt2
-rw-r--r--sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py20
-rw-r--r--sources/shiboken6/tests/smartbinding/typesystem_smart.xml2
68 files changed, 1252 insertions, 631 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
index 89d636964..f07fb96c6 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
@@ -81,7 +81,7 @@ QTextStream &operator<<(QTextStream &str, const RejectEntry &re)
return str;
}
-static void applyCachedFunctionModifications(AbstractMetaFunction *metaFunction,
+static void applyCachedFunctionModifications(const AbstractMetaFunctionPtr &metaFunction,
const FunctionModificationList &functionMods)
{
for (const FunctionModification &mod : functionMods) {
@@ -317,7 +317,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte
return;
}
- AbstractMetaFunction *metaFunction = traverseFunction(item, baseoperandClass);
+ auto metaFunction = traverseFunction(item, baseoperandClass);
if (metaFunction == nullptr)
return;
@@ -350,7 +350,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte
}
metaFunction->setFlags(flags);
metaFunction->setAccess(Access::Public);
- AbstractMetaClass::addFunction(baseoperandClass, AbstractMetaFunctionCPtr(metaFunction));
+ AbstractMetaClass::addFunction(baseoperandClass, metaFunction);
if (!metaFunction->arguments().isEmpty()) {
const auto include = metaFunction->arguments().constFirst().type().typeEntry()->include();
baseoperandClass->typeEntry()->addArgumentInclude(include);
@@ -371,7 +371,7 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem
if (streamedClass == nullptr)
return false;
- AbstractMetaFunction *streamFunction = traverseFunction(item, streamedClass);
+ auto streamFunction = traverseFunction(item, streamedClass);
if (!streamFunction)
return false;
@@ -401,7 +401,7 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem
funcClass = streamClass;
}
- AbstractMetaClass::addFunction(funcClass, AbstractMetaFunctionCPtr(streamFunction));
+ AbstractMetaClass::addFunction(funcClass, streamFunction);
auto funcTe = funcClass->typeEntry();
if (funcClass == streamClass)
funcTe->addArgumentInclude(streamedClass->typeEntry()->include());
@@ -461,7 +461,7 @@ FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments,
+ clang::languageLevelOption(level));
}
FileModelItem result = clang::parse(arguments, addCompilerSupportArguments,
- clangFlags, builder)
+ level, clangFlags, builder)
? builder.dom() : FileModelItem();
const clang::BaseVisitor::Diagnostics &diagnostics = builder.diagnostics();
if (const auto diagnosticsCount = diagnostics.size()) {
@@ -555,17 +555,16 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom,
if (!funcEntry || !funcEntry->generateCode())
continue;
- AbstractMetaFunction *metaFunc = traverseFunction(func, nullptr);
- if (!metaFunc)
+ auto metaFuncPtr = traverseFunction(func, nullptr);
+ if (!metaFuncPtr)
continue;
- AbstractMetaFunctionCPtr metaFuncPtr(metaFunc);
- if (!funcEntry->hasSignature(metaFunc->minimalSignature()))
+ if (!funcEntry->hasSignature(metaFuncPtr->minimalSignature()))
continue;
- metaFunc->setTypeEntry(funcEntry);
- applyFunctionModifications(metaFunc);
- metaFunc->applyTypeModifications();
+ metaFuncPtr->setTypeEntry(funcEntry);
+ applyFunctionModifications(metaFuncPtr);
+ metaFuncPtr->applyTypeModifications();
setInclude(funcEntry, func->fileName());
@@ -1348,7 +1347,7 @@ void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item
}
}
-void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction)
+void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(const AbstractMetaFunctionPtr &metaFunction)
{
if (!metaFunction->isConversionOperator())
return;
@@ -1372,13 +1371,13 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF
metaFunction->setType(metaType);
}
-AbstractMetaFunctionRawPtrList
+AbstractMetaFunctionList
AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem,
AbstractMetaClass::Attributes *constructorAttributes,
const AbstractMetaClassPtr &currentClass)
{
*constructorAttributes = {};
- AbstractMetaFunctionRawPtrList result;
+ AbstractMetaFunctionList result;
const FunctionList &scopeFunctionList = scopeItem->functions();
result.reserve(scopeFunctionList.size());
const bool isNamespace = currentClass->isNamespace();
@@ -1388,7 +1387,7 @@ AbstractMetaFunctionRawPtrList
} else if (function->isSpaceshipOperator() && !function->isDeleted()) {
if (currentClass)
AbstractMetaClass::addSynthesizedComparisonOperators(currentClass);
- } else if (auto *metaFunction = traverseFunction(function, currentClass)) {
+ } else if (auto metaFunction = traverseFunction(function, currentClass)) {
result.append(metaFunction);
} else if (!function->isDeleted() && function->functionType() == CodeModel::Constructor) {
auto arguments = function->arguments();
@@ -1404,11 +1403,11 @@ void AbstractMetaBuilderPrivate::traverseFunctions(const ScopeModelItem& scopeIt
const AbstractMetaClassPtr &metaClass)
{
AbstractMetaClass::Attributes constructorAttributes;
- const AbstractMetaFunctionRawPtrList functions =
+ const AbstractMetaFunctionList functions =
classFunctionList(scopeItem, &constructorAttributes, metaClass);
metaClass->setAttributes(metaClass->attributes() | constructorAttributes);
- for (AbstractMetaFunction *metaFunction : functions) {
+ for (const auto &metaFunction : functions) {
if (metaClass->isNamespace())
metaFunction->setCppAttribute(FunctionAttribute::Static);
@@ -1461,23 +1460,20 @@ void AbstractMetaBuilderPrivate::traverseFunctions(const ScopeModelItem& scopeIt
if (!metaFunction->isDestructor()
&& !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) {
- if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction))
- qCWarning(lcShiboken, "%s", qPrintable(msgSignalOverloaded(metaClass, metaFunction)));
+ if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction.get()))
+ qCWarning(lcShiboken, "%s", qPrintable(msgSignalOverloaded(metaClass,
+ metaFunction.get())));
if (metaFunction->isConversionOperator())
fixReturnTypeOfConversionOperator(metaFunction);
- AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(metaFunction));
+ AbstractMetaClass::addFunction(metaClass, metaFunction);
applyFunctionModifications(metaFunction);
} else if (metaFunction->isDestructor()) {
metaClass->setHasPrivateDestructor(metaFunction->isPrivate());
metaClass->setHasProtectedDestructor(metaFunction->isProtected());
metaClass->setHasVirtualDestructor(metaFunction->isVirtual());
}
- if (!metaFunction->ownerClass()) {
- delete metaFunction;
- metaFunction = nullptr;
- }
}
fillAddedFunctions(metaClass);
@@ -1539,7 +1535,7 @@ QStringList AbstractMetaBuilder::definitionNames(const QString &name,
return result;
}
-void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction *func)
+void AbstractMetaBuilderPrivate::applyFunctionModifications(const AbstractMetaFunctionPtr &func)
{
AbstractMetaFunction& funcRef = *func;
for (const FunctionModification &mod : func->modifications(func->implementingClass())) {
@@ -1574,7 +1570,8 @@ bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &me
&info, &baseContainerType);
if (templ) {
setupInheritance(templ);
- inheritTemplate(metaClass, templ, info);
+ if (!inheritTemplate(metaClass, templ, info))
+ return false;
metaClass->typeEntry()->setBaseContainerType(templ->typeEntry());
return true;
}
@@ -1676,15 +1673,14 @@ static AbstractMetaFunction::FunctionType functionTypeFromName(const QString &);
bool AbstractMetaBuilderPrivate::traverseAddedGlobalFunction(const AddedFunctionPtr &addedFunc,
QString *errorMessage)
{
- AbstractMetaFunction *metaFunction =
- traverseAddedFunctionHelper(addedFunc, nullptr, errorMessage);
+ auto metaFunction = traverseAddedFunctionHelper(addedFunc, nullptr, errorMessage);
if (metaFunction == nullptr)
return false;
- m_globalFunctions << AbstractMetaFunctionCPtr(metaFunction);
+ m_globalFunctions << metaFunction;
return true;
}
-AbstractMetaFunction *
+AbstractMetaFunctionPtr
AbstractMetaBuilderPrivate::traverseAddedFunctionHelper(const AddedFunctionPtr &addedFunc,
const AbstractMetaClassPtr &metaClass /* = {} */,
QString *errorMessage)
@@ -1695,10 +1691,10 @@ AbstractMetaFunction *
msgAddedFunctionInvalidReturnType(addedFunc->name(),
addedFunc->returnType().qualifiedName(),
*errorMessage, metaClass);
- return nullptr;
+ return {};
}
- auto *metaFunction = new AbstractMetaFunction(addedFunc);
+ auto metaFunction = std::make_shared<AbstractMetaFunction>(addedFunc);
metaFunction->setType(returnType.value());
metaFunction->setFunctionType(functionTypeFromName(addedFunc->name()));
@@ -1716,8 +1712,7 @@ AbstractMetaFunction *
msgAddedFunctionInvalidArgType(addedFunc->name(),
arg.typeInfo.qualifiedName(), i + 1,
*errorMessage, metaClass);
- delete metaFunction;
- return nullptr;
+ return {};
}
type->decideUsagePattern();
@@ -1774,8 +1769,7 @@ bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunction
const AbstractMetaClassPtr &metaClass,
QString *errorMessage)
{
- AbstractMetaFunction *metaFunction =
- traverseAddedFunctionHelper(addedFunc, metaClass, errorMessage);
+ auto metaFunction = traverseAddedFunctionHelper(addedFunc, metaClass, errorMessage);
if (metaFunction == nullptr)
return false;
@@ -1795,12 +1789,13 @@ bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunction
metaFunction->setDeclaringClass(metaClass);
metaFunction->setImplementingClass(metaClass);
- AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(metaFunction));
+ AbstractMetaClass::addFunction(metaClass, metaFunction);
metaClass->setHasNonPrivateConstructor(true);
return true;
}
-void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func, const FunctionModificationList &mods)
+void AbstractMetaBuilderPrivate::fixArgumentNames(const AbstractMetaFunctionPtr &func,
+ const FunctionModificationList &mods)
{
AbstractMetaArgumentList &arguments = func->arguments();
@@ -1919,7 +1914,7 @@ static AbstractMetaFunction::FunctionType functionTypeFromName(const QString &na
// Apply the <array> modifications of the arguments
static bool applyArrayArgumentModifications(const FunctionModificationList &functionMods,
- AbstractMetaFunction *func,
+ const AbstractMetaFunctionPtr &func,
QString *errorMessage)
{
for (const FunctionModification &mod : functionMods) {
@@ -1980,13 +1975,14 @@ void AbstractMetaBuilderPrivate::rejectFunction(const FunctionModelItem &functio
m_rejectedFunctions.insert({reason, signatureWithType, sortKey, rejectReason});
}
-AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem,
- const AbstractMetaClassPtr &currentClass)
+AbstractMetaFunctionPtr
+ AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem,
+ const AbstractMetaClassPtr &currentClass)
{
const auto *tdb = TypeDatabase::instance();
if (!functionItem->templateParameters().isEmpty())
- return nullptr;
+ return {};
if (functionItem->isDeleted()) {
switch (functionItem->functionType()) {
@@ -2000,7 +1996,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
default:
break;
}
- return nullptr;
+ return {};
}
const QString &functionName = functionItem->name();
const QString className = currentClass != nullptr ?
@@ -2010,7 +2006,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
// Skip enum helpers generated by Q_ENUM
if ((currentClass == nullptr || currentClass->isNamespace())
&& (functionName == u"qt_getEnumMetaObject" || functionName == u"qt_getEnumName")) {
- return nullptr;
+ return {};
}
// Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT
@@ -2018,10 +2014,10 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
if (currentClass != nullptr) {
if (functionName == u"qt_check_for_QGADGET_macro"
|| functionName.startsWith(u"qt_meta")) {
- return nullptr;
+ return {};
}
if (functionName == u"metaObject" && className != u"QObject")
- return nullptr;
+ return {};
}
} // PySide extensions
@@ -2029,7 +2025,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
if (tdb->isFunctionRejected(className, functionName, &rejectReason)) {
rejectFunction(functionItem, currentClass,
AbstractMetaBuilder::GenerationDisabled, rejectReason);
- return nullptr;
+ return {};
}
const QString &signature = functionSignature(functionItem);
@@ -2040,22 +2036,22 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
qCInfo(lcShiboken, "%s::%s was rejected by the type database (%s).",
qPrintable(className), qPrintable(signature), qPrintable(rejectReason));
}
- return nullptr;
+ return {};
}
if (functionItem->isFriend())
- return nullptr;
+ return {};
const auto cppAttributes = functionItem->attributes();
const bool deprecated = cppAttributes.testFlag(FunctionAttribute::Deprecated);
if (deprecated && m_skipDeprecated) {
rejectFunction(functionItem, currentClass,
AbstractMetaBuilder::GenerationDisabled, u" is deprecated."_s);
- return nullptr;
+ return {};
}
AbstractMetaFunction::Flags flags;
- auto *metaFunction = new AbstractMetaFunction(functionName);
+ auto metaFunction = std::make_shared<AbstractMetaFunction>(functionName);
metaFunction->setCppAttributes(cppAttributes);
const QByteArray cSignature = signature.toUtf8();
const QString unresolvedSignature =
@@ -2088,8 +2084,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
if (tdb->isReturnTypeRejected(className, returnType.toString(), &rejectReason)) {
rejectFunction(functionItem, currentClass,
AbstractMetaBuilder::GenerationDisabled, rejectReason);
- delete metaFunction;
- return nullptr;
+ return {};
}
TranslateTypeFlags flags;
@@ -2103,8 +2098,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
qPrintable(msgSkippingFunction(functionItem, signature, reason)));
rejectFunction(functionItem, currentClass,
AbstractMetaBuilder::UnmatchedReturnType, reason);
- delete metaFunction;
- return nullptr;
+ return {};
}
metaFunction->setType(type.value());
@@ -2135,8 +2129,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
if (tdb->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) {
rejectFunction(functionItem, currentClass,
AbstractMetaBuilder::GenerationDisabled, rejectReason);
- delete metaFunction;
- return nullptr;
+ return {};
}
TranslateTypeFlags flags;
@@ -2163,8 +2156,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
qPrintable(msgSkippingFunction(functionItem, signature, reason)));
rejectFunction(functionItem, currentClass,
AbstractMetaBuilder::UnmatchedArgumentType, reason);
- delete metaFunction;
- return nullptr;
+ return {};
}
auto metaType = metaTypeO.value();
@@ -2187,8 +2179,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
AbstractMetaArgumentList &metaArguments = metaFunction->arguments();
const FunctionModificationList functionMods = currentClass
- ? AbstractMetaFunction::findClassModifications(metaFunction, currentClass)
- : AbstractMetaFunction::findGlobalModifications(metaFunction);
+ ? AbstractMetaFunction::findClassModifications(metaFunction.get(), currentClass)
+ : AbstractMetaFunction::findGlobalModifications(metaFunction.get());
applyCachedFunctionModifications(metaFunction, functionMods);
@@ -2213,7 +2205,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
&& metaFunction->argumentName(i + 1, false, currentClass).isEmpty()) {
qCWarning(lcShiboken, "%s",
qPrintable(msgUnnamedArgumentDefaultExpression(currentClass, i + 1,
- className, metaFunction)));
+ className, metaFunction.get())));
}
}
@@ -3128,80 +3120,103 @@ std::optional<AbstractMetaType>
AbstractMetaClassPtr
AbstractMetaBuilder::inheritTemplateClass(const ComplexTypeEntryPtr &te,
const AbstractMetaClassCPtr &templateClass,
- const AbstractMetaTypeList &templateTypes,
- InheritTemplateFlags flags)
+ const AbstractMetaTypeList &templateTypes)
{
auto result = std::make_shared<AbstractMetaClass>();
result->setTypeDef(true);
result->setTypeEntry(te);
if (!AbstractMetaBuilderPrivate::inheritTemplate(result, templateClass,
- templateTypes, flags)) {
+ templateTypes)) {
return {};
}
AbstractMetaBuilderPrivate::inheritTemplateFunctions(result);
return result;
}
+
+static std::optional<AbstractMetaType>
+ inheritTemplateParameter(const AbstractMetaClassPtr &subclass,
+ const AbstractMetaClassCPtr &templateClass,
+ const TypeInfo &info, QString *errorMessage)
+{
+ QString typeName = info.qualifiedName().join("::"_L1);
+ TypeDatabase *typeDb = TypeDatabase::instance();
+ TypeEntryPtr t;
+ // Check for a non-type template integer parameter, that is, for a base
+ // "template <int R, int C> Matrix<R, C>" and subclass
+ // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of
+ // EnumValueTypeEntry for the integer values encountered on the fly.
+ if (isNumber(typeName)) {
+ t = typeDb->findType(typeName);
+ if (!t) {
+ auto parent = typeSystemTypeEntry(subclass->typeEntry());
+ t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent);
+ }
+ } else {
+ QStringList possibleNames;
+ possibleNames << subclass->qualifiedCppName() + "::"_L1 + typeName;
+ possibleNames << templateClass->qualifiedCppName() + "::"_L1 + typeName;
+ if (subclass->enclosingClass())
+ possibleNames << subclass->enclosingClass()->qualifiedCppName() + "::"_L1 + typeName;
+ possibleNames << typeName;
+
+ for (const QString &possibleName : std::as_const(possibleNames)) {
+ t = typeDb->findType(possibleName);
+ if (t)
+ break;
+ }
+ }
+
+ if (!t) {
+ *errorMessage = msgIgnoringTemplateParameter(typeName,
+ "The corresponding type was not found in the typesystem.");
+ return std::nullopt;
+ }
+
+ if (t->isContainer()) {
+ *errorMessage = msgIgnoringTemplateParameter(typeName,
+ "Template inheritance from nested containers is not supported");
+ return std::nullopt;
+ }
+ AbstractMetaType result(t);
+ result.setConstant(info.isConstant());
+ result.setReferenceType(info.referenceType());
+ result.setIndirectionsV(info.indirectionsV());
+ result.decideUsagePattern();
+ return result;
+}
+
bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass,
const AbstractMetaClassCPtr &templateClass,
const TypeInfo &info)
{
AbstractMetaTypeList templateTypes;
+ QString errorMessage;
for (const TypeInfo &i : info.instantiations()) {
- QString typeName = i.qualifiedName().join(u"::"_s);
- TypeDatabase *typeDb = TypeDatabase::instance();
- TypeEntryPtr t;
- // Check for a non-type template integer parameter, that is, for a base
- // "template <int R, int C> Matrix<R, C>" and subclass
- // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of
- // EnumValueTypeEntry for the integer values encountered on the fly.
- if (isNumber(typeName)) {
- t = typeDb->findType(typeName);
- if (!t) {
- auto parent = typeSystemTypeEntry(subclass->typeEntry());
- t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent);
- }
- } else {
- QStringList possibleNames;
- possibleNames << subclass->qualifiedCppName() + u"::"_s + typeName;
- possibleNames << templateClass->qualifiedCppName() + u"::"_s + typeName;
- if (subclass->enclosingClass())
- possibleNames << subclass->enclosingClass()->qualifiedCppName() + u"::"_s + typeName;
- possibleNames << typeName;
-
- for (const QString &possibleName : std::as_const(possibleNames)) {
- t = typeDb->findType(possibleName);
- if (t)
- break;
- }
- }
-
- if (t) {
- AbstractMetaType temporaryType(t);
- temporaryType.setConstant(i.isConstant());
- temporaryType.setReferenceType(i.referenceType());
- temporaryType.setIndirectionsV(i.indirectionsV());
- temporaryType.decideUsagePattern();
- templateTypes << temporaryType;
+ const auto typeO = inheritTemplateParameter(subclass, templateClass, i, &errorMessage);
+ if (typeO.has_value()) {
+ templateTypes.append(typeO.value());
} else {
- qCWarning(lcShiboken).noquote().nospace()
- << "Ignoring template parameter " << typeName << " from "
- << info.toString() << ". The corresponding type was not found in the typesystem.";
+ errorMessage = msgInheritTemplateIssue(subclass, info, errorMessage);
+ qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
}
}
+ if (templateTypes.isEmpty()) {
+ errorMessage = msgInheritTemplateIssue(subclass, info,
+ "No template parameters could be inherited"_L1);
+ qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
+ return false;
+ }
return inheritTemplate(subclass, templateClass, templateTypes);
}
bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass,
const AbstractMetaClassCPtr &templateClass,
- const AbstractMetaTypeList &templateTypes,
- InheritTemplateFlags flags)
+ const AbstractMetaTypeList &templateTypes)
{
subclass->setTemplateBaseClass(templateClass);
- if (flags.testFlag(InheritTemplateFlag::SetEnclosingClass))
- subclass->setEnclosingClass(templateClass->enclosingClass());
subclass->setTemplateBaseClassInstantiations(templateTypes);
subclass->setBaseClass(templateClass->baseClass());
return true;
@@ -3291,7 +3306,7 @@ AbstractMetaFunctionPtr
}
QString errorMessage;
- if (!applyArrayArgumentModifications(f->modifications(subclass), f.get(),
+ if (!applyArrayArgumentModifications(f->modifications(subclass), f,
&errorMessage)) {
qCWarning(lcShiboken, "While specializing %s (%s): %s",
qPrintable(subclass->name()), qPrintable(templateClass->name()),
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h
index cbd8c7034..20261ed3c 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h
@@ -100,10 +100,9 @@ public:
const AbstractMetaTypeList &templateTypes);
static AbstractMetaClassPtr
- inheritTemplateClass(const ComplexTypeEntryPtr &te,
- const AbstractMetaClassCPtr &templateClass,
- const AbstractMetaTypeList &templateTypes,
- InheritTemplateFlags flags = {});
+ inheritTemplateClass(const ComplexTypeEntryPtr &te,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaTypeList &templateTypes);
/// Performs a template specialization of the member function.
/// \param function Member function
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
index d7aaba5b0..4e337339e 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
@@ -98,20 +98,21 @@ public:
const QSet<QString> &enumsDeclarations);
void traverseEnums(const ScopeModelItem &item, const AbstractMetaClassPtr &parent,
const QStringList &enumsDeclarations);
- AbstractMetaFunctionRawPtrList classFunctionList(const ScopeModelItem &scopeItem,
- AbstractMetaClass::Attributes *constructorAttributes,
- const AbstractMetaClassPtr &currentClass);
+ AbstractMetaFunctionList classFunctionList(const ScopeModelItem &scopeItem,
+ AbstractMetaClass::Attributes *constructorAttributes,
+ const AbstractMetaClassPtr &currentClass);
void traverseFunctions(const ScopeModelItem& item,
const AbstractMetaClassPtr &parent);
- static void applyFunctionModifications(AbstractMetaFunction *func);
+ static void applyFunctionModifications(const AbstractMetaFunctionPtr &func);
void traverseFields(const ScopeModelItem &item, const AbstractMetaClassPtr &parent);
bool traverseStreamOperator(const FunctionModelItem &functionItem,
const AbstractMetaClassPtr &currentClass);
void traverseOperatorFunction(const FunctionModelItem &item,
const AbstractMetaClassPtr &currentClass);
- AbstractMetaFunction *traverseAddedFunctionHelper(const AddedFunctionPtr &addedFunc,
- const AbstractMetaClassPtr &metaClass,
- QString *errorMessage);
+ AbstractMetaFunctionPtr
+ traverseAddedFunctionHelper(const AddedFunctionPtr &addedFunc,
+ const AbstractMetaClassPtr &metaClass,
+ QString *errorMessage);
bool traverseAddedGlobalFunction(const AddedFunctionPtr &addedFunc,
QString *errorMessage);
bool traverseAddedMemberFunction(const AddedFunctionPtr &addedFunc,
@@ -121,8 +122,9 @@ public:
const AbstractMetaClassPtr &currentClass,
AbstractMetaBuilder::RejectReason reason,
const QString &rejectReason);
- AbstractMetaFunction *traverseFunction(const FunctionModelItem &function,
- const AbstractMetaClassPtr &currentClass);
+ AbstractMetaFunctionPtr
+ traverseFunction(const FunctionModelItem &function,
+ const AbstractMetaClassPtr &currentClass);
std::optional<AbstractMetaField> traverseField(const VariableModelItem &field,
const AbstractMetaClassCPtr &cls);
void checkFunctionModifications() const;
@@ -142,7 +144,7 @@ public:
* said class.
* \param metaFunction conversion operator function to be fixed.
*/
- static void fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction);
+ static void fixReturnTypeOfConversionOperator(const AbstractMetaFunctionPtr &metaFunction);
void parseQ_Properties(const AbstractMetaClassPtr &metaClass,
const QStringList &declarations);
@@ -190,8 +192,7 @@ public:
const TypeInfo &info);
static bool inheritTemplate(const AbstractMetaClassPtr &subclass,
const AbstractMetaClassCPtr &templateClass,
- const AbstractMetaTypeList &templateTypes,
- InheritTemplateFlags flags = {});
+ const AbstractMetaTypeList &templateTypes);
static AbstractMetaFunctionPtr
inheritTemplateFunction(const AbstractMetaFunctionCPtr &function,
@@ -213,7 +214,8 @@ public:
void sortLists();
void setInclude(const TypeEntryPtr &te, const QString &path) const;
- static void fixArgumentNames(AbstractMetaFunction *func, const FunctionModificationList &mods);
+ static void fixArgumentNames(const AbstractMetaFunctionPtr &func,
+ const FunctionModificationList &mods);
void fillAddedFunctions(const AbstractMetaClassPtr &metaClass);
AbstractMetaClassCPtr resolveTypeSystemTypeDef(const AbstractMetaType &t) const;
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h b/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h
index 802f549cf..27321ca2d 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h
@@ -30,6 +30,7 @@ using AbstractMetaEnumValueList = QList<AbstractMetaEnumValue>;
using AbstractMetaFieldList = QList<AbstractMetaField>;
using AbstractMetaFunctionRawPtrList = QList<AbstractMetaFunction *>;
using AbstractMetaFunctionCList = QList<AbstractMetaFunctionCPtr>;
+using AbstractMetaFunctionList = QList<AbstractMetaFunctionPtr>;
using AbstractMetaTypeList = QList<AbstractMetaType>;
using UsingMembers = QList<UsingMember>;
diff --git a/sources/shiboken6/ApiExtractor/abstractmetatype.cpp b/sources/shiboken6/ApiExtractor/abstractmetatype.cpp
index dcfc74bbb..3ec07509d 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetatype.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetatype.cpp
@@ -543,6 +543,7 @@ void AbstractMetaType::decideUsagePattern()
pattern = ObjectPattern;
}
setTypeUsagePattern(pattern);
+ Q_ASSERT(pattern != ContainerPattern || !d->m_instantiations.isEmpty());
}
bool AbstractMetaTypeData::hasTemplateChildren() const
diff --git a/sources/shiboken6/ApiExtractor/apiextractor.cpp b/sources/shiboken6/ApiExtractor/apiextractor.cpp
index 83ee4437e..786cd0783 100644
--- a/sources/shiboken6/ApiExtractor/apiextractor.cpp
+++ b/sources/shiboken6/ApiExtractor/apiextractor.cpp
@@ -456,11 +456,10 @@ AbstractMetaFunctionPtr
AbstractMetaClassPtr ApiExtractor::inheritTemplateClass(const ComplexTypeEntryPtr &te,
const AbstractMetaClassCPtr &templateClass,
- const AbstractMetaTypeList &templateTypes,
- InheritTemplateFlags flags)
+ const AbstractMetaTypeList &templateTypes)
{
return AbstractMetaBuilder::inheritTemplateClass(te, templateClass,
- templateTypes, flags);
+ templateTypes);
}
QString ApiExtractorPrivate::getSimplifiedContainerTypeName(const AbstractMetaType &type)
@@ -606,7 +605,15 @@ void ApiExtractorPrivate::addInstantiatedSmartPointer(InstantiationCollectContex
const auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(smp.smartPointer->typeEntry());
QString name = ste->getTargetName(smp.type);
auto parentTypeEntry = ste->parent();
- InheritTemplateFlags flags;
+
+ // FIXME PYSIDE 7: Make global scope the default behavior?
+ // Note: Also requires changing SmartPointerTypeEntry::getTargetName()
+ // to not strip namespaces from unnamed instances.
+ const bool globalScope = name.startsWith("::"_L1);
+ if (globalScope) {
+ name.remove(0, 2);
+ parentTypeEntry = typeSystemTypeEntry(ste);
+ }
auto colonPos = name.lastIndexOf(u"::");
const bool withinNameSpace = colonPos != -1;
@@ -617,19 +624,18 @@ void ApiExtractorPrivate::addInstantiatedSmartPointer(InstantiationCollectContex
if (nameSpaces.isEmpty())
throw Exception(msgNamespaceNotFound(name));
parentTypeEntry = nameSpaces.constFirst();
- } else {
- flags.setFlag(InheritTemplateFlag::SetEnclosingClass);
}
TypedefEntryPtr typedefEntry(new TypedefEntry(name, ste->name(), ste->version(),
parentTypeEntry));
typedefEntry->setTargetLangPackage(ste->targetLangPackage());
auto instantiationEntry = TypeDatabase::initializeTypeDefEntry(typedefEntry, ste);
+ instantiationEntry->setParent(parentTypeEntry);
smp.specialized = ApiExtractor::inheritTemplateClass(instantiationEntry, smp.smartPointer,
- {instantiatedType}, flags);
+ {instantiatedType});
Q_ASSERT(smp.specialized);
- if (withinNameSpace) { // move class to desired namespace
+ if (parentTypeEntry->type() != TypeEntry::TypeSystemType) { // move class to desired namespace
const auto enclClass = AbstractMetaClass::findClass(m_builder->classes(), parentTypeEntry);
Q_ASSERT(enclClass);
auto specialized = std::const_pointer_cast<AbstractMetaClass>(smp.specialized);
diff --git a/sources/shiboken6/ApiExtractor/apiextractor.h b/sources/shiboken6/ApiExtractor/apiextractor.h
index feae9454c..7bff5c252 100644
--- a/sources/shiboken6/ApiExtractor/apiextractor.h
+++ b/sources/shiboken6/ApiExtractor/apiextractor.h
@@ -73,8 +73,7 @@ public:
static AbstractMetaClassPtr
inheritTemplateClass(const ComplexTypeEntryPtr &te,
const AbstractMetaClassCPtr &templateClass,
- const AbstractMetaTypeList &templateTypes,
- InheritTemplateFlags flags = {});
+ const AbstractMetaTypeList &templateTypes);
private:
ApiExtractorPrivate *d;
diff --git a/sources/shiboken6/ApiExtractor/apiextractorflags.h b/sources/shiboken6/ApiExtractor/apiextractorflags.h
index 4fe6ecc1a..6f69b8b77 100644
--- a/sources/shiboken6/ApiExtractor/apiextractorflags.h
+++ b/sources/shiboken6/ApiExtractor/apiextractorflags.h
@@ -15,12 +15,4 @@ enum class ApiExtractorFlag
Q_DECLARE_FLAGS(ApiExtractorFlags, ApiExtractorFlag)
Q_DECLARE_OPERATORS_FOR_FLAGS(ApiExtractorFlags)
-enum class InheritTemplateFlag
-{
- SetEnclosingClass = 0x1
-};
-
-Q_DECLARE_FLAGS(InheritTemplateFlags, InheritTemplateFlag)
-Q_DECLARE_OPERATORS_FOR_FLAGS(InheritTemplateFlags)
-
#endif // APIEXTRACTORFLAGS_H
diff --git a/sources/shiboken6/ApiExtractor/apiextractorresult.cpp b/sources/shiboken6/ApiExtractor/apiextractorresult.cpp
index 2a48a30d1..5a433bbeb 100644
--- a/sources/shiboken6/ApiExtractor/apiextractorresult.cpp
+++ b/sources/shiboken6/ApiExtractor/apiextractorresult.cpp
@@ -7,6 +7,7 @@
#include "enumtypeentry.h"
#include "flagstypeentry.h"
+#include "smartpointertypeentry.h"
ApiExtractorResult::ApiExtractorResult() = default;
@@ -50,6 +51,18 @@ const InstantiatedSmartPointers &ApiExtractorResult::instantiatedSmartPointers()
return m_instantiatedSmartPointers;
}
+std::optional<InstantiatedSmartPointer>
+ ApiExtractorResult::findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
+ const TypeEntryCPtr &pointee) const
+{
+ for (const auto &smp : m_instantiatedSmartPointers) {
+ const auto &i = smp.type;
+ if (i.typeEntry() == pointer && i.instantiations().at(0).typeEntry() == pointee)
+ return smp;
+ }
+ return std::nullopt;
+}
+
const QMultiHash<QString, QString> &ApiExtractorResult::typedefTargetToName() const
{
return m_typedefTargetToName;
diff --git a/sources/shiboken6/ApiExtractor/apiextractorresult.h b/sources/shiboken6/ApiExtractor/apiextractorresult.h
index 88a2093f1..b2aae88ed 100644
--- a/sources/shiboken6/ApiExtractor/apiextractorresult.h
+++ b/sources/shiboken6/ApiExtractor/apiextractorresult.h
@@ -43,6 +43,9 @@ public:
const AbstractMetaTypeList &instantiatedContainers() const;
const InstantiatedSmartPointers &instantiatedSmartPointers() const;
+ std::optional<InstantiatedSmartPointer>
+ findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
+ const TypeEntryCPtr &pointee) const;
const QMultiHash<QString, QString> &typedefTargetToName() const;
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp
index da6930476..6c0cf3ae2 100644
--- a/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp
@@ -235,6 +235,7 @@ static QByteArray msgCreateTranslationUnit(const QByteArrayList &clangArgs, unsi
static CXTranslationUnit createTranslationUnit(CXIndex index,
const QByteArrayList &args,
bool addCompilerSupportArguments,
+ LanguageLevel level,
unsigned flags = 0)
{
// courtesy qdoc
@@ -255,7 +256,7 @@ static CXTranslationUnit createTranslationUnit(CXIndex index,
QByteArrayList clangArgs;
if (addCompilerSupportArguments) {
- clangArgs += emulatedCompilerOptions();
+ clangArgs += emulatedCompilerOptions(level);
clangArgs += defaultArgs;
}
clangArgs += detectVulkan();
@@ -280,7 +281,7 @@ static CXTranslationUnit createTranslationUnit(CXIndex index,
*/
bool parse(const QByteArrayList &clangArgs, bool addCompilerSupportArguments,
- unsigned clangFlags, BaseVisitor &bv)
+ LanguageLevel level, unsigned clangFlags, BaseVisitor &bv)
{
CXIndex index = clang_createIndex(0 /* excludeDeclarationsFromPCH */,
1 /* displayDiagnostics */);
@@ -291,7 +292,7 @@ bool parse(const QByteArrayList &clangArgs, bool addCompilerSupportArguments,
CXTranslationUnit translationUnit =
createTranslationUnit(index, clangArgs, addCompilerSupportArguments,
- clangFlags);
+ level, clangFlags);
if (!translationUnit)
return false;
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangparser.h b/sources/shiboken6/ApiExtractor/clangparser/clangparser.h
index 4a46248e4..22e0a50cd 100644
--- a/sources/shiboken6/ApiExtractor/clangparser/clangparser.h
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangparser.h
@@ -14,6 +14,8 @@
#include <string_view>
#include <utility>
+enum class LanguageLevel;
+
namespace clang {
struct Diagnostic;
@@ -79,7 +81,7 @@ private:
bool parse(const QByteArrayList &clangArgs,
bool addCompilerSupportArguments,
- unsigned clangFlags, BaseVisitor &ctx);
+ LanguageLevel level, unsigned clangFlags, BaseVisitor &ctx);
} // namespace clang
diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
index 4c13b141f..20224020b 100644
--- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
+++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
@@ -106,7 +106,7 @@ static bool runProcess(const QString &program, const QStringList &arguments,
QProcess process;
process.start(program, arguments, QProcess::ReadWrite);
if (!process.waitForStarted()) {
- qWarning().noquote().nospace() << "Unable to start "
+ qCWarning(lcShiboken).noquote().nospace() << "Unable to start "
<< process.program() << ": " << process.errorString();
return false;
}
@@ -119,18 +119,18 @@ static bool runProcess(const QString &program, const QStringList &arguments,
*stdOutIn = process.readAllStandardOutput();
if (!finished) {
- qWarning().noquote().nospace() << process.program() << " timed out: " << stdErr;
+ qCWarning(lcShiboken).noquote().nospace() << process.program() << " timed out: " << stdErr;
process.kill();
return false;
}
if (process.exitStatus() != QProcess::NormalExit) {
- qWarning().noquote().nospace() << process.program() << " crashed: " << stdErr;
+ qCWarning(lcShiboken).noquote().nospace() << process.program() << " crashed: " << stdErr;
return false;
}
if (process.exitCode() != 0) {
- qWarning().noquote().nospace() << process.program() << " exited "
+ qCWarning(lcShiboken).noquote().nospace() << process.program() << " exited "
<< process.exitCode() << ": " << stdErr;
return false;
}
@@ -263,8 +263,8 @@ static QString queryLlvmConfigDir(const QString &arg)
return {};
const QString path = QFile::decodeName(stdOut.trimmed());
if (!QFileInfo::exists(path)) {
- qWarning(R"(%s: "%s" as returned by llvm-config "%s" does not exist.)",
- __FUNCTION__, qPrintable(QDir::toNativeSeparators(path)), qPrintable(arg));
+ qCWarning(lcShiboken, R"(%s: "%s" as returned by llvm-config "%s" does not exist.)",
+ __FUNCTION__, qPrintable(QDir::toNativeSeparators(path)), qPrintable(arg));
return {};
}
return path;
@@ -277,7 +277,8 @@ static QString findClangLibDir()
const QString path = QFile::decodeName(qgetenv(envVar)) + u"/lib"_s;
if (QFileInfo::exists(path))
return path;
- qWarning("%s: %s as pointed to by %s does not exist.", __FUNCTION__, qPrintable(path), envVar);
+ qCWarning(lcShiboken, "%s: %s as pointed to by %s does not exist.",
+ __FUNCTION__, qPrintable(path), envVar);
}
}
return queryLlvmConfigDir(u"--libdir"_s);
@@ -289,13 +290,23 @@ static QString findClangBuiltInIncludesDir()
const QString clangPathLibDir = findClangLibDir();
if (!clangPathLibDir.isEmpty()) {
QString candidate;
+ QString clangDirName = clangPathLibDir + u"/clang"_s;
+ // PYSIDE-2769: llvm-config --libdir may report /usr/lib64 on manylinux_2_28_x86_64
+ // whereas the includes are under /usr/lib/clang/../include.
+ if (!QFileInfo::exists(clangDirName) && clangPathLibDir.endsWith("64"_L1)) {
+ const QString fallback = clangPathLibDir.sliced(0, clangPathLibDir.size() - 2);
+ clangDirName = fallback + u"/clang"_s;
+ qCWarning(lcShiboken, "%s: Falling back from %s to %s.",
+ __FUNCTION__, qPrintable(clangPathLibDir), qPrintable(fallback));
+ }
+
QVersionNumber lastVersionNumber(1, 0, 0);
- const QString clangDirName = clangPathLibDir + u"/clang"_s;
QDir clangDir(clangDirName);
const QFileInfoList versionDirs =
clangDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
if (versionDirs.isEmpty())
- qWarning("%s: No subdirectories found in %s.", __FUNCTION__, qPrintable(clangDirName));
+ qCWarning(lcShiboken, "%s: No subdirectories found in %s.",
+ __FUNCTION__, qPrintable(clangDirName));
for (const QFileInfo &fi : versionDirs) {
const QString fileName = fi.fileName();
if (fileName.at(0).isDigit()) {
@@ -365,14 +376,15 @@ static void appendClangBuiltinIncludes(HeaderPaths *p)
}
// Returns clang options needed for emulating the host compiler
-QByteArrayList emulatedCompilerOptions()
+QByteArrayList emulatedCompilerOptions(LanguageLevel level)
{
QByteArrayList result;
HeaderPaths headerPaths;
switch (compiler()) {
case Compiler::Msvc:
result.append("-fms-compatibility-version="_ba + msvcCompatVersion());
- result.append(QByteArrayLiteral("-fdelayed-template-parsing"));
+ if (level < LanguageLevel::Cpp20)
+ result.append("-fdelayed-template-parsing"_ba);
result.append(QByteArrayLiteral("-Wno-microsoft-enum-value"));
result.append("/Zc:__cplusplus"_ba);
// Fix yvals_core.h: STL1000: Unexpected compiler version, expected Clang 7 or newer (MSVC2017 update)
diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h
index 462e8f205..f1d63b7c3 100644
--- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h
+++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h
@@ -33,7 +33,7 @@ enum class Platform {
namespace clang {
QVersionNumber libClangVersion();
-QByteArrayList emulatedCompilerOptions();
+QByteArrayList emulatedCompilerOptions(LanguageLevel level);
LanguageLevel emulatedCompilerLanguageLevel();
const char *languageLevelOption(LanguageLevel l);
diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp
index f9f46f520..170595660 100644
--- a/sources/shiboken6/ApiExtractor/messages.cpp
+++ b/sources/shiboken6/ApiExtractor/messages.cpp
@@ -481,6 +481,21 @@ QString msgCannotFindTypeEntryForSmartPointer(const QString &t, const QString &s
+ u"\" for instantiation of \""_s +smartPointerType + u"\"."_s;
}
+QString msgInheritTemplateIssue(const AbstractMetaClassPtr &subclass,
+ const TypeInfo &info,
+ const QString &what)
+{
+ return "While inheriting template "_L1 + subclass->name()
+ + " from "_L1 + info.toString() + ": "_L1 + what;
+}
+
+QString msgIgnoringTemplateParameter(const QString &typeName,
+ const char *why)
+{
+ return "Ignoring template parameter "_L1 + typeName +
+ ": "_L1 + QLatin1StringView(why);
+}
+
QString msgInvalidSmartPointerType(const TypeInfo &i)
{
return u"Invalid smart pointer type \""_s +i.toString() + u"\"."_s;
@@ -980,3 +995,10 @@ QString msgInvalidLanguageLevel(const QString &l)
{
return u"Invalid argument for language level: \""_s + l + u"\"."_s;
}
+
+QString msgCannotFindImage(const QString &href, const QString &context,
+ const QString &candidate)
+{
+ return "Cannot resolve image "_L1 + href + " for "_L1 + context
+ + " (tried "_L1 + QDir::toNativeSeparators(candidate) + ")."_L1;
+}
diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h
index 2899cbdfa..5216b26a7 100644
--- a/sources/shiboken6/ApiExtractor/messages.h
+++ b/sources/shiboken6/ApiExtractor/messages.h
@@ -126,6 +126,10 @@ QString msgUnableToTranslateType(const TypeInfo &typeInfo,
QString msgCannotFindTypeEntry(const QString &t);
QString msgCannotFindTypeEntryForSmartPointer(const QString &t, const QString &smartPointerType);
+QString msgInheritTemplateIssue(const AbstractMetaClassPtr &subclass,
+ const TypeInfo &info, const QString &what);
+QString msgIgnoringTemplateParameter(const QString &typeName,
+ const char *why);
QString msgInvalidSmartPointerType(const TypeInfo &i);
QString msgCannotFindSmartPointerInstantion(const TypeInfo &i);
@@ -257,4 +261,7 @@ QString msgMissingProjectFileMarker(const QString &name, const QByteArray &start
QString msgInvalidLanguageLevel(const QString &l);
+QString msgCannotFindImage(const QString &href, const QString &context,
+ const QString &candidate);
+
#endif // MESSAGES_H
diff --git a/sources/shiboken6/ApiExtractor/typedatabase.cpp b/sources/shiboken6/ApiExtractor/typedatabase.cpp
index 749c4baa3..61fd22418 100644
--- a/sources/shiboken6/ApiExtractor/typedatabase.cpp
+++ b/sources/shiboken6/ApiExtractor/typedatabase.cpp
@@ -88,7 +88,8 @@ static const PythonTypes &builtinPythonTypes()
{u"PyObject"_s, u"true"_s, TypeSystem::CPythonType::Other},
// shiboken-specific
{u"PyPathLike"_s, u"Shiboken::String::checkPath"_s, TypeSystem::CPythonType::Other},
- {u"PySequence"_s, u"Shiboken::String::checkIterable"_s, TypeSystem::CPythonType::Other},
+ {u"PySequence"_s, u"Shiboken::String::checkIterableArgument"_s,
+ TypeSystem::CPythonType::Other},
{u"PyUnicode"_s, u"PyUnicode_Check"_s, TypeSystem::CPythonType::String},
{u"PyTypeObject"_s, u"PyType_Check"_s, TypeSystem::CPythonType::Other},
{u"str"_s, u"Shiboken::String::check"_s, TypeSystem::CPythonType::String},
diff --git a/sources/shiboken6/cmake/ShibokenHelpers.cmake b/sources/shiboken6/cmake/ShibokenHelpers.cmake
index 8bc066102..cff6df95e 100644
--- a/sources/shiboken6/cmake/ShibokenHelpers.cmake
+++ b/sources/shiboken6/cmake/ShibokenHelpers.cmake
@@ -202,12 +202,6 @@ macro(get_python_extension_suffix)
# Python_SOABI is only set by CMake 3.17+
# TODO: Lower this to CMake 3.16 if possible.
if(SHIBOKEN_IS_CROSS_BUILD)
- # For android platform armv7a FindPython module return Python_SOABI as empty because
- # it is unable to set Python_CONFIG i.e. find `python3-config` script
- # This workaround sets the Python_SOABI manually for this platform.
- if(CMAKE_SYSTEM_NAME STREQUAL "Android" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a")
- set(Python_SOABI "cpython-311}")
- endif()
if(NOT Python_SOABI)
message(FATAL_ERROR "Python_SOABI variable is empty.")
endif()
@@ -320,6 +314,17 @@ macro(shiboken_find_required_python)
"${_shiboken_backup_CMAKE_FIND_ROOT_PATH_MODE_PROGRAM}")
set(CMAKE_FIND_ROOT_PATH
"${_shiboken_backup_CMAKE_FIND_ROOT_PATH}")
+
+ # For Android platform sometimes the FindPython module returns Python_SOABI as empty in
+ # certain scenarios eg: armv7a target, macOS host etc. This is because
+ # it is unable to set Python_CONFIG i.e. `python3-config` script
+ # This workaround sets the Python_SOABI manually for this Android platform.
+ # This needs to be updated manually if the Python version for Android cross compilation
+ # changes.
+ # TODO: Find a better way to set Python_SOABI for Android platform
+ if(CMAKE_SYSTEM_NAME STREQUAL "Android" AND NOT Python_SOABI)
+ set(Python_SOABI "cpython-311")
+ endif()
else()
find_package(
Python
diff --git a/sources/shiboken6/doc/shibokenmodule.rst b/sources/shiboken6/doc/shibokenmodule.rst
index 2f1c6d166..3bc4fa6ba 100644
--- a/sources/shiboken6/doc/shibokenmodule.rst
+++ b/sources/shiboken6/doc/shibokenmodule.rst
@@ -125,6 +125,11 @@ To import the module:
Dumps the map of wrappers existing in libshiboken to standard error.
+.. function:: dumpConverters()
+
+ Dumps the map of named converters existing in libshiboken to standard
+ error.
+
.. py:class:: VoidPtr(address, size = -1, writeable = 0)
:param address: (PyBuffer, SbkObject, int, VoidPtr)
diff --git a/sources/shiboken6/doc/typediscovery.rst b/sources/shiboken6/doc/typediscovery.rst
new file mode 100644
index 000000000..76d3adf7b
--- /dev/null
+++ b/sources/shiboken6/doc/typediscovery.rst
@@ -0,0 +1,145 @@
+.. _typediscovery:
+
+**************
+Type Discovery
+**************
+
+When converting objects which are part of a class hierarchy from a pointer to a
+base class, it is expected to get the Python type of the actual, most derived
+type, as opposed to C++ which requires a cast for this:
+
+.. code-block:: python
+
+ def event(self, event):
+ if event.type() == QEvent.Type.MousePress:
+ self.do_things(event.position())
+ ...
+
+
+.. code-block:: c++
+
+ bool event(QEvent *event) override
+ {
+ if (event->type() == QEvent::MousePress) {
+ auto *mouseEvent = static_cast<QMouseEvent *>(event);
+ doThings(mouseEvent->position());
+ ...
+ }
+
+The process of determining the type of the event is called `type discovery`.
+
+Shiboken generates code to automatically detect the type. First, it tries to
+find a converter for the name obtained by ``typeid(*pointer).name()``. This
+should normally work as this name is registered by the binding. If that fails,
+it starts walking a type inheritance graph built up in libshiboken to find the
+most derived class by using a cast function (``dynamic_cast<>`` by default) to
+check.
+
+For normal class hierarchies with virtual destructors, no special handling
+is required since ``typeid()`` usually detects the proper class name.
+
+Multiple inheritance
+====================
+
+In case of multiple inheritance in C++, the conversion to the derived class is
+not done in case it is not a single-line direct inheritance. For example, in
+Qt, the class ``QWidget`` inherits both ``QObject`` (base of the ``QObject``
+hierarchy) and ``QPaintDevice``.
+
+When calling a function returning a ``QPaintDevice *``, for example
+``QPainter.device()``, a Python type representing ``QPaintDevice`` is returned
+instead of the underlying widget type. This restriction exists because the
+underlying pointer in C++ is a pointer to a ``QPaintDevice *`` and differs from
+the pointer to the ``QWidget``.
+
+Hierarchies of classes with non-virtual destructors
+===================================================
+
+There are some hierarchies of value-ish C++ classes that do not have virtual
+destructors. This makes type discovery based on ``typeid()`` and
+``dynamic_cast<>`` impossible.
+
+Examples in Qt are the ``QStyleOption``-derived or the ``QGradient``
+-derived classes.
+
+For such classes, some attributes need to be specified on the type entries:
+
+Primarily, a :ref:`polymorphic-id-expression` attribute
+must be specified to be used as a check replacing ``dynamic_cast<>``.
+
+In addition, a :ref:`polymorphic-name-function` attribute can be specified.
+This replaces the type name guess obtained by ``typeid()`` and is mainly a hint
+to speed things up by skipping the checks for each type in the inheritance
+graph.
+
+A :ref:`polymorphic-base` attribute identifies the base class of a hierarchy.
+It should be given in case the base class inherits from another class to
+prevent the logic from going below the base class.
+
+Using type discovery attributes for class hierarchies with virtual destructors
+==============================================================================
+
+It is possible to use :ref:`polymorphic-id-expression` and
+:ref:`polymorphic-name-function` for normal class hierarchies with virtual
+destructors as well since they basically replace ``typeid()`` and
+``dynamic_cast<>``. This makes sense if expressions can be specified that are
+faster than the checks on virtual tables.
+
+Specifying :ref:`polymorphic-base` can also make sense for generating special
+cast functions in case of multiple inheritance. For example, in Qt,
+``QWindow``, ``QLayout``, ``QWidget`` are base classes of hierarchies. Since
+they all inherit from ``QObject``, indicating the base classes prevents
+the logic from using ``QObject`` as a base class.
+
+.. _typediscovery-attributes:
+
+Type discovery attributes reference
+===================================
+
+The following attributes related to type discovery may be be specified on the
+:ref:`object-type` or :ref:`value-type` elements:
+
+.. _polymorphic-id-expression:
+
+polymorphic-id-expression
++++++++++++++++++++++++++
+
+The **polymorphic-id-expression** attribute specifies an expression checking
+whether a base class pointer is of the matching type. For example, in a
+``virtual eventHandler(BaseEvent *e)`` function, this is used to construct a
+Python wrapper matching the derived class (for example, a ``MouseEvent`` or
+similar). The attribute value may contain placeholders:
+
+%1
+ Fully qualified class name
+
+%B
+ Fully qualified name of the base class (found by base class
+ search or as indicated by **polymorphic-base**).
+
+To check for a class inheriting ``BaseEvent``, specify:
+
+.. code-block:: xml
+
+ <object-type name="MouseEvent"
+ polymorphic-id-expression="%B-&gt;type() == BaseEvent::MouseEvent"/>
+
+.. _polymorphic-name-function:
+
+polymorphic-name-function
++++++++++++++++++++++++++
+
+The **polymorphic-name-function** attribute specifies the name of a function
+returning the type name of a derived class on the base class type entry.
+Normally, ``typeid(ptr).name()`` is used for this.
+
+The function is expected to return ``const char *``.
+
+.. _polymorphic-base:
+
+polymorphic-base
+++++++++++++++++
+
+The boolean **polymorphic-base** attribute indicates whether the class is the
+base class of a class hierarchy. It is used for the *%B* placeholder in
+**polymorphic-id-expression** and for cast operations in multiple inheritance.
diff --git a/sources/shiboken6/doc/typesystem.rst b/sources/shiboken6/doc/typesystem.rst
index e1e4fdda2..26f929801 100644
--- a/sources/shiboken6/doc/typesystem.rst
+++ b/sources/shiboken6/doc/typesystem.rst
@@ -65,3 +65,4 @@ Extra options and Python caveats
typesystem_solving_compilation.rst
typesystem_specialfunctions.rst
+ typediscovery.rst
diff --git a/sources/shiboken6/doc/typesystem_converters.rst b/sources/shiboken6/doc/typesystem_converters.rst
index 7bdabc49c..ab6fba930 100644
--- a/sources/shiboken6/doc/typesystem_converters.rst
+++ b/sources/shiboken6/doc/typesystem_converters.rst
@@ -233,61 +233,3 @@ Variables & Functions
**%CHECKTYPE[CPPTYPE]**
Replaced by a |project| type checking function for a Python variable.
The C++ type is indicated by ``CPPTYPE``.
-
-
-.. _oldconverters:
-
-Converting The Old Converters
-=============================
-
-If you use |project| for your bindings, and has defined some type conversions
-using the ``Shiboken::Converter`` template, then you must update your converters
-to the new scheme.
-
-Previously your conversion rules were declared in one line, like this:
-
-
-.. code-block:: xml
-
- <primitive-type name="Complex" target-lang-api-name="PyComplex">
- <include file-name="complex.h" location="global"/>
- <conversion-rule file="complex_conversions.h"/>
- </primitive-type>
-
-
-And implemented in a separate C++ file, like this:
-
-
-.. code-block:: c++
-
- namespace Shiboken {
- template<> struct Converter<Complex>
- {
- static inline bool checkType(PyObject* pyObj) {
- return PyComplex_Check(pyObj);
- }
- static inline bool isConvertible(PyObject* pyObj) {
- return PyComplex_Check(pyObj);
- }
- static inline PyObject* toPython(void* cppobj) {
- return toPython(*reinterpret_cast<Complex*>(cppobj));
- }
- static inline PyObject* toPython(const Complex& cpx) {
- return PyComplex_FromDoubles(cpx.real(), cpx.imag());
- }
- static inline Complex toCpp(PyObject* pyobj) {
- double real = PyComplex_RealAsDouble(pyobj);
- double imag = PyComplex_ImagAsDouble(pyobj);
- return Complex(real, imag);
- }
- };
- }
-
-
-In this case, the parts of the implementation that will be used in the new
-conversion-rule are the ones in the two last method
-``static inline PyObject* toPython(const Complex& cpx)`` and
-``static inline Complex toCpp(PyObject* pyobj)``. The ``isConvertible`` method
-is gone, and the ``checkType`` is now an attribute of the :ref:`add-conversion <add-conversion>`
-tag. Refer back to the first example in this page and you will be able to
-correlate the above template with the new scheme of conversion rule definition.
diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst
index 66e68ae2b..e979c4ee2 100644
--- a/sources/shiboken6/doc/typesystem_specifying_types.rst
+++ b/sources/shiboken6/doc/typesystem_specifying_types.rst
@@ -536,37 +536,8 @@ type system has this attribute set, the heuristics will be applied
to all classes. In shiboken 7, it will be mandatory to set the
attribute.
-The *optional* **polymorphic-id-expression** attribute specifies an
-expression checking whether a base class pointer is of the matching
-type. For example, in a ``virtual eventHandler(BaseEvent *e)``
-function, this is used to construct a Python wrapper matching
-the derived class (for example, a ``MouseEvent`` or similar).
-The attribute value may contain placeholders:
-
-%1
- Fully qualified class name
-
-%B
- Fully qualified name of the base class (found by base class
- search or as indicated by **polymorphic-base**).
-
-To check for a class inheriting ``BaseEvent``, specify:
-
-.. code-block:: xml
-
- <object-type name="MouseEvent"
- polymorphic-id-expression="%B-&gt;type() == BaseEvent::MouseEvent"/>
-
-The *optional* **polymorphic-name-function** specifies the name of a
-function returning the type name of a derived class on the base class
-type entry. Normally, ``typeid(ptr).name()`` is used for this.
-However, this fails if the type hierarchy does not have virtual functions.
-In this case, a function is required which typically decides depending
-on some type enumeration.
-
-The *optional* **polymorphic-base** attribute indicates
-whether the class is the base class of a class hierarchy
-(used for the *%B* placeholder in **polymorphic-id-expression**).
+For the *optional* **polymorphic-id-expression**, **polymorphic-name-function**
+and **polymorphic-base** attributes, see :ref:`typediscovery-attributes`.
interface-type
^^^^^^^^^^^^^^
@@ -750,6 +721,9 @@ found in the code will be generated. The type name might optionally
be followed an equal sign and the Python type name, for example
``instantiations="int=IntPtr,double=DoublePtr"``.
It is also possible to specify a namespace delimited by ``::``.
+By default, the type will be in the namespace of the smart pointer,
+for example, ``std`` for ``std::shared_ptr``. Preceding
+the type name by ``::`` causes it to be in the global namespace.
The *optional* attribute **type** specifies the type:
diff --git a/sources/shiboken6/generator/generator.cpp b/sources/shiboken6/generator/generator.cpp
index b224858c5..a01326530 100644
--- a/sources/shiboken6/generator/generator.cpp
+++ b/sources/shiboken6/generator/generator.cpp
@@ -231,10 +231,9 @@ QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType &smartP
const AbstractMetaType innerType = smartPointerType.getSmartPointerInnerType();
smartPointerType.typeEntry()->qualifiedCppName();
QString fileName = smartPointerType.typeEntry()->qualifiedCppName().toLower();
- fileName.replace(u"::"_s, u"_"_s);
- fileName.append(u"_"_s);
+ fileName.append(u'_');
fileName.append(innerType.name().toLower());
-
+ fileName.replace(u"::"_s, u"_"_s); // std::shared_ptr<std::string>
return fileName;
}
diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
index 2797ff254..1634a7e83 100644
--- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
@@ -970,8 +970,10 @@ static QStringList enumListToToc(const AbstractMetaEnumList &enums)
static QChar sortKey(const QString &key)
{
const auto size = key.size();
- if (size >= 2 && (key.at(0) == u'Q' || key.at(0) == u'q') && key.at(1).isUpper())
- return key.at(1); // "QClass" -> 'C', "qSin()" -> 'S'
+ if (size >= 2 && (key.at(0) == u'Q' || key.at(0) == u'q')
+ && (key.at(1).isUpper() || key.at(1).isDigit())) {
+ return key.at(1); // "QClass" -> 'C', "qSin()" -> 'S', 'Q3DSurfaceWidget' -> '3'
+ }
if (size >= 3 && key.startsWith("Q_"_L1))
return key.at(2).toUpper(); // "Q_ARG" -> 'A'
if (size >= 4 && key.startsWith("QT_"_L1))
@@ -1564,3 +1566,26 @@ QtXmlToSphinxLink QtDocGenerator::resolveLink(const QtXmlToSphinxLink &link) con
}
return resolved;
}
+
+QtXmlToSphinxDocGeneratorInterface::Image
+ QtDocGenerator::resolveImage(const QString &href, const QString &context) const
+{
+ QString relativeSourceDir = href;
+ const QString source = m_options.parameters.docDataDir + u'/' + relativeSourceDir;
+ if (!QFileInfo::exists(source))
+ throw Exception(msgCannotFindImage(href, context,source));
+
+ // Determine target directory from context, "Pyside2.QtGui.QPainter" ->"Pyside2/QtGui".
+ // FIXME: Not perfect yet, should have knowledge about namespaces (DataVis3D) or
+ // nested classes "Pyside2.QtGui.QTouchEvent.QTouchPoint".
+ QString relativeTargetDir = context;
+ const auto lastDot = relativeTargetDir.lastIndexOf(u'.');
+ if (lastDot != -1)
+ relativeTargetDir.truncate(lastDot);
+ relativeTargetDir.replace(u'.', u'/');
+ if (!relativeTargetDir.isEmpty())
+ relativeTargetDir += u'/';
+ relativeTargetDir += href;
+
+ return {relativeSourceDir, relativeTargetDir};
+}
diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
index 3b1c82e74..56e15e2a1 100644
--- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
+++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
@@ -48,6 +48,7 @@ public:
const QString &methodName) const override;
const QLoggingCategory &loggingCategory() const override;
QtXmlToSphinxLink resolveLink(const QtXmlToSphinxLink &) const override;
+ Image resolveImage(const QString &href, const QString &context) const override;
static QString getFuncName(const AbstractMetaFunctionCPtr &cppFunc);
static QString formatArgs(const AbstractMetaFunctionCPtr &func);
diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp
index 55c1d2090..b8fec836c 100644
--- a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp
+++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp
@@ -1240,36 +1240,17 @@ WebXmlTag QtXmlToSphinx::parentTag() const
// Copy images that are placed in a subdirectory "images" under the webxml files
// by qdoc to a matching subdirectory under the "rst/PySide6/<module>" directory
-static bool copyImage(const QString &href, const QString &docDataDir,
- const QString &context, const QString &outputDir,
+static bool copyImage(const QString &docDataDir, const QString &relativeSourceFile,
+ const QString &outputDir, const QString &relativeTargetFile,
const QLoggingCategory &lc, QString *errorMessage)
{
- const QChar slash = u'/';
- const auto lastSlash = href.lastIndexOf(slash);
- const QString imagePath = lastSlash != -1 ? href.left(lastSlash) : QString();
- const QString imageFileName = lastSlash != -1 ? href.right(href.size() - lastSlash - 1) : href;
- QFileInfo imageSource(docDataDir + slash + href);
- if (!imageSource.exists()) {
- QTextStream(errorMessage) << "Image " << href << " does not exist in "
- << QDir::toNativeSeparators(docDataDir);
- return false;
- }
- // Determine directory from context, "Pyside2.QtGui.QPainter" ->"Pyside2/QtGui".
- // FIXME: Not perfect yet, should have knowledge about namespaces (DataVis3D) or
- // nested classes "Pyside2.QtGui.QTouchEvent.QTouchPoint".
- QString relativeTargetDir = context;
- const auto lastDot = relativeTargetDir.lastIndexOf(u'.');
- if (lastDot != -1)
- relativeTargetDir.truncate(lastDot);
- relativeTargetDir.replace(u'.', slash);
- if (!imagePath.isEmpty())
- relativeTargetDir += slash + imagePath;
-
- const QString targetDir = outputDir + slash + relativeTargetDir;
- const QString targetFileName = targetDir + slash + imageFileName;
+ QString targetFileName = outputDir + u'/' + relativeTargetFile;
if (QFileInfo::exists(targetFileName))
return true;
- if (!QFileInfo::exists(targetDir)) {
+
+ QString relativeTargetDir = relativeTargetFile;
+ relativeTargetDir.truncate(qMax(relativeTargetDir.lastIndexOf(u'/'), qsizetype(0)));
+ if (!relativeTargetDir.isEmpty() && !QFileInfo::exists(outputDir + u'/' + relativeTargetDir)) {
const QDir outDir(outputDir);
if (!outDir.mkpath(relativeTargetDir)) {
QTextStream(errorMessage) << "Cannot create " << QDir::toNativeSeparators(relativeTargetDir)
@@ -1278,28 +1259,29 @@ static bool copyImage(const QString &href, const QString &docDataDir,
}
}
- QFile source(imageSource.absoluteFilePath());
+ QFile source(docDataDir + u'/' + relativeSourceFile);
if (!source.copy(targetFileName)) {
QTextStream(errorMessage) << "Cannot copy " << QDir::toNativeSeparators(source.fileName())
<< " to " << QDir::toNativeSeparators(targetFileName) << ": "
<< source.errorString();
return false;
}
- qCDebug(lc).noquote().nospace() << __FUNCTION__ << " href=\""
- << href << "\", context=\"" << context << "\", docDataDir=\""
- << docDataDir << "\", outputDir=\"" << outputDir << "\", copied \""
- << source.fileName() << "\"->\"" << targetFileName << '"';
+
+ qCDebug(lc).noquote().nospace() << __FUNCTION__ << " \"" << relativeSourceFile
+ << "\"->\"" << relativeTargetFile << '"';
return true;
}
bool QtXmlToSphinx::copyImage(const QString &href) const
{
QString errorMessage;
- const bool result =
- ::copyImage(href, m_parameters.docDataDir, m_context,
- m_parameters.outputDirectory,
- m_generator->loggingCategory(),
- &errorMessage);
+ const auto imagePaths = m_generator->resolveImage(href, m_context);
+ const bool result = ::copyImage(m_parameters.docDataDir,
+ imagePaths.source,
+ m_parameters.outputDirectory,
+ imagePaths.target,
+ m_generator->loggingCategory(),
+ &errorMessage);
if (!result)
throw Exception(errorMessage);
return result;
diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h b/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h
index 16eefad83..d4a098a12 100644
--- a/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h
+++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h
@@ -53,6 +53,15 @@ public:
virtual QtXmlToSphinxLink resolveLink(const QtXmlToSphinxLink &) const = 0;
+ // Resolve images paths relative to doc data directory/output directory.
+ struct Image
+ {
+ QString source;
+ QString target;
+ };
+
+ virtual Image resolveImage(const QString &href, const QString &context) const = 0;
+
virtual ~QtXmlToSphinxDocGeneratorInterface() = default;
};
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
index 84d3c93d3..97a38a08d 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
@@ -59,6 +59,7 @@ using namespace Qt::StringLiterals;
static const char shibokenErrorsOccurred[] = "Shiboken::Errors::occurred() != nullptr";
static constexpr auto virtualMethodStaticReturnVar = "result"_L1;
+static constexpr auto initFuncPrefix = "init_"_L1;
static constexpr auto sbkObjectTypeF = "SbkObject_TypeF()"_L1;
static const char initInheritanceFunction[] = "initInheritance";
@@ -1337,7 +1338,8 @@ void CppGenerator::writeVirtualMethodPythonOverride(TextStream &s,
s << "if (" << PYTHON_RETURN_VAR << ".isNull()) {\n" << indent
<< "// An error happened in python code!\n"
- << "Shiboken::Errors::storeErrorOrPrint();\n"
+ << "Shiboken::Errors::storePythonOverrideErrorOrPrint(\""
+ << func->ownerClass()->name() << "\", funcName);\n"
<< returnStatement.statement << "\n" << outdent
<< "}\n";
@@ -1590,6 +1592,33 @@ void CppGenerator::writeEnumConverterFunctions(TextStream &s, const AbstractMeta
s << '\n';
}
+static void writePointerToPythonConverter(TextStream &c,
+ const AbstractMetaClassCPtr &metaClass,
+ const QString &typeName,
+ const QString &cpythonType)
+{
+ c << "auto *pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppIn));\n"
+ << "if (pyOut) {\n" << indent
+ << "Py_INCREF(pyOut);\nreturn pyOut;\n" << outdent
+ << "}\n";
+
+ const QString nameFunc = metaClass->typeEntry()->polymorphicNameFunction();
+ if (nameFunc.isEmpty() && !metaClass->hasVirtualDestructor()) {
+ c << "return Shiboken::Object::newObjectWithHeuristics("
+ << cpythonType << ", const_cast<void *>(cppIn), false);\n";
+ return;
+ }
+
+ c << "auto *tCppIn = reinterpret_cast<const " << typeName << R"( *>(cppIn);
+const char *typeName = )";
+ if (nameFunc.isEmpty())
+ c << "typeid(*tCppIn).name();\n";
+ else
+ c << nameFunc << "(tCppIn);\n";
+ c << "return Shiboken::Object::newObjectForPointer("
+ << cpythonType << ", const_cast<void *>(cppIn), false, typeName);\n";
+}
+
void CppGenerator::writeConverterFunctions(TextStream &s, const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &classContext) const
{
@@ -1635,26 +1664,7 @@ void CppGenerator::writeConverterFunctions(TextStream &s, const AbstractMetaClas
c << "return PySide::getWrapperForQObject(reinterpret_cast<"
<< typeName << " *>(const_cast<void *>(cppIn)), " << cpythonType << ");\n";
} else {
- c << "auto *pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppIn));\n"
- << "if (pyOut) {\n" << indent
- << "Py_INCREF(pyOut);\nreturn pyOut;\n" << outdent
- << "}\n"
- << "bool exactType = false;\n"
- << "auto *tCppIn = reinterpret_cast<const " << typeName << R"( *>(cppIn);
-const char *typeName = )";
-
- const QString nameFunc = metaClass->typeEntry()->polymorphicNameFunction();
- if (nameFunc.isEmpty())
- c << "typeid(*tCppIn).name();\n";
- else
- c << nameFunc << "(tCppIn);\n";
- c << R"(auto *sbkType = Shiboken::ObjectType::typeForTypeName(typeName);
-if (sbkType != nullptr && Shiboken::ObjectType::hasSpecialCastFunction(sbkType))
- exactType = true;
-)"
- << "PyObject *result = Shiboken::Object::newObject(" << cpythonType
- << R"(, const_cast<void *>(cppIn), false, exactType, typeName);
-return result;)";
+ writePointerToPythonConverter(c, metaClass, typeName, cpythonType);
}
std::swap(targetTypeName, sourceTypeName);
writeCppToPythonFunction(s, c.toString(), sourceTypeName, targetTypeName);
@@ -5096,6 +5106,17 @@ QList<PyMethodDefEntry>
return result;
}
+QString CppGenerator::pythonSignature(const AbstractMetaType &type) const
+{
+ if (type.isSmartPointer() && !type.instantiations().isEmpty()) {
+ const auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(type.typeEntry());
+ const auto instantiationTe = type.instantiations().constFirst().typeEntry();
+ if (auto opt = api().findSmartPointerInstantiation(ste, instantiationTe))
+ return opt->specialized->typeEntry()->qualifiedTargetLangName();
+ }
+ return type.pythonSignature();
+}
+
// Format the type signature of a function parameter
QString CppGenerator::signatureParameter(const AbstractMetaArgument &arg) const
{
@@ -5107,17 +5128,22 @@ QString CppGenerator::signatureParameter(const AbstractMetaArgument &arg) const
metaType = *viewOn;
s << arg.name() << ':';
- QStringList signatures(metaType.pythonSignature());
+ QStringList signatures(pythonSignature(metaType));
// Implicit conversions (C++): Check for converting constructors
// "QColor(Qt::GlobalColor)" or conversion operators
const AbstractMetaFunctionCList conversions =
api().implicitConversions(metaType);
for (const auto &f : conversions) {
- if (f->isConstructor() && !f->arguments().isEmpty())
- signatures << f->arguments().constFirst().type().pythonSignature();
- else if (f->isConversionOperator())
+ if (f->isConstructor() && !f->arguments().isEmpty()) {
+ // PYSIDE-2712: modified types from converting constructors are not always correct
+ // candidates if they are modified by the type system reference
+ if (!f->arguments().constFirst().isTypeModified()) {
+ signatures << pythonSignature(f->arguments().constFirst().type());
+ }
+ } else if (f->isConversionOperator()) {
signatures << f->ownerClass()->fullName();
+ }
}
const qsizetype size = signatures.size();
@@ -5174,7 +5200,7 @@ void CppGenerator::writeSignatureInfo(TextStream &s, const OverloadData &overloa
QString returnType = f->pyiTypeReplaced(0); // pyi or modified type
if (returnType.isEmpty() && !f->isVoid())
- returnType = f->type().pythonSignature();
+ returnType = pythonSignature(f->type());
if (!returnType.isEmpty())
s << "->" << returnType;
@@ -5593,6 +5619,9 @@ void CppGenerator::writeClassRegister(TextStream &s,
writeConverterRegister(s, metaClass, classContext);
s << '\n';
+ if (classContext.forSmartPointer())
+ writeSmartPointerConverterInitialization(s, classContext.preciseType());
+
// class inject-code target/beginning
if (!classTypeEntry->codeSnips().isEmpty()) {
writeClassCodeSnips(s, classTypeEntry->codeSnips(),
@@ -5826,7 +5855,7 @@ void CppGenerator::writeTypeDiscoveryFunction(TextStream &s,
} else if (metaClass->isPolymorphic()) {
const auto &ancestors = metaClass->allTypeSystemAncestors();
for (const auto &ancestor : ancestors) {
- if (ancestor->baseClass())
+ if (ancestor->baseClass() && !ancestor->typeEntry()->isPolymorphicBase())
continue;
if (ancestor->isPolymorphic()) {
s << "if (instanceType == Shiboken::SbkType< " << m_gsp
@@ -6028,16 +6057,20 @@ void CppGenerator::writeNbBoolFunction(const GeneratorContext &context,
// Write declaration and invocation of the init function for the module init
// function.
-void CppGenerator::writeInitFunc(TextStream &declStr, TextStream &callStr,
- const QString &initFunctionName,
- const TypeEntryCPtr &enclosingEntry,
- const QString &pythonName, bool lazy)
+static void writeInitFuncDecl(TextStream &declStr,
+ const QString &functionName)
{
- const QString functionName = "init_"_L1 + initFunctionName;
- const bool hasParent = enclosingEntry && enclosingEntry->type() != TypeEntry::TypeSystemType;
- declStr << "PyTypeObject *" << functionName << "(PyObject *"
- << (hasParent ? "enclosingClass" : "module") << ");\n";
+ declStr << "PyTypeObject *" << functionName << "(PyObject *enclosing);\n";
+}
+// Write declaration and invocation of the init function for the module init
+// function.
+void CppGenerator::writeInitFuncCall(TextStream &callStr,
+ const QString &functionName,
+ const TypeEntryCPtr &enclosingEntry,
+ const QString &pythonName, bool lazy)
+{
+ const bool hasParent = enclosingEntry && enclosingEntry->type() != TypeEntry::TypeSystemType;
if (!lazy) {
const QString enclosing = hasParent
? "reinterpret_cast<PyObject *>("_L1 + cpythonTypeNameExt(enclosingEntry) + u')'
@@ -6046,18 +6079,14 @@ void CppGenerator::writeInitFunc(TextStream &declStr, TextStream &callStr,
} else if (hasParent) {
const QString &enclosingName = enclosingEntry->name();
const auto parts = QStringView{enclosingName}.split(u"::", Qt::SkipEmptyParts);
+ const QString namePathPrefix = enclosingEntry->name().replace("::"_L1, "."_L1);
callStr << "Shiboken::Module::AddTypeCreationFunction("
- << "module, \"" << pythonName << "\", " << functionName << ", \"";
- for (qsizetype i = 0; i < parts.size(); ++i) {
- if (i > 0)
- callStr << "\", \"";
- callStr << parts.at(i);
- }
- callStr << "\");\n";
+ << "module, \"" << parts[0] << "\", "
+ << functionName << ", \"" << namePathPrefix << '.' << pythonName << "\");\n";
} else {
callStr << "Shiboken::Module::AddTypeCreationFunction("
<< "module, \"" << pythonName << "\", "
- << "init_" << initFunctionName << ");\n";
+ << functionName << ");\n";
}
}
@@ -6114,9 +6143,10 @@ bool CppGenerator::finishGeneration()
s_classInitDecl << te->configCondition() << '\n';
s_classPythonDefines << te->configCondition() << '\n';
}
- writeInitFunc(s_classInitDecl, s_classPythonDefines,
- getSimpleClassInitFunctionName(cls),
- targetLangEnclosingEntry(te), cls->name());
+ const QString initFunc = initFuncPrefix + getSimpleClassInitFunctionName(cls);
+ writeInitFuncDecl(s_classInitDecl, initFunc);
+ writeInitFuncCall(s_classPythonDefines, initFunc,
+ targetLangEnclosingEntry(te), cls->name());
if (cls->hasStaticFields()) {
s_classInitDecl << "PyTypeObject *"
<< getSimpleClassStaticFieldsInitFunctionName(cls) << "(PyObject *module);\n";
@@ -6133,13 +6163,12 @@ bool CppGenerator::finishGeneration()
for (const auto &smp : api().instantiatedSmartPointers()) {
GeneratorContext context = contextForSmartPointer(smp.specialized, smp.type);
const auto enclosingClass = context.metaClass()->enclosingClass();
- auto enclosingTypeEntry = enclosingClass
- ? enclosingClass->typeEntry()
- : targetLangEnclosingEntry(smp.type.typeEntry());
+ auto enclosingTypeEntry = targetLangEnclosingEntry(smp.specialized->typeEntry());
- writeInitFunc(s_classInitDecl, s_classPythonDefines,
- getInitFunctionName(context),
- enclosingTypeEntry, smp.type.name());
+ const QString initFunc = initFuncPrefix + getInitFunctionName(context);
+ writeInitFuncDecl(s_classInitDecl, initFunc);
+ writeInitFuncCall(s_classPythonDefines,
+ initFunc, enclosingTypeEntry, smp.specialized->name());
includes.insert(smp.type.instantiations().constFirst().typeEntry()->include());
}
@@ -6333,18 +6362,6 @@ bool CppGenerator::finishGeneration()
s << '\n';
}
- // Implicit smart pointers conversions
- const auto &smartPointersList = api().instantiatedSmartPointers();
- if (!smartPointersList.isEmpty()) {
- s << "// SmartPointers converters.\n\n";
- for (const auto &smp : smartPointersList) {
- s << "// C++ to Python conversion for smart pointer type '"
- << smp.type.cppSignature() << "'.\n";
- writeSmartPointerConverterFunctions(s, smp.type);
- }
- s << '\n';
- }
-
s << "static struct PyModuleDef moduledef = {\n"
<< " /* m_base */ PyModuleDef_HEAD_INIT,\n"
<< " /* m_name */ \"" << moduleName() << "\",\n"
@@ -6403,9 +6420,14 @@ bool CppGenerator::finishGeneration()
s << "{nullptr, nullptr}\n" << outdent << "};\n"
<< "// The new global structure consisting of (type, name) pairs.\n"
- << cppApiVariableName() << " = cppApi;\n"
- << "// The backward compatible alias with upper case indexes.\n"
- << cppApiVariableNameOld() << " = reinterpret_cast<PyTypeObject **>(cppApi);\n\n";
+ << cppApiVariableName() << " = cppApi;\n";
+ if (usePySideExtensions())
+ s << "QT_WARNING_PUSH\nQT_WARNING_DISABLE_DEPRECATED\n";
+ s << "// The backward compatible alias with upper case indexes.\n"
+ << cppApiVariableNameOld() << " = reinterpret_cast<PyTypeObject **>(cppApi);\n";
+ if (usePySideExtensions())
+ s << "QT_WARNING_POP\n";
+ s << '\n';
}
s << "// Create an array of primitive type converters for the current module.\n"
@@ -6454,14 +6476,6 @@ bool CppGenerator::finishGeneration()
s << '\n';
}
- if (!smartPointersList.isEmpty()) {
- s << '\n';
- for (const auto &smp : smartPointersList) {
- writeSmartPointerConverterInitialization(s, smp.type);
- s << '\n';
- }
- }
-
if (!extendedConverters.isEmpty()) {
s << '\n';
for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h
index a31c2ca14..5920c9a3a 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.h
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.h
@@ -60,10 +60,10 @@ private:
void generateIncludes(TextStream &s, const GeneratorContext &classContext,
const IncludeGroupList &includes = {},
const AbstractMetaClassCList &innerClasses = {}) const;
- static void writeInitFunc(TextStream &declStr, TextStream &callStr,
- const QString &initFunctionName,
- const TypeEntryCPtr &enclosingEntry,
- const QString &pythonName, bool lazy = true);
+ static void writeInitFuncCall(TextStream &callStr,
+ const QString &functionName,
+ const TypeEntryCPtr &enclosingEntry,
+ const QString &pythonName, bool lazy = true);
static void writeCacheResetNative(TextStream &s, const GeneratorContext &classContext);
void writeConstructorNative(TextStream &s, const GeneratorContext &classContext,
const AbstractMetaFunctionCPtr &func) const;
@@ -413,6 +413,7 @@ private:
void writeSignatureInfo(TextStream &s, const OverloadData &overloads) const;
QString signatureParameter(const AbstractMetaArgument &arg) const;
+ QString pythonSignature(const AbstractMetaType &type) const;
/// Writes the implementation of all methods part of python sequence protocol
void writeSequenceMethods(TextStream &s,
const AbstractMetaClassCPtr &metaClass,
@@ -550,9 +551,6 @@ private:
static bool hasBoolCast(const AbstractMetaClassCPtr &metaClass)
{ return boolCast(metaClass).has_value(); }
- std::optional<AbstractMetaType>
- findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
- const TypeEntryCPtr &pointee) const;
void clearTpFuncs();
static QString chopType(QString s);
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
index 1b893640a..44b76f181 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
@@ -86,18 +86,6 @@ static ComparisonOperatorList smartPointeeComparisons(const GeneratorContext &co
return result;
}
-std::optional<AbstractMetaType>
- CppGenerator::findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
- const TypeEntryCPtr &pointee) const
-{
- for (const auto &smp : api().instantiatedSmartPointers()) {
- const auto &i = smp.type;
- if (i.typeEntry() == pointer && i.instantiations().at(0).typeEntry() == pointee)
- return i;
- }
- return {};
-}
-
static bool hasParameterPredicate(const AbstractMetaFunctionCPtr &f)
{
return !f->arguments().isEmpty();
@@ -225,6 +213,8 @@ void CppGenerator::generateSmartPointerClass(TextStream &s, const GeneratorConte
s << '\n';
writeConverterFunctions(s, metaClass, classContext);
+ // Implicit smart pointers conversions
+ writeSmartPointerConverterFunctions(s, classContext.preciseType());
writeClassRegister(s, metaClass, classContext, signatureStream);
// class inject-code native/end
@@ -252,8 +242,8 @@ void CppGenerator::writeSmartPointerConverterFunctions(TextStream &s,
for (const auto &base : baseClasses) {
auto baseTe = base->typeEntry();
if (smartPointerTypeEntry->matchesInstantiation(baseTe)) {
- if (auto opt = findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
- const auto smartTargetType = opt.value();
+ if (auto opt = api().findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
+ const auto &smartTargetType = opt.value().type;
s << "// SmartPointer derived class: "
<< smartTargetType.cppSignature() << "\n";
writePythonToCppConversionFunctions(s, smartPointerType,
@@ -308,8 +298,8 @@ void CppGenerator::writeSmartPointerConverterInitialization(TextStream &s,
for (const auto &base : classes) {
auto baseTe = base->typeEntry();
- if (auto opt = findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
- const auto smartTargetType = opt.value();
+ if (auto opt = api().findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
+ const auto &smartTargetType = opt.value().type;
s << "// Convert to SmartPointer derived class: ["
<< smartTargetType.cppSignature() << "]\n";
const QString converter = u"Shiboken::Conversions::getConverter(\""_s
diff --git a/sources/shiboken6/generator/shiboken/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp
index 1f574b47c..7cec9c38e 100644
--- a/sources/shiboken6/generator/shiboken/headergenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp
@@ -198,9 +198,6 @@ void HeaderGenerator::writeWrapperClassDeclaration(TextStream &s,
const auto typeEntry = metaClass->typeEntry();
InheritedOverloadSet inheritedOverloads;
- // write license comment
- s << licenseComment();
-
// Class
s << "class " << wrapperName
<< " : public " << metaClass->qualifiedCppName()
@@ -706,8 +703,12 @@ bool HeaderGenerator::finishGeneration()
macrosStream << ti;
macrosStream << "};\n\n";
+ // FIXME: Remove backwards compatible variable in PySide 7.
macrosStream << "// This variable stores all Python types exported by this module.\n";
macrosStream << "extern Shiboken::Module::TypeInitStruct *" << cppApiVariableName() << ";\n\n";
+ macrosStream << "// This variable stores all Python types exported by this module ";
+ macrosStream << "in a backwards compatible way with identical indexing.\n";
+ macrosStream << "[[deprecated]] extern PyTypeObject **" << cppApiVariableNameOld() << ";\n\n";
macrosStream << "// This variable stores the Python module object exported by this module.\n";
macrosStream << "extern PyObject *" << pythonModuleObjectName() << ";\n\n";
macrosStream << "// This variable stores all type converters exported by this module.\n";
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
index a1417e5d9..67fd9c994 100644
--- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
@@ -2555,7 +2555,8 @@ void ShibokenGenerator::collectFullTypeNamesArray(QStringList &typeNames)
int smartPointerCountIndex = getMaxTypeIndex();
for (const auto &smp : api().instantiatedSmartPointers()) {
auto entry = smp.type.typeEntry();
- typeNames[smartPointerCountIndex] = entry->qualifiedTargetLangName();
+ typeNames[smartPointerCountIndex] =
+ smp.specialized->typeEntry()->qualifiedTargetLangName();
++smartPointerCountIndex;
}
}
diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp
index 1ac65c00c..0ce80d0c6 100644
--- a/sources/shiboken6/libshiboken/basewrapper.cpp
+++ b/sources/shiboken6/libshiboken/basewrapper.cpp
@@ -27,7 +27,9 @@
#include "signature_p.h"
#include "voidptr.h"
+#include <string>
#include <iostream>
+#include <sstream>
#if defined(__APPLE__)
#include <dlfcn.h>
@@ -197,31 +199,6 @@ static PyGetSetDef SbkObjectType_tp_getset[] = {
static PyTypeObject *createObjectTypeType()
{
- // PYSIDE-2676: When using the new type extension, we need to use an
- // extra meta type that provides the extra size.
- // This is a hairy part of Python 3.12 .
- //
- // The problem here is that we use the type extension both in types
- // and also in meta types. This was invisible with extender dicts.
- // Please study carefully:
- // https://docs.python.org/3/c-api/type.html#c.PyType_Spec.basicsize
-
- PyType_Slot SbkObjectTypeMeta_Type_slots[] = {
- {Py_tp_base, static_cast<void *>(&PyType_Type)},
- {Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)},
- {0, nullptr}
- };
-
- PyType_Spec SbkObjectTypeMeta_Type_spec = {
- "1:Shiboken.ObjectTypeMeta",
- -long(sizeof(SbkObjectTypePrivate)),
- 0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined
- Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_TYPE_SUBCLASS,
- SbkObjectTypeMeta_Type_slots,
- };
-
- auto specMeta = &SbkObjectTypeMeta_Type_spec;
-
PyType_Slot SbkObjectType_Type_slots[] = {
{Py_tp_dealloc, reinterpret_cast<void *>(SbkObjectType_tp_dealloc)},
{Py_tp_getattro, reinterpret_cast<void *>(mangled_type_getattro)},
@@ -259,14 +236,9 @@ static PyTypeObject *createObjectTypeType()
SbkObjectType_Type_slots,
};
- if (_PepRuntimeVersion() >= 0x030C00) {
- auto *meta = SbkType_FromSpec(specMeta);
- auto spec = &SbkObjectType_Type_spec_312;
- return SbkType_FromSpecWithMeta(spec, meta);
- }
-
- auto spec = &SbkObjectType_Type_spec;
- return SbkType_FromSpec(spec);
+ return SbkType_FromSpec(_PepRuntimeVersion() >= 0x030C00 ?
+ &SbkObjectType_Type_spec_312 :
+ &SbkObjectType_Type_spec);
}
PyTypeObject *SbkObjectType_TypeF(void)
@@ -801,6 +773,19 @@ namespace Shiboken
void _initMainThreadId(); // helper.cpp
+static std::string msgFailedToInitializeType(const char *description)
+{
+ std::ostringstream stream;
+ stream << "[libshiboken] Failed to initialize " << description;
+ if (auto *error = PepErr_GetRaisedException()) {
+ if (auto *str = PyObject_Str(error))
+ stream << ": " << Shiboken::String::toCString(str);
+ Py_DECREF(error);
+ }
+ stream << '.';
+ return stream.str();
+}
+
namespace Conversions { void init(); }
void init()
@@ -816,11 +801,13 @@ void init()
//Init private data
Pep384_Init();
- if (PyType_Ready(SbkObjectType_TypeF()) < 0)
- Py_FatalError("[libshiboken] Failed to initialize Shiboken.BaseWrapperType metatype.");
+ auto *type = SbkObjectType_TypeF();
+ if (type == nullptr || PyType_Ready(type) < 0)
+ Py_FatalError(msgFailedToInitializeType("Shiboken.BaseWrapperType metatype").c_str());
- if (PyType_Ready(SbkObject_TypeF()) < 0)
- Py_FatalError("[libshiboken] Failed to initialize Shiboken.BaseWrapper type.");
+ type = SbkObject_TypeF();
+ if (type == nullptr || PyType_Ready(type) < 0)
+ Py_FatalError(msgFailedToInitializeType("Shiboken.BaseWrapper type").c_str());
VoidPtr::init();
@@ -1010,8 +997,7 @@ introduceWrapperType(PyObject *enclosingObject,
PyObject *bases,
unsigned wrapperFlags)
{
- const auto basesSize = PySequence_Fast_GET_SIZE(bases);
- assert(basesSize > 0);
+ assert(PySequence_Fast_GET_SIZE(bases) > 0);
typeSpec->slots[0].pfunc = PySequence_Fast_GET_ITEM(bases, 0);
auto *type = SbkType_FromSpecBasesMeta(typeSpec, bases, SbkObjectType_TypeF());
@@ -1085,6 +1071,26 @@ bool hasSpecialCastFunction(PyTypeObject *sbkType)
return d != nullptr && d->mi_specialcast != nullptr;
}
+// Find whether base is a direct single line base class of type
+// (no multiple inheritance), that is, a C++ pointer cast can safely be done.
+static bool isDirectAncestor(PyTypeObject *type, PyTypeObject *base)
+{
+ if (type == base)
+ return true;
+ if (PyTuple_Size(type->tp_bases) == 0)
+ return false;
+ auto *sbkObjectType = SbkObject_TypeF();
+ auto *firstBase = reinterpret_cast<PyTypeObject *>(PyTuple_GetItem(type->tp_bases, 0));
+ return firstBase != sbkObjectType
+ && PyType_IsSubtype(type, sbkObjectType) != 0
+ && isDirectAncestor(firstBase, base);
+}
+
+bool canDowncastTo(PyTypeObject *baseType, PyTypeObject *targetType)
+{
+ return isDirectAncestor(targetType, baseType);
+}
+
} // namespace ObjectType
@@ -1454,25 +1460,67 @@ SbkObject *findColocatedChild(SbkObject *wrapper,
return nullptr;
}
+// Legacy, for compatibility only.
PyObject *newObject(PyTypeObject *instanceType,
void *cptr,
bool hasOwnership,
bool isExactType,
const char *typeName)
{
- // Try to find the exact type of cptr.
- if (!isExactType) {
- if (PyTypeObject *exactType = ObjectType::typeForTypeName(typeName)) {
- instanceType = exactType;
- } else {
- auto resolved = BindingManager::instance().findDerivedType(cptr, instanceType);
- if (resolved.first != nullptr) {
- instanceType = resolved.first;
- cptr = resolved.second;
- }
+ return isExactType
+ ? newObjectForType(instanceType, cptr, hasOwnership)
+ : newObjectWithHeuristics(instanceType, cptr, hasOwnership, typeName);
+}
+
+static PyObject *newObjectWithHeuristicsHelper(PyTypeObject *instanceType,
+ PyTypeObject *exactType,
+ void *cptr,
+ bool hasOwnership)
+{
+ // Try to find the exact type of cptr. For hierarchies with
+ // non-virtual destructors, typeid() will return the base name.
+ // Try type discovery in these cases.
+ if (exactType == nullptr || exactType == instanceType) {
+ auto resolved = BindingManager::instance().findDerivedType(cptr, instanceType);
+ if (resolved.first != nullptr
+ && Shiboken::ObjectType::canDowncastTo(instanceType, resolved.first)) {
+ exactType = resolved.first;
+ cptr = resolved.second;
}
}
+ return newObjectForType(exactType != nullptr ? exactType : instanceType,
+ cptr, hasOwnership);
+}
+
+PyObject *newObjectForPointer(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership,
+ const char *typeName)
+{
+ // Try to find the exact type of cptr.
+ PyTypeObject *exactType = ObjectType::typeForTypeName(typeName);
+ // PYSIDE-868: In case of multiple inheritance, (for example,
+ // a function returning a QPaintDevice * from a QWidget *),
+ // use instance type to avoid pointer offset errors.
+ return exactType != nullptr && !Shiboken::ObjectType::canDowncastTo(instanceType, exactType)
+ ? newObjectForType(instanceType, cptr, hasOwnership)
+ : newObjectWithHeuristicsHelper(instanceType, exactType, cptr, hasOwnership);
+}
+
+
+PyObject *newObjectWithHeuristics(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership,
+ const char *typeName)
+{
+ return newObjectWithHeuristicsHelper(instanceType,
+ ObjectType::typeForTypeName(typeName),
+ cptr, hasOwnership);
+}
+
+PyObject *newObjectForType(PyTypeObject *instanceType, void *cptr, bool hasOwnership)
+{
bool shouldCreate = true;
bool shouldRegister = true;
SbkObject *self = nullptr;
diff --git a/sources/shiboken6/libshiboken/basewrapper.h b/sources/shiboken6/libshiboken/basewrapper.h
index 4835c4810..ec5545aea 100644
--- a/sources/shiboken6/libshiboken/basewrapper.h
+++ b/sources/shiboken6/libshiboken/basewrapper.h
@@ -265,6 +265,14 @@ LIBSHIBOKEN_API PyTypeObject *typeForTypeName(const char *typeName);
* \since 5.12
*/
LIBSHIBOKEN_API bool hasSpecialCastFunction(PyTypeObject *sbkType);
+
+/// Returns whether a C++ pointer of \p baseType can be safely downcast
+/// to \p targetType (base is a direct, single line base class of targetType).
+/// (is a direct, single-line inheritance)
+/// \param baseType Python type of base class
+/// \param targetType Python type of derived class
+/// \since 6.8
+LIBSHIBOKEN_API bool canDowncastTo(PyTypeObject *baseType, PyTypeObject *targetType);
}
namespace Object {
@@ -297,7 +305,8 @@ LIBSHIBOKEN_API SbkObject *findColocatedChild(SbkObject *wrapper,
const PyTypeObject *instanceType);
/**
- * Bind a C++ object to Python.
+ * Bind a C++ object to Python. Forwards to
+ * newObjectWithHeuristics(), newObjectForType() depending on \p isExactType.
* \param instanceType equivalent Python type for the C++ object.
* \param hasOwnership if true, Python will try to delete the underlying C++ object when there's no more refs.
* \param isExactType if false, Shiboken will use some heuristics to detect the correct Python type of this C++
@@ -311,6 +320,40 @@ LIBSHIBOKEN_API PyObject *newObject(PyTypeObject *instanceType,
bool isExactType = false,
const char *typeName = nullptr);
+/// Bind a C++ object to Python for polymorphic pointers. Calls
+/// newObjectWithHeuristics() with an additional check for multiple
+/// inheritance, in which case it will fall back to instanceType.
+/// \param instanceType Equivalent Python type for the C++ object.
+/// \param hasOwnership if true, Python will try to delete the underlying C++ object
+/// when there's no more refs.
+/// \param typeName If non-null, this will be used as helper to find the correct
+/// Python type for this object (obtained by typeid().name().
+LIBSHIBOKEN_API PyObject *newObjectForPointer(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership = true,
+ const char *typeName = nullptr);
+
+/// Bind a C++ object to Python using some heuristics to detect the correct
+/// Python type of this C++ object. In any case \p instanceType must be provided;
+/// it'll be used as search starting point and as fallback.
+/// \param instanceType Equivalent Python type for the C++ object.
+/// \param hasOwnership if true, Python will try to delete the underlying C++ object
+/// C++ object when there are no more references.
+/// when there's no more refs.
+/// \param typeName If non-null, this will be used as helper to find the correct
+/// Python type for this object (obtained by typeid().name().
+LIBSHIBOKEN_API PyObject *newObjectWithHeuristics(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership = true,
+ const char *typeName = nullptr);
+
+/// Bind a C++ object to Python using the given type.
+/// \param instanceType Equivalent Python type for the C++ object.
+/// \param hasOwnership if true, Python will try to delete the underlying
+/// C++ object when there are no more references.
+LIBSHIBOKEN_API PyObject *newObjectForType(PyTypeObject *instanceType,
+ void *cptr, bool hasOwnership = true);
+
/**
* Changes the valid flag of a PyObject, invalid objects will raise an exception when someone tries to access it.
*/
diff --git a/sources/shiboken6/libshiboken/pep384impl.cpp b/sources/shiboken6/libshiboken/pep384impl.cpp
index 4b3759456..5310207a3 100644
--- a/sources/shiboken6/libshiboken/pep384impl.cpp
+++ b/sources/shiboken6/libshiboken/pep384impl.cpp
@@ -105,13 +105,13 @@ static PyType_Spec typeprobe_spec = {
static void
check_PyTypeObject_valid()
{
- auto *obtype = reinterpret_cast<PyObject *>(&PyType_Type);
- auto *probe_tp_base = reinterpret_cast<PyTypeObject *>(
- PyObject_GetAttr(obtype, Shiboken::PyMagicName::base()));
+ auto *typetype = &PyType_Type;
+ auto *obtype = reinterpret_cast<PyObject *>(typetype);
+ auto *probe_tp_base_obj = PyObject_GetAttr(obtype, Shiboken::PyMagicName::base());
+ auto *probe_tp_base = reinterpret_cast<PyTypeObject *>(probe_tp_base_obj);
auto *probe_tp_bases = PyObject_GetAttr(obtype, Shiboken::PyMagicName::bases());
- auto *check = reinterpret_cast<PyTypeObject *>(
- PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases));
- auto *typetype = reinterpret_cast<PyTypeObject *>(obtype);
+ auto *checkObj = PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases);
+ auto *check = reinterpret_cast<PyTypeObject *>(checkObj);
PyObject *w = PyObject_GetAttr(obtype, Shiboken::PyMagicName::weakrefoffset());
long probe_tp_weakrefoffset = PyLong_AsLong(w);
PyObject *d = PyObject_GetAttr(obtype, Shiboken::PyMagicName::dictoffset());
@@ -149,8 +149,8 @@ check_PyTypeObject_valid()
|| probe_tp_mro != typetype->tp_mro
|| Py_TPFLAGS_DEFAULT != (check->tp_flags & Py_TPFLAGS_DEFAULT))
Py_FatalError("The structure of type objects has changed!");
- Py_DECREF(check);
- Py_DECREF(probe_tp_base);
+ Py_DECREF(checkObj);
+ Py_DECREF(probe_tp_base_obj);
Py_DECREF(w);
Py_DECREF(d);
Py_DECREF(probe_tp_bases);
@@ -482,6 +482,47 @@ Pep_GetVerboseFlag()
}
#endif // Py_LIMITED_API
+// Support for pyerrors.h
+
+#if defined(Py_LIMITED_API) || PY_VERSION_HEX < 0x030C0000
+// Emulate PyErr_GetRaisedException() using the deprecated PyErr_Fetch()/PyErr_Store()
+PyObject *PepErr_GetRaisedException()
+{
+ PyObject *type{};
+ PyObject *value{};
+ PyObject *traceback{};
+ PyErr_Fetch(&type, &value, &traceback);
+ Py_XINCREF(value);
+ PyErr_Restore(type, value, traceback);
+ return value;
+}
+
+struct PepException_HEAD
+{
+ PyObject_HEAD
+ PyObject *x1; // dict
+ PyObject *args;
+};
+
+// PyException_GetArgs/PyException_SetArgs were added to the stable API in 3.12
+PyObject *PepException_GetArgs(PyObject *ex)
+{
+ auto *h = reinterpret_cast<PepException_HEAD *>(ex);
+ Py_XINCREF(h->args);
+ return h->args;
+}
+
+LIBSHIBOKEN_API void PepException_SetArgs(PyObject *ex, PyObject *args)
+{
+ auto *h = reinterpret_cast<PepException_HEAD *>(ex);
+ Py_XINCREF(args);
+ auto *old = h->args; // Py_XSETREF()
+ h->args = args;
+ Py_XDECREF(old);
+
+}
+#endif // Limited or < 3.12
+
/*****************************************************************************
*
* Support for code.h
@@ -722,11 +763,8 @@ PyTypeObject *PepStaticMethod_TypePtr = nullptr;
static PyTypeObject *
getStaticMethodType(void)
{
- // this works for Python 3, only
- // "StaticMethodType = type(str.__dict__['maketrans'])\n";
static const char prog[] =
- "from xxsubtype import spamlist\n"
- "result = type(spamlist.__dict__['staticmeth'])\n";
+ "result = type(str.__dict__['maketrans'])\n";
return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
}
@@ -1009,9 +1047,12 @@ long _PepRuntimeVersion()
SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type)
{
+ // PYSIDE-2676: Use the meta type explicitly.
+ // A derived type would fail the offset calculation.
+ static auto *meta = SbkObjectType_TypeF();
assert(SbkObjectType_Check(type));
auto *obType = reinterpret_cast<PyObject *>(type);
- void *data = PyObject_GetTypeData(obType, Py_TYPE(obType));
+ void *data = PyObject_GetTypeData(obType, meta);
return reinterpret_cast<SbkObjectTypePrivate *>(data);
}
@@ -1061,11 +1102,12 @@ static thread_local SbkObjectTypePrivate *SOTP_value{};
SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type)
{
+ static auto *meta = SbkObjectType_TypeF();
static bool use_312 = _PepRuntimeVersion() >= 0x030C00;
assert(SbkObjectType_Check(type));
if (use_312) {
auto *obType = reinterpret_cast<PyObject *>(type);
- void *data = PepObject_GetTypeData(obType, Py_TYPE(obType));
+ void *data = PepObject_GetTypeData(obType, meta);
return reinterpret_cast<SbkObjectTypePrivate *>(data);
}
if (type == SOTP_key)
diff --git a/sources/shiboken6/libshiboken/pep384impl.h b/sources/shiboken6/libshiboken/pep384impl.h
index ec58aac81..7188366e2 100644
--- a/sources/shiboken6/libshiboken/pep384impl.h
+++ b/sources/shiboken6/libshiboken/pep384impl.h
@@ -188,6 +188,17 @@ LIBSHIBOKEN_API int Pep_GetFlag(const char *name);
LIBSHIBOKEN_API int Pep_GetVerboseFlag(void);
#endif
+// pyerrors.h
+#if defined(Py_LIMITED_API) || PY_VERSION_HEX < 0x030C0000
+LIBSHIBOKEN_API PyObject *PepErr_GetRaisedException();
+LIBSHIBOKEN_API PyObject *PepException_GetArgs(PyObject *ex);
+LIBSHIBOKEN_API void PepException_SetArgs(PyObject *ex, PyObject *args);
+#else
+# define PepErr_GetRaisedException PyErr_GetRaisedException
+# define PepException_GetArgs PyException_GetArgs
+# define PepException_SetArgs PyException_SetArgs
+#endif
+
/*****************************************************************************
*
* RESOLVED: unicodeobject.h
diff --git a/sources/shiboken6/libshiboken/sbkcontainer.h b/sources/shiboken6/libshiboken/sbkcontainer.h
index 240c772a9..8ad5aadc6 100644
--- a/sources/shiboken6/libshiboken/sbkcontainer.h
+++ b/sources/shiboken6/libshiboken/sbkcontainer.h
@@ -74,10 +74,9 @@ public:
static PyObject *tpNewInvalid(PyTypeObject * /* subtype */, PyObject * /* args */, PyObject * /* kwds */)
{
- PyErr_Format(PyExc_NotImplementedError,
+ return PyErr_Format(PyExc_NotImplementedError,
"Opaque containers of type '%s' cannot be instantiated.",
typeid(SequenceContainer).name());
- return nullptr;
}
static int tpInit(PyObject * /* self */, PyObject * /* args */, PyObject * /* kwds */)
@@ -105,10 +104,8 @@ public:
static PyObject *sqGetItem(PyObject *self, Py_ssize_t i)
{
auto *d = get(self);
- if (i < 0 || i >= Py_ssize_t(d->m_list->size())) {
- PyErr_SetString(PyExc_IndexError, "index out of bounds");
- return nullptr;
- }
+ if (i < 0 || i >= Py_ssize_t(d->m_list->size()))
+ return PyErr_Format(PyExc_IndexError, "index out of bounds");
auto it = std::cbegin(*d->m_list);
std::advance(it, i);
return ShibokenContainerValueConverter<value_type>::convertValueToPython(*it);
@@ -133,14 +130,10 @@ public:
static PyObject *push_back(PyObject *self, PyObject *pyArg)
{
auto *d = get(self);
- if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg)) {
- PyErr_SetString(PyExc_TypeError, "wrong type passed to append.");
- return nullptr;
- }
- if (d->m_const) {
- PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
- return nullptr;
- }
+ if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg))
+ return PyErr_Format(PyExc_TypeError, "wrong type passed to append.");
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
if (!value.has_value())
@@ -152,14 +145,10 @@ public:
static PyObject *push_front(PyObject *self, PyObject *pyArg)
{
auto *d = get(self);
- if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg)) {
- PyErr_SetString(PyExc_TypeError, "wrong type passed to append.");
- return nullptr;
- }
- if (d->m_const) {
- PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
- return nullptr;
- }
+ if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg))
+ return PyErr_Format(PyExc_TypeError, "wrong type passed to append.");
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
if (!value.has_value())
@@ -171,10 +160,8 @@ public:
static PyObject *clear(PyObject *self)
{
auto *d = get(self);
- if (d->m_const) {
- PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
- return nullptr;
- }
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
d->m_list->clear();
Py_RETURN_NONE;
@@ -183,10 +170,8 @@ public:
static PyObject *pop_back(PyObject *self)
{
auto *d = get(self);
- if (d->m_const) {
- PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
- return nullptr;
- }
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
d->m_list->pop_back();
Py_RETURN_NONE;
@@ -195,10 +180,8 @@ public:
static PyObject *pop_front(PyObject *self)
{
auto *d = get(self);
- if (d->m_const) {
- PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
- return nullptr;
- }
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
d->m_list->pop_front();
Py_RETURN_NONE;
@@ -208,21 +191,16 @@ public:
static PyObject *reserve(PyObject *self, PyObject *pyArg)
{
auto *d = get(self);
- if (PyLong_Check(pyArg) == 0) {
- PyErr_SetString(PyExc_TypeError, "wrong type passed to reserve().");
- return nullptr;
- }
- if (d->m_const) {
- PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
- return nullptr;
- }
+ if (PyLong_Check(pyArg) == 0)
+ return PyErr_Format(PyExc_TypeError, "wrong type passed to reserve().");
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
if constexpr (ShibokenContainerHasReserve<SequenceContainer>::value) {
const Py_ssize_t size = PyLong_AsSsize_t(pyArg);
d->m_list->reserve(size);
} else {
- PyErr_SetString(PyExc_TypeError, "Container does not support reserve().");
- return nullptr;
+ return PyErr_Format(PyExc_TypeError, "Container does not support reserve().");
}
Py_RETURN_NONE;
diff --git a/sources/shiboken6/libshiboken/sbkconverter.cpp b/sources/shiboken6/libshiboken/sbkconverter.cpp
index 358827aa8..9ab674415 100644
--- a/sources/shiboken6/libshiboken/sbkconverter.cpp
+++ b/sources/shiboken6/libshiboken/sbkconverter.cpp
@@ -12,7 +12,12 @@
#include "voidptr.h"
#include <string>
+#include <cstring>
+#include <iostream>
#include <unordered_map>
+#include <unordered_set>
+#include <map>
+#include <set>
static SbkConverter **PrimitiveTypeConverters;
@@ -72,6 +77,103 @@ void init()
initArrayConverters();
}
+static void dumpPyTypeObject(std::ostream &str, PyTypeObject *t)
+{
+ str << "\nPython type ";
+ if (t == nullptr) {
+ str << "<None>";
+ return;
+ }
+ str << '"' << t->tp_name << '"';
+ if (t->tp_base != nullptr && t->tp_base != &PyBaseObject_Type)
+ str << '(' << t->tp_base->tp_name << ')';
+}
+
+static void dumpSbkConverter(std::ostream &str, const SbkConverter *c)
+{
+ str << "SbkConverter " << static_cast<const void *>(c) << ": ";
+ if (c->pointerToPython != nullptr)
+ str << ", C++ pointer->Python";
+ if (c->copyToPython != nullptr)
+ str << ", copy->Python";
+ if (c->toCppPointerConversion.second != nullptr)
+ str << ", Python->C++ pointer";
+ if (!c->toCppConversions.empty())
+ str << ", " << c->toCppConversions.size() << " Python->C++ conversions";
+}
+
+// Less than operator for a PyTypeObject for dumping the converter map
+static bool pyTypeObjectLessThan(const PyTypeObject *t1, const PyTypeObject *t2)
+{
+ const bool isNull1 = t1 == nullptr;
+ const bool isNull2 = t2 == nullptr;
+ if (isNull1 || isNull2)
+ return isNull1 && !isNull2;
+ // Internal types (lower case) first
+ const bool isInternal1 = std::islower(t1->tp_name[0]);
+ const bool isInternal2 = std::islower(t2->tp_name[0]);
+ if (isInternal1 != isInternal2)
+ return !isInternal2;
+ return std::strcmp(t1->tp_name, t2->tp_name) < 0;
+}
+
+void dumpConverters()
+{
+ struct PyTypeObjectLess {
+
+ bool operator()(const PyTypeObject *t1, const PyTypeObject *t2) const {
+ return pyTypeObjectLessThan(t1, t2);
+ }
+ };
+
+ using StringSet = std::set<std::string>;
+ using SbkConverterNamesMap = std::unordered_map<SbkConverter *, StringSet>;
+ using PyTypeObjectConverterMap = std::map<PyTypeObject *, SbkConverterNamesMap,
+ PyTypeObjectLess>;
+
+ auto &str = std::cerr;
+
+ // Sort the entries by the associated PyTypeObjects and converters
+ PyTypeObjectConverterMap pyTypeObjectConverterMap;
+ for (const auto &converter : converters) {
+ auto *sbkConverter = converter.second;
+ if (sbkConverter == nullptr) {
+ str << "Non-existent: \"" << converter.first << "\"\n";
+ continue;
+ }
+ auto *typeObject = sbkConverter->pythonType;
+ auto typeIt = pyTypeObjectConverterMap.find(typeObject);
+ if (typeIt == pyTypeObjectConverterMap.end())
+ typeIt = pyTypeObjectConverterMap.insert(std::make_pair(typeObject,
+ SbkConverterNamesMap{})).first;
+ SbkConverterNamesMap &sbkConverterMap = typeIt->second;
+ auto convIt = sbkConverterMap.find(sbkConverter);
+ if (convIt == sbkConverterMap.end())
+ convIt = sbkConverterMap.insert(std::make_pair(sbkConverter,
+ StringSet{})).first;
+ convIt->second.insert(converter.first);
+ }
+
+ for (const auto &tc : pyTypeObjectConverterMap) {
+ dumpPyTypeObject(str, tc.first);
+ str << ", " << tc.second.size() << " converter(s):\n";
+ for (const auto &cn : tc.second) {
+ str << " ";
+ dumpSbkConverter(str, cn.first);
+ str << ", " << cn.second.size() << " alias(es):";
+ int i = 0;
+ for (const auto &name : cn.second) {
+ if ((i++ % 5) == 0)
+ str << "\n ";
+ str << " \"" << name << '"';
+ }
+ str << '\n';
+ }
+ }
+
+ str << '\n';
+}
+
SbkConverter *createConverterObject(PyTypeObject *type,
PythonToCppFunc toCppPointerConvFunc,
IsConvertibleToCppFunc toCppPointerCheckFunc,
@@ -422,18 +524,36 @@ void registerConverterName(SbkConverter *converter, const char *typeName)
converters.insert(std::make_pair(typeName, converter));
}
-static std::string getRealTypeName(const char *name)
+static std::string getRealTypeName(const std::string &typeName)
{
- std::string typeName(name);
auto size = typeName.size();
if (std::isalnum(typeName[size - 1]) == 0)
return typeName.substr(0, size - 1);
return typeName;
}
-SbkConverter *getConverter(const char *typeName)
+// PYSIDE-2404: Build a negative cache of already failed lookups.
+// The resulting list must be reset after each new import,
+// because that can change results. Also clear the cache after
+// reaching some threashold.
+static std::unordered_set<std::string> nonExistingTypeNames{};
+
+// Arbitrary size limit to prevent random name overflows.
+static constexpr std::size_t negativeCacheLimit = 50;
+
+static void rememberAsNonexistent(const std::string &typeName)
+{
+ if (nonExistingTypeNames.size() > negativeCacheLimit)
+ clearNegativeLazyCache();
+ converters.insert(std::make_pair(typeName, nullptr));
+ nonExistingTypeNames.insert(typeName);
+}
+
+SbkConverter *getConverter(const char *typeNameC)
{
+ std::string typeName = typeNameC;
auto it = converters.find(typeName);
+ // PYSIDE-2404: This can also contain explicit nullptr as a negative cache.
if (it != converters.end())
return it->second;
// PYSIDE-2404: Did not find the name. Load the lazy classes
@@ -442,6 +562,9 @@ SbkConverter *getConverter(const char *typeName)
it = converters.find(typeName);
if (it != converters.end())
return it->second;
+ // Cache the negative result. Don't forget to clear the cache for new modules.
+ rememberAsNonexistent(typeName);
+
if (Shiboken::pyVerbose() > 0) {
const std::string message =
std::string("Can't find type resolver for type '") + typeName + "'.";
@@ -450,6 +573,15 @@ SbkConverter *getConverter(const char *typeName)
return nullptr;
}
+void clearNegativeLazyCache()
+{
+ for (const auto &typeName : nonExistingTypeNames) {
+ auto it = converters.find(typeName);
+ converters.erase(it);
+ }
+ nonExistingTypeNames.clear();
+}
+
SbkConverter *primitiveTypeConverter(int index)
{
return PrimitiveTypeConverters[index];
@@ -704,14 +836,7 @@ PyTypeObject *getPythonTypeObject(const SbkConverter *converter)
PyTypeObject *getPythonTypeObject(const char *typeName)
{
- auto *type = getPythonTypeObject(getConverter(typeName));
- if (type == nullptr) {
- // PYSIDE-2404: Did not find the name. Load the lazy classes
- // which have this name and try again.
- Shiboken::Module::loadLazyClassesWithName(getRealTypeName(typeName).c_str());
- type = getPythonTypeObject(getConverter(typeName));
- }
- return type;
+ return getPythonTypeObject(getConverter(typeName));
}
bool pythonTypeIsValueType(const SbkConverter *converter)
diff --git a/sources/shiboken6/libshiboken/sbkconverter_p.h b/sources/shiboken6/libshiboken/sbkconverter_p.h
index c886c9b9f..08fc4c8e1 100644
--- a/sources/shiboken6/libshiboken/sbkconverter_p.h
+++ b/sources/shiboken6/libshiboken/sbkconverter_p.h
@@ -531,6 +531,12 @@ SbkConverter *createConverterObject(PyTypeObject *type,
IsConvertibleToCppFunc toCppPointerCheckFunc,
CppToPythonFunc pointerToPythonFunc,
CppToPythonFunc copyToPythonFunc);
+
+LIBSHIBOKEN_API void dumpConverters();
+
+/// Interface for sbkmodule which must reset cache when new module is loaded.
+LIBSHIBOKEN_API void clearNegativeLazyCache();
+
} // namespace Shiboken::Conversions
#endif // SBK_CONVERTER_P_H
diff --git a/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp b/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp
index 44e900f01..7637efa70 100644
--- a/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp
+++ b/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp
@@ -49,17 +49,17 @@ PyObject *createByteArray1(Py_ssize_t, const uint8_t *)
PyObject *createDoubleArray1(Py_ssize_t, const double *)
{
- return Py_None;
+ Py_RETURN_NONE;
}
PyObject *createFloatArray1(Py_ssize_t, const float *)
{
- return Py_None;
+ Py_RETURN_NONE;
}
PyObject *createIntArray1(Py_ssize_t, const int *)
{
- return Py_None;
+ Py_RETURN_NONE;
}
#endif // !HAVE_NUMPY
diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp
index d39369979..4c0597bda 100644
--- a/sources/shiboken6/libshiboken/sbkenum.cpp
+++ b/sources/shiboken6/libshiboken/sbkenum.cpp
@@ -3,6 +3,7 @@
#include "sbkenum.h"
#include "sbkstring.h"
+#include "helper.h"
#include "sbkstaticstrings.h"
#include "sbkstaticstrings_p.h"
#include "sbkconverter.h"
@@ -306,6 +307,8 @@ static PyTypeObject *createEnumForPython(PyObject *scopeOrModule,
enumName = PyDict_GetItem(sotp->enumTypeDict, name);
}
+ SBK_UNUSED(getPyEnumMeta()); // enforce PyEnumModule creation
+ assert(PyEnumModule != nullptr);
AutoDecRef PyEnumType(PyObject_GetAttr(PyEnumModule, enumName));
assert(PyEnumType.object());
bool isFlag = PyObject_IsSubclass(PyEnumType, PyFlag);
diff --git a/sources/shiboken6/libshiboken/sbkerrors.cpp b/sources/shiboken6/libshiboken/sbkerrors.cpp
index 1832624d5..84c080f8d 100644
--- a/sources/shiboken6/libshiboken/sbkerrors.cpp
+++ b/sources/shiboken6/libshiboken/sbkerrors.cpp
@@ -6,6 +6,11 @@
#include "helper.h"
#include "gilstate.h"
+#include <cstdio>
+#include <string>
+
+using namespace std::literals::string_literals;
+
namespace Shiboken
{
@@ -93,6 +98,21 @@ void setWrongContainerType()
PyErr_SetString(PyExc_TypeError, "Wrong type passed to container conversion.");
}
+// Prepend something to an exception message provided it is a single string
+// argument.
+static bool prependToExceptionMessage(PyObject *exc, const char *context)
+{
+ Shiboken::AutoDecRef args(PepException_GetArgs(exc));
+ if (args.isNull() || PyTuple_Check(args.object()) == 0 || PyTuple_Size(args) != 1)
+ return false;
+ auto *oldMessage = PyTuple_GetItem(args, 0);
+ if (oldMessage == nullptr || PyUnicode_CheckExact(oldMessage) == 0)
+ return false;
+ auto *newMessage = PyUnicode_FromFormat("%s%U", context, oldMessage);
+ PepException_SetArgs(exc, PyTuple_Pack(1, newMessage));
+ return true;
+}
+
struct ErrorStore {
PyObject *type;
PyObject *exc;
@@ -101,17 +121,42 @@ struct ErrorStore {
static thread_local ErrorStore savedError{};
+static bool hasPythonContext()
+{
+ return _pythonContextStack & 1;
+}
+
void storeErrorOrPrint()
{
// This error happened in a function with no way to return an error state.
// Therefore, we handle the error when we are error checking, anyway.
// But we do that only when we know that an error handler can pick it up.
- if (_pythonContextStack & 1)
+ if (hasPythonContext())
PyErr_Fetch(&savedError.type, &savedError.exc, &savedError.traceback);
else
PyErr_Print();
}
+// Like storeErrorOrPrint() with additional context info that is prepended
+// to the exception message or printed.
+static void storeErrorOrPrintWithContext(const char *context)
+{
+ if (hasPythonContext()) {
+ PyErr_Fetch(&savedError.type, &savedError.exc, &savedError.traceback);
+ prependToExceptionMessage(savedError.exc, context);
+ } else {
+ std::fputs(context, stderr);
+ PyErr_Print();
+ }
+}
+
+void storePythonOverrideErrorOrPrint(const char *className, const char *funcName)
+{
+ const std::string context = "Error calling Python override of "s
+ + className + "::"s + funcName + "(): "s;
+ storeErrorOrPrintWithContext(context.c_str());
+}
+
PyObject *occurred()
{
if (savedError.type) {
diff --git a/sources/shiboken6/libshiboken/sbkerrors.h b/sources/shiboken6/libshiboken/sbkerrors.h
index 6ff85f8e1..18ce701e7 100644
--- a/sources/shiboken6/libshiboken/sbkerrors.h
+++ b/sources/shiboken6/libshiboken/sbkerrors.h
@@ -50,6 +50,11 @@ LIBSHIBOKEN_API void setWrongContainerType();
/// This replaces `PyErr_Print`, which cannot report errors as exception.
/// To be used in contexts where raising errors is impossible.
LIBSHIBOKEN_API void storeErrorOrPrint();
+
+/// Call storeErrorOrPrint() and print the context to report
+/// errors when calling Python overrides of virtual functions.
+LIBSHIBOKEN_API void storePythonOverrideErrorOrPrint(const char *className, const char *funcName);
+
/// Handle an error as in PyErr_Occurred(), but also check for errors which
/// were captured by `storeErrorOrPrint`.
/// To be used in normal error checks.
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
index f31b8f4f7..971835c53 100644
--- a/sources/shiboken6/libshiboken/sbkfeature_base.cpp
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
@@ -92,8 +92,12 @@ void disassembleFrame(const char *marker)
PyErr_Restore(error_type, error_value, error_traceback);
}
-// python 3.12
-static int const CALL = 171;
+// Python 3.13
+static int const LOAD_ATTR_313 = 82;
+static int const CALL_313 = 53;
+static int const PUSH_NULL_313 = 34;
+// Python 3.12
+static int const CALL_312 = 171;
// Python 3.11
static int const PRECALL = 166;
// we have "big instructions" with gaps after them
@@ -105,13 +109,16 @@ static int const LOAD_METHOD = 160;
static int const CALL_METHOD = 161;
// Python 3.6
static int const CALL_FUNCTION = 131;
-static int const LOAD_ATTR = 106;
+static int const LOAD_ATTR_312 = 106;
// NoGil (how long will this exist in this form?)
static int const LOAD_METHOD_NOGIL = 55;
static int const CALL_METHOD_NOGIL = 72;
static bool currentOpcode_Is_CallMethNoArgs()
{
+ static auto number = _PepRuntimeVersion();
+ static int LOAD_ATTR = number < 0x030D00 ? LOAD_ATTR_312 : LOAD_ATTR_313;
+ static int CALL = number < 0x030D00 ? CALL_312 : CALL_313;
// PYSIDE-2221: Special case for the NoGil version:
// Find out if we have such a version.
// We could also ask the variable `Py_NOGIL`.
@@ -148,7 +155,6 @@ static bool currentOpcode_Is_CallMethNoArgs()
}
uint8_t opcode2 = co_code[f_lasti + 2];
uint8_t oparg2 = co_code[f_lasti + 3];
- static auto number = _PepRuntimeVersion();
if (number < 0x030B00)
return opcode1 == LOAD_METHOD && opcode2 == CALL_METHOD && oparg2 == 0;
@@ -158,7 +164,7 @@ static bool currentOpcode_Is_CallMethNoArgs()
// don't need to take care of them.
if (opcode1 == LOAD_METHOD)
f_lasti += LOAD_METHOD_GAP_311;
- else if (opcode1 == LOAD_ATTR)
+ else if (opcode1 == LOAD_ATTR_312)
f_lasti += LOAD_ATTR_GAP_311;
else
return false;
@@ -176,6 +182,11 @@ static bool currentOpcode_Is_CallMethNoArgs()
else
return false;
+ if (number >= 0x030D00) {
+ int opcode3 = co_code[f_lasti + 2];
+ if (opcode3 == PUSH_NULL_313)
+ f_lasti += 2;
+ }
opcode2 = co_code[f_lasti + 2];
oparg2 = co_code[f_lasti + 3];
diff --git a/sources/shiboken6/libshiboken/sbkmodule.cpp b/sources/shiboken6/libshiboken/sbkmodule.cpp
index 4153df27f..a94fbe279 100644
--- a/sources/shiboken6/libshiboken/sbkmodule.cpp
+++ b/sources/shiboken6/libshiboken/sbkmodule.cpp
@@ -7,21 +7,27 @@
#include "bindingmanager.h"
#include "sbkstring.h"
#include "sbkcppstring.h"
+#include "sbkconverter_p.h"
#include <unordered_map>
#include <unordered_set>
+#include <vector>
#include <cstring>
+/// This hash maps module objects to arrays of converters.
+using ModuleConvertersMap = std::unordered_map<PyObject *, SbkConverter **> ;
+
/// This hash maps module objects to arrays of Python types.
using ModuleTypesMap = std::unordered_map<PyObject *, Shiboken::Module::TypeInitStruct *> ;
-/// This hash maps module objects to arrays of converters.
-using ModuleConvertersMap = std::unordered_map<PyObject *, SbkConverter **>;
+struct TypeCreationStruct
+{
+ Shiboken::Module::TypeCreationFunction func;
+ std::vector<std::string> subtypeNames;
+};
-/// This hash maps type names to type creation functions.
-using TypeCreationFunctionModulePair =
- std::pair<Shiboken::Module::TypeCreationFunction, PyObject *>;
-using NameToTypeFunctionMap = std::unordered_map<std::string, TypeCreationFunctionModulePair>;
+/// This hash maps type names to type creation structs.
+using NameToTypeFunctionMap = std::unordered_map<std::string, TypeCreationStruct> ;
/// This hash maps module objects to maps of names to functions.
using ModuleToFuncsMap = std::unordered_map<PyObject *, NameToTypeFunctionMap> ;
@@ -56,8 +62,8 @@ LIBSHIBOKEN_API PyTypeObject *get(TypeInitStruct &typeStruct)
AutoDecRef modName(String::fromCppStringView(names.substr(0, dotPos)));
auto *modOrType = PyDict_GetItem(sysModules, modName);
if (modOrType == nullptr) {
- PyErr_Format(PyExc_SystemError, "Module %s should already be in sys.modules",
- PyModule_GetName(modOrType));
+ PyErr_Format(PyExc_SystemError, "Module \"%U\" should already be in sys.modules",
+ modName.object());
return nullptr;
}
@@ -74,6 +80,39 @@ LIBSHIBOKEN_API PyTypeObject *get(TypeInitStruct &typeStruct)
return typeStruct.type;
}
+static void incarnateHelper(PyObject *module, const std::string_view names,
+ const NameToTypeFunctionMap &nameToFunc)
+{
+ auto dotPos = names.find('.');
+ std::string::size_type startPos = 0;
+ auto *modOrType{module};
+ while (dotPos != std::string::npos) {
+ auto typeName = names.substr(startPos, dotPos - startPos);
+ AutoDecRef obTypeName(String::fromCppStringView(typeName));
+ modOrType = PyObject_GetAttr(modOrType, obTypeName);
+ startPos = dotPos + 1;
+ dotPos = names.find('.', startPos);
+ }
+ // now we have the type to create.
+ auto funcIter = nameToFunc.find(std::string(names));
+ // - call this function that returns a PyTypeObject
+ auto tcStruct = funcIter->second;
+ auto initFunc = tcStruct.func;
+ PyTypeObject *type = initFunc(modOrType);
+ auto name = names.substr(startPos);
+ PyObject_SetAttrString(modOrType, name.data(), reinterpret_cast<PyObject *>(type));
+}
+
+static void incarnateSubtypes(PyObject *module,
+ const std::vector<std::string> &nameList,
+ NameToTypeFunctionMap &nameToFunc)
+{
+ for (auto const & tableIter : nameList) {
+ std::string_view names(tableIter);
+ incarnateHelper(module, names, nameToFunc);
+ }
+}
+
static PyTypeObject *incarnateType(PyObject *module, const char *name,
NameToTypeFunctionMap &nameToFunc)
{
@@ -85,13 +124,15 @@ static PyTypeObject *incarnateType(PyObject *module, const char *name,
return nullptr;
}
// - call this function that returns a PyTypeObject
- auto pair = funcIter->second;
- auto initFunc = pair.first;
- auto *modOrType = pair.second;
+ auto tcStruct = funcIter->second;
+ auto initFunc = tcStruct.func;
+ auto *modOrType{module};
// PYSIDE-2404: Make sure that no switching happens during type creation.
auto saveFeature = initSelectableFeature(nullptr);
PyTypeObject *type = initFunc(modOrType);
+ if (!tcStruct.subtypeNames.empty())
+ incarnateSubtypes(module, tcStruct.subtypeNames, nameToFunc);
initSelectableFeature(saveFeature);
// - assign this object to the name in the module
@@ -164,7 +205,7 @@ static PyObject *PyModule_lazyGetAttro(PyObject *module, PyObject *name)
// - locate the name and retrieve the generating function
const char *attrNameStr = Shiboken::String::toCString(name);
auto &nameToFunc = tableIter->second;
- // - create the real type (incarnateType checks this)
+ // - create the real type and handle subtypes
auto *type = incarnateType(module, attrNameStr, nameToFunc);
auto *ret = reinterpret_cast<PyObject *>(type);
// - if attribute does really not exist use the original
@@ -172,7 +213,6 @@ static PyObject *PyModule_lazyGetAttro(PyObject *module, PyObject *name)
PyErr_Clear();
return origModuleGetattro(module, name);
}
-
return ret;
}
@@ -208,6 +248,9 @@ static PyMethodDef module_methods[] = {
// Python 3.8 - 3.12
static int const LOAD_CONST_312 = 100;
static int const IMPORT_NAME_312 = 108;
+// Python 3.13
+static int const LOAD_CONST_313 = 83;
+static int const IMPORT_NAME_313 = 75;
static bool isImportStar(PyObject *module)
{
@@ -220,6 +263,9 @@ static bool isImportStar(PyObject *module)
static PyObject *const _co_consts = Shiboken::String::createStaticString("co_consts");
static PyObject *const _co_names = Shiboken::String::createStaticString("co_names");
+ static int LOAD_CONST = _PepRuntimeVersion() < 0x030D00 ? LOAD_CONST_312 : LOAD_CONST_313;
+ static int IMPORT_NAME = _PepRuntimeVersion() < 0x030D00 ? IMPORT_NAME_312 : IMPORT_NAME_313;
+
auto *obFrame = reinterpret_cast<PyObject *>(PyEval_GetFrame());
if (obFrame == nullptr)
return true; // better assume worst-case.
@@ -239,7 +285,7 @@ static bool isImportStar(PyObject *module)
PyBytes_AsStringAndSize(dec_co_code, &co_code, &code_len);
uint8_t opcode2 = co_code[f_lasti];
uint8_t opcode1 = co_code[f_lasti - 2];
- if (opcode1 == LOAD_CONST_312 && opcode2 == IMPORT_NAME_312) {
+ if (opcode1 == LOAD_CONST && opcode2 == IMPORT_NAME) {
uint8_t oparg1 = co_code[f_lasti - 1];
uint8_t oparg2 = co_code[f_lasti + 1];
AutoDecRef dec_co_consts(PyObject_GetAttr(dec_f_code, _co_consts));
@@ -260,8 +306,6 @@ static bool isImportStar(PyObject *module)
// PYSIDE-2404: These modules produce ambiguous names which we cannot handle, yet.
static std::unordered_set<std::string> dontLazyLoad{
- "sample",
- "smart",
"testbinding"
};
@@ -292,24 +336,22 @@ static bool shouldLazyLoad(PyObject *module)
return std::strncmp(modName, "PySide6.", 8) == 0;
}
-void AddTypeCreationFunction(PyObject *module,
- const char *name,
- TypeCreationFunction func)
+static int lazyLoadDefault()
{
- static const char *flag = getenv("PYSIDE6_OPTION_LAZY");
- static const int value = flag != nullptr ? std::atoi(flag) : 1;
+#ifndef PYPY_VERSION
+ int result = 1;
+#else
+ int result = 0;
+#endif
+ if (auto *flag = getenv("PYSIDE6_OPTION_LAZY"))
+ result = std::atoi(flag);
+ return result;
+}
- // - locate the module in the moduleTofuncs mapping
- auto tableIter = moduleToFuncs.find(module);
- assert(tableIter != moduleToFuncs.end());
- // - Assign the name/generating function pair.
- auto &nameToFunc = tableIter->second;
- TypeCreationFunctionModulePair pair{func, module};
- auto nit = nameToFunc.find(name);
- if (nit == nameToFunc.end())
- nameToFunc.insert(std::make_pair(name, pair));
- else
- nit->second = pair;
+void checkIfShouldLoadImmediately(PyObject *module, const std::string &name,
+ const NameToTypeFunctionMap &nameToFunc)
+{
+ static const int value = lazyLoadDefault();
// PYSIDE-2404: Lazy Loading
//
@@ -319,56 +361,56 @@ void AddTypeCreationFunction(PyObject *module,
// 3 - lazy loading for any module.
//
// By default we lazy load all known modules (option = 1).
-
if (value == 0 // completely disabled
|| canNotLazyLoad(module) // for some reason we cannot lazy load
|| (value == 1 && !shouldLazyLoad(module)) // not a known module
) {
- PyTypeObject *type = func(module);
- PyModule_AddObject(module, name, reinterpret_cast<PyObject *>(type)); // steals reference
+ incarnateHelper(module, name, nameToFunc);
}
}
void AddTypeCreationFunction(PyObject *module,
const char *name,
- TypeCreationFunction func,
- const char *containerName)
+ TypeCreationFunction func)
{
- // This version could be delayed as well, but for the few cases
- // we simply fetch the container type and insert directly.
- AutoDecRef obContainerType(PyObject_GetAttrString(module, containerName));
- PyTypeObject *type = func(obContainerType);
- PyObject_SetAttrString(obContainerType, name, reinterpret_cast<PyObject *>(type)); // steals reference
-}
+ // - locate the module in the moduleTofuncs mapping
+ auto tableIter = moduleToFuncs.find(module);
+ assert(tableIter != moduleToFuncs.end());
+ // - Assign the name/generating function tcStruct.
+ auto &nameToFunc = tableIter->second;
+ TypeCreationStruct tcStruct{func, {}};
+ auto nit = nameToFunc.find(name);
+ if (nit == nameToFunc.end())
+ nameToFunc.insert(std::make_pair(name, tcStruct));
+ else
+ nit->second = tcStruct;
-void AddTypeCreationFunction(PyObject *module,
- const char *name,
- TypeCreationFunction func,
- const char *outerContainerName,
- const char *innerContainerName)
-{
- // This version has even more indirection. It is very rare, and
- // we handle it directly.
- AutoDecRef obOuterType(PyObject_GetAttrString(module, outerContainerName));
- AutoDecRef obInnerType(PyObject_GetAttrString(obOuterType, innerContainerName));
- PyTypeObject *type = func(obInnerType);
- PyObject_SetAttrString(obInnerType, name, reinterpret_cast<PyObject *>(type)); // steals reference
+ checkIfShouldLoadImmediately(module, name, nameToFunc);
}
void AddTypeCreationFunction(PyObject *module,
- const char *name,
+ const char *containerName,
TypeCreationFunction func,
- const char *containerName3,
- const char *containerName2,
- const char *containerName)
+ const char *namePath)
{
- // This version has even mode indirection. It is very rare, and
- // we handle it directly.
- AutoDecRef obContainerType3(PyObject_GetAttrString(module, containerName3));
- AutoDecRef obContainerType2(PyObject_GetAttrString(obContainerType3, containerName2));
- AutoDecRef obContainerType(PyObject_GetAttrString(obContainerType2, containerName));
- PyTypeObject *type = func(obContainerType);
- PyObject_SetAttrString(obContainerType, name, reinterpret_cast<PyObject *>(type)); // steals reference
+ // - locate the module in the moduleTofuncs mapping
+ auto tableIter = moduleToFuncs.find(module);
+ assert(tableIter != moduleToFuncs.end());
+ // - Assign the name/generating function tcStruct.
+ auto &nameToFunc = tableIter->second;
+ auto nit = nameToFunc.find(containerName);
+
+ // - insert namePath into the subtype vector of the main type.
+ nit->second.subtypeNames.push_back(namePath);
+ // - insert it also as its own entry.
+ nit = nameToFunc.find(namePath);
+ TypeCreationStruct tcStruct{func, {}};
+ if (nit == nameToFunc.end())
+ nameToFunc.insert(std::make_pair(namePath, tcStruct));
+ else
+ nit->second = tcStruct;
+
+ checkIfShouldLoadImmediately(module, namePath, nameToFunc);
}
PyObject *import(const char *moduleName)
@@ -441,11 +483,11 @@ PyObject *create(const char * /* modName */, void *moduleData)
// Install the getattr patch.
origModuleGetattro = PyModule_Type.tp_getattro;
PyModule_Type.tp_getattro = PyModule_lazyGetAttro;
- // Add the lazy import redirection.
+ // Add the lazy import redirection, keeping a reference.
origImportFunc = PyDict_GetItemString(builtins, "__import__");
- auto *func = PyCFunction_NewEx(lazy_methods, nullptr, nullptr);
+ Py_INCREF(origImportFunc);
+ AutoDecRef func(PyCFunction_NewEx(lazy_methods, nullptr, nullptr));
PyDict_SetItemString(builtins, "__import__", func);
- // Everything is set.
lazy_init = true;
}
// PYSIDE-2404: Nuitka inserts some additional code in standalone mode
@@ -455,6 +497,8 @@ PyObject *create(const char * /* modName */, void *moduleData)
// into `sys.modules`. This can cause a race condition.
// Insert the module early into the module dict to prevend recursion.
PyDict_SetItemString(sysModules, PyModule_GetName(module), module);
+ // Clear the non-existing name cache because we have a new module.
+ Shiboken::Conversions::clearNegativeLazyCache();
return module;
}
diff --git a/sources/shiboken6/libshiboken/sbkmodule.h b/sources/shiboken6/libshiboken/sbkmodule.h
index 1b3de33b7..2c407e09d 100644
--- a/sources/shiboken6/libshiboken/sbkmodule.h
+++ b/sources/shiboken6/libshiboken/sbkmodule.h
@@ -56,18 +56,6 @@ LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
TypeCreationFunction func,
const char *containerName);
-LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
- const char *name,
- TypeCreationFunction func,
- const char *outerContainerName,
- const char *innerContainerName);
-
-LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
- const char *name,
- TypeCreationFunction func,
- const char *containerName3,
- const char *containerName2,
- const char *containerName);
/**
* Registers the list of types created by \p module.
* \param module Module where the types were created.
diff --git a/sources/shiboken6/libshiboken/sbknumpy.cpp b/sources/shiboken6/libshiboken/sbknumpy.cpp
index 2e1c64d73..b6422e73f 100644
--- a/sources/shiboken6/libshiboken/sbknumpy.cpp
+++ b/sources/shiboken6/libshiboken/sbknumpy.cpp
@@ -29,10 +29,8 @@ static void initNumPy()
// Expanded from macro "import_array" in __multiarray_api.h
// Make sure to read about the magic defines PY_ARRAY_UNIQUE_SYMBOL etc.,
// when changing this or spreading the code over several source files.
- if (_import_array() < 0) {
+ if (_import_array() < 0)
PyErr_Print();
- PyErr_Clear();
- }
}
#endif // HAVE_NUMPY
diff --git a/sources/shiboken6/libshiboken/sbkstring.cpp b/sources/shiboken6/libshiboken/sbkstring.cpp
index 1471cd7fe..b5e87ca5a 100644
--- a/sources/shiboken6/libshiboken/sbkstring.cpp
+++ b/sources/shiboken6/libshiboken/sbkstring.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "sbkstring.h"
+#include "sbkenum.h"
#include "sbkstaticstrings_p.h"
#include "autodecref.h"
@@ -14,6 +15,11 @@ bool checkIterable(PyObject *obj)
return PyObject_HasAttr(obj, Shiboken::PyMagicName::iter());
}
+bool checkIterableArgument(PyObject *obj)
+{
+ return checkIterable(obj) && !Shiboken::Enum::check(obj);
+}
+
static PyObject *initPathLike()
{
PyObject *PathLike{};
diff --git a/sources/shiboken6/libshiboken/sbkstring.h b/sources/shiboken6/libshiboken/sbkstring.h
index f91847c11..ebc5428c7 100644
--- a/sources/shiboken6/libshiboken/sbkstring.h
+++ b/sources/shiboken6/libshiboken/sbkstring.h
@@ -13,6 +13,8 @@ namespace String
{
LIBSHIBOKEN_API bool check(PyObject *obj);
LIBSHIBOKEN_API bool checkIterable(PyObject *obj);
+ /// Check for iterable function arguments (excluding enumerations)
+ LIBSHIBOKEN_API bool checkIterableArgument(PyObject *obj);
LIBSHIBOKEN_API bool checkPath(PyObject *path);
LIBSHIBOKEN_API bool checkType(PyTypeObject *obj);
LIBSHIBOKEN_API bool checkChar(PyObject *obj);
diff --git a/sources/shiboken6/libshiboken/voidptr.cpp b/sources/shiboken6/libshiboken/voidptr.cpp
index 7045b08b1..8bb3f6ac8 100644
--- a/sources/shiboken6/libshiboken/voidptr.cpp
+++ b/sources/shiboken6/libshiboken/voidptr.cpp
@@ -156,10 +156,9 @@ PyObject *SbkVoidPtrObject_int(PyObject *v)
PyObject *toBytes(PyObject *self, PyObject * /* args */)
{
auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(self);
- if (sbkObject->size < 0) {
- PyErr_SetString(PyExc_IndexError, "VoidPtr does not have a size set.");
- return nullptr;
- }
+ if (sbkObject->size < 0)
+ return PyErr_Format(PyExc_IndexError, "VoidPtr does not have a size set.");
+
PyObject *bytes = PyBytes_FromStringAndSize(reinterpret_cast<const char *>(sbkObject->cptr),
sbkObject->size);
Py_XINCREF(bytes);
diff --git a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp
index b3adfe78b..5c6219885 100644
--- a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp
+++ b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp
@@ -100,6 +100,10 @@ const bool ok = Shiboken::BindingManager::instance().dumpTypeGraph(%1);
Shiboken::BindingManager::instance().dumpWrapperMap();
// @snippet dumpwrappermap
+// @snippet dumpconverters
+Shiboken::Conversions::dumpConverters();
+// @snippet dumpconverters
+
// @snippet init
// Add __version__ and __version_info__ attributes to the module
PyObject* version = PyTuple_New(5);
diff --git a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml
index aa08a8bbf..acb522ecc 100644
--- a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml
+++ b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml
@@ -57,9 +57,14 @@
<inject-code file="shibokenmodule.cpp" snippet="dumpwrappermap"/>
</add-function>
+ <add-function signature="dumpConverters()">
+ <inject-code file="shibokenmodule.cpp" snippet="dumpconverters"/>
+ </add-function>
+
<extra-includes>
<include file-name="sbkversion.h" location="local"/>
<include file-name="voidptr.h" location="local"/>
+ <include file-name="sbkconverter_p.h" location="local"/>
</extra-includes>
<inject-code position="end" file="shibokenmodule.cpp" snippet="init"/>
</typesystem>
diff --git a/sources/shiboken6/tests/libother/othermultiplederived.h b/sources/shiboken6/tests/libother/othermultiplederived.h
index a8e265388..9f90c43a7 100644
--- a/sources/shiboken6/tests/libother/othermultiplederived.h
+++ b/sources/shiboken6/tests/libother/othermultiplederived.h
@@ -6,11 +6,12 @@
#include "libothermacros.h"
#include "multiple_derived.h"
+#include "objecttype.h"
#include "virtualmethods.h"
class ObjectType;
-class LIBOTHER_API OtherMultipleDerived : public MDerived1
+class LIBOTHER_API OtherMultipleDerived : public OtherBase, public MDerived1
{
public:
// this will use CppCopier from other module (bug#142)
diff --git a/sources/shiboken6/tests/libsample/derived.h b/sources/shiboken6/tests/libsample/derived.h
index b7736c37a..cf95cb601 100644
--- a/sources/shiboken6/tests/libsample/derived.h
+++ b/sources/shiboken6/tests/libsample/derived.h
@@ -26,7 +26,7 @@ public:
public:
void uselessMethod() {}
SomeInnerClass operator+(const SomeInnerClass &other) { return other; }
- bool operator==(const SomeInnerClass &) { return true; }
+ bool operator==(const SomeInnerClass &) const { return true; }
};
explicit Derived(int id = -1) noexcept;
diff --git a/sources/shiboken6/tests/libsample/point.cpp b/sources/shiboken6/tests/libsample/point.cpp
index b8630eb1e..0a28e877f 100644
--- a/sources/shiboken6/tests/libsample/point.cpp
+++ b/sources/shiboken6/tests/libsample/point.cpp
@@ -34,7 +34,7 @@ void Point::show() const
std::cout << "(x: " << m_x << ", y: " << m_y << ")";
}
-bool Point::operator==(const Point &other)
+bool Point::operator==(const Point &other) const
{
return m_x == other.m_x && m_y == other.m_y;
}
diff --git a/sources/shiboken6/tests/libsample/point.h b/sources/shiboken6/tests/libsample/point.h
index 59e0236d5..7e5d128ab 100644
--- a/sources/shiboken6/tests/libsample/point.h
+++ b/sources/shiboken6/tests/libsample/point.h
@@ -38,7 +38,7 @@ public:
// The != operator is not implemented for the purpose of testing
// for the absense of the __ne__ method in the Python binding.
- bool operator==(const Point &other);
+ bool operator==(const Point &other) const;
Point operator+(const Point &other);
Point operator-(const Point &other);
diff --git a/sources/shiboken6/tests/libsample/pointf.cpp b/sources/shiboken6/tests/libsample/pointf.cpp
index 6b39f73a9..736a5c6b5 100644
--- a/sources/shiboken6/tests/libsample/pointf.cpp
+++ b/sources/shiboken6/tests/libsample/pointf.cpp
@@ -26,7 +26,7 @@ void PointF::show() const
std::cout << "(x: " << m_x << ", y: " << m_y << ")";
}
-bool PointF::operator==(const PointF &other)
+bool PointF::operator==(const PointF &other) const
{
return m_x == other.m_x && m_y == other.m_y;
}
diff --git a/sources/shiboken6/tests/libsample/pointf.h b/sources/shiboken6/tests/libsample/pointf.h
index bb50b5c6d..49e009467 100644
--- a/sources/shiboken6/tests/libsample/pointf.h
+++ b/sources/shiboken6/tests/libsample/pointf.h
@@ -31,7 +31,7 @@ public:
// The != operator is not implemented for the purpose of testing
// for the absence of the __ne__ method in the Python binding.
- bool operator==(const PointF &other);
+ bool operator==(const PointF &other) const;
PointF operator+(const PointF &other);
PointF operator-(const PointF &other);
diff --git a/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp
index a7b73cc81..472f807f2 100644
--- a/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp
+++ b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp
@@ -51,6 +51,46 @@ void StdSharedPtrTestBench::printInt(const std::shared_ptr<int> &p)
std::cerr << '\n';
}
+std::shared_ptr<double> StdSharedPtrTestBench::createDouble(double v)
+{
+ return std::make_shared<double>(v);
+}
+
+std::shared_ptr<double> StdSharedPtrTestBench::createNullDouble()
+{
+ return {};
+}
+
+void StdSharedPtrTestBench::printDouble(const std::shared_ptr<double> &p)
+{
+ std::cerr << __FUNCTION__ << ' ';
+ if (p.get())
+ std::cerr << *p;
+ else
+ std::cerr << "nullptr";
+ std::cerr << '\n';
+}
+
+std::shared_ptr<std::string> StdSharedPtrTestBench::createString(const char *text)
+{
+ return std::make_shared<std::string>(text);
+}
+
+std::shared_ptr<std::string> StdSharedPtrTestBench::createNullString()
+{
+ return {};
+}
+
+void StdSharedPtrTestBench::printString(const std::shared_ptr<std::string> &p)
+{
+ std::cerr << __FUNCTION__ << ' ';
+ if (p.get())
+ std::cerr << '"' << *p << '"';
+ else
+ std::cerr << "nullptr";
+ std::cerr << '\n';
+}
+
StdSharedPtrVirtualMethodTester::StdSharedPtrVirtualMethodTester() = default;
StdSharedPtrVirtualMethodTester::~StdSharedPtrVirtualMethodTester() = default;
diff --git a/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h
index 8991cded6..9d4c207b5 100644
--- a/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h
+++ b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h
@@ -7,6 +7,7 @@
#include "libsmartmacros.h"
#include <memory>
+#include <string>
class Integer;
@@ -23,6 +24,14 @@ public:
static std::shared_ptr<int> createInt(int v = 42);
static std::shared_ptr<int> createNullInt();
static void printInt(const std::shared_ptr<int> &);
+
+ static std::shared_ptr<double> createDouble(double v = 42);
+ static std::shared_ptr<double> createNullDouble();
+ static void printDouble(const std::shared_ptr<double> &);
+
+ static std::shared_ptr<std::string> createString(const char *text);
+ static std::shared_ptr<std::string> createNullString();
+ static void printString(const std::shared_ptr<std::string> &);
};
class LIB_SMART_API StdSharedPtrVirtualMethodTester
diff --git a/sources/shiboken6/tests/otherbinding/typediscovery_test.py b/sources/shiboken6/tests/otherbinding/typediscovery_test.py
index 791d3bdce..39dc5cf0f 100644
--- a/sources/shiboken6/tests/otherbinding/typediscovery_test.py
+++ b/sources/shiboken6/tests/otherbinding/typediscovery_test.py
@@ -13,7 +13,8 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
from shiboken_paths import init_paths
init_paths()
-from sample import Abstract, Base1, Derived
+from sample import (Abstract, Base1, Derived,
+ MDerived1, SonOfMDerived1, MDerived3)
from other import OtherMultipleDerived
@@ -32,14 +33,18 @@ class TypeDiscoveryTest(unittest.TestCase):
def testMultipleInheritance(self):
obj = OtherMultipleDerived.createObject("Base1")
self.assertEqual(type(obj), Base1)
- # PYSIDE-868: In case of multiple inheritance, a factory
- # function will return the base class wrapper.
+ # PYSIDE-868: In case of single line direct inheritance,
+ # a factory function will return the class wrapper
+ # of the derived class.
obj = OtherMultipleDerived.createObject("MDerived1")
- self.assertEqual(type(obj), Base1)
+ self.assertEqual(type(obj), MDerived1)
obj = OtherMultipleDerived.createObject("SonOfMDerived1")
- self.assertEqual(type(obj), Base1)
+ self.assertEqual(type(obj), SonOfMDerived1)
obj = OtherMultipleDerived.createObject("MDerived3")
- self.assertEqual(type(obj), Base1)
+ self.assertEqual(type(obj), MDerived3)
+ # PYSIDE-868: OtherMultipleDerived inherits
+ # OtherBase, Base1. In this case, a factory
+ # function will return the base class wrapper.
obj = OtherMultipleDerived.createObject("OtherMultipleDerived")
self.assertEqual(type(obj), Base1)
diff --git a/sources/shiboken6/tests/qtxmltosphinx/main.cpp b/sources/shiboken6/tests/qtxmltosphinx/main.cpp
index 27aaee7d1..5b0624376 100644
--- a/sources/shiboken6/tests/qtxmltosphinx/main.cpp
+++ b/sources/shiboken6/tests/qtxmltosphinx/main.cpp
@@ -40,6 +40,7 @@ public:
const QString &) const override;
const QLoggingCategory &loggingCategory() const override;
QtXmlToSphinxLink resolveLink(const QtXmlToSphinxLink &link) const override;
+ Image resolveImage(const QString &href, const QString &) const;
};
// QtXmlToSphinxDocGeneratorInterface
@@ -63,11 +64,18 @@ const QLoggingCategory &QtXmlToSphinxDocGenerator::loggingCategory() const
return lcQtXmlToSphinx();
}
-QtXmlToSphinxLink QtXmlToSphinxDocGenerator::resolveLink(const QtXmlToSphinxLink &link) const
+QtXmlToSphinxLink
+ QtXmlToSphinxDocGenerator::resolveLink(const QtXmlToSphinxLink &link) const
{
return link;
}
+QtXmlToSphinxDocGeneratorInterface::Image
+ QtXmlToSphinxDocGenerator::resolveImage(const QString &href, const QString &) const
+{
+ return {href, href};
+}
+
static bool run(const QString &fileName)
{
QtXmlToSphinxDocGenerator generator;
diff --git a/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp
index 45cecd1a1..3ba77196f 100644
--- a/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp
+++ b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp
@@ -39,6 +39,12 @@ QtXmlToSphinxLink QtXmlToSphinxTest::resolveLink(const QtXmlToSphinxLink &link)
return link;
}
+QtXmlToSphinxDocGeneratorInterface::Image
+ QtXmlToSphinxTest::resolveImage(const QString &href, const QString &) const
+{
+ return {href, href};
+}
+
QString QtXmlToSphinxTest::transformXml(const QString &xml) const
{
return QtXmlToSphinx(this, m_parameters, xml).result();
diff --git a/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h
index 0a210b7a0..5108ef452 100644
--- a/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h
+++ b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h
@@ -19,6 +19,7 @@ public:
const QString &) const override;
const QLoggingCategory &loggingCategory() const override;
QtXmlToSphinxLink resolveLink(const QtXmlToSphinxLink &link) const override;
+ Image resolveImage(const QString &href, const QString &context) const override;
private slots:
void testTable_data();
diff --git a/sources/shiboken6/tests/smartbinding/CMakeLists.txt b/sources/shiboken6/tests/smartbinding/CMakeLists.txt
index 2e729321e..594744840 100644
--- a/sources/shiboken6/tests/smartbinding/CMakeLists.txt
+++ b/sources/shiboken6/tests/smartbinding/CMakeLists.txt
@@ -18,8 +18,10 @@ ${CMAKE_CURRENT_BINARY_DIR}/smart/smart_integer2_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/smart/sharedptr_integer2_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/smart/stdsharedptrtestbench_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/smart/stdsharedptrvirtualmethodtester_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_double_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_integer_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_int_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_std_string_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/smart/std_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/smart/std_optional_int_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/smart/std_optional_integer_wrapper.cpp
diff --git a/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py b/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py
index 2e6aea3d9..a37a307a5 100644
--- a/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py
+++ b/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py
@@ -10,7 +10,7 @@ from pathlib import Path
sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
from shiboken_paths import init_paths
init_paths()
-from smart import Integer, StdSharedPtrTestBench, StdSharedPtrVirtualMethodTester, std
+from smart import Integer, StdDoublePtr, StdSharedPtrTestBench, StdSharedPtrVirtualMethodTester, std
def call_func_on_ptr(ptr):
@@ -49,6 +49,24 @@ class StdSharedPtrTests(unittest.TestCase):
self.assertFalse(np)
p = StdSharedPtrTestBench.createInt()
StdSharedPtrTestBench.printInt(p)
+ ip = std.StdIntPtr(42)
+ StdSharedPtrTestBench.printInt(ip)
+
+ def testDouble(self):
+ np = StdSharedPtrTestBench.createNullDouble()
+ StdSharedPtrTestBench.printDouble(np)
+ self.assertFalse(np)
+ p = StdSharedPtrTestBench.createDouble(67)
+ StdSharedPtrTestBench.printDouble(p)
+ dp = StdDoublePtr(42)
+ StdSharedPtrTestBench.printDouble(dp)
+
+ def testString(self):
+ np = StdSharedPtrTestBench.createNullString()
+ StdSharedPtrTestBench.printString(np)
+ self.assertFalse(np)
+ p = StdSharedPtrTestBench.createString("bla")
+ StdSharedPtrTestBench.printString(p)
def testVirtuals(self):
"""Test whether code generating virtual function overrides is generated
diff --git a/sources/shiboken6/tests/smartbinding/typesystem_smart.xml b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml
index 261d5f15d..e479e4ddf 100644
--- a/sources/shiboken6/tests/smartbinding/typesystem_smart.xml
+++ b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml
@@ -50,7 +50,7 @@
value-check-method="operator bool"
ref-count-method="use_count"
reset-method="reset"
- instantiations="Integer,int">
+ instantiations="Integer,int=StdIntPtr,double=::StdDoublePtr,std::string">
<include file-name="memory" location="global"/>
</smart-pointer-type>