diff options
| author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2024-12-04 12:27:33 +0100 |
|---|---|---|
| committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2024-12-09 15:08:12 +0100 |
| commit | 206b907dec8e6feddb495ca177ca20fd446efddc (patch) | |
| tree | b35aca3af55a80405ca815fa8f33f79878f8fb1d | |
| parent | 3da05cc765ab16b3622e2262022a40aa92fc0334 (diff) | |
Fix crash instantiating smart pointer types
For a smart pointer to a derived class, the smart pointer to the base
class needs to be generated first for the conversion to the base class
to work.
Topologically sort instantiated smart pointers by base classes.
Fixes: PYSIDE-2946
Task-number: PYSIDE-454
Pick-to: 6.8
Change-Id: If7be39e72312f8fe61ef7fbc0b351e070894d22e
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
| -rw-r--r-- | sources/shiboken6/ApiExtractor/apiextractor.cpp | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/sources/shiboken6/ApiExtractor/apiextractor.cpp b/sources/shiboken6/ApiExtractor/apiextractor.cpp index 847377332..f3d9d0b58 100644 --- a/sources/shiboken6/ApiExtractor/apiextractor.cpp +++ b/sources/shiboken6/ApiExtractor/apiextractor.cpp @@ -11,6 +11,7 @@ #include "abstractmetalang.h" #include "codesnip.h" #include "exception.h" +#include "graph.h" #include "messages.h" #include "modifications.h" #include "optionsparser.h" @@ -401,6 +402,48 @@ bool ApiExtractorPrivate::runHelper(ApiExtractorFlags flags) return result; } +static qsizetype indexOfPointee(const InstantiatedSmartPointers &instantiatedList, + const AbstractMetaClassCPtr &pointee) +{ + for (qsizetype i = 0, size = instantiatedList.size(); i < size; ++i) { + if (instantiatedList.at(i).pointee == pointee) + return i; + } + return -1; +} + +// Sort the list of instantiated smart pointers such that base classes go before +// descendant classes since those register conversions to smart_ptr<base> for +// which the base definition needs to exist (PYSIDE-2946). +static InstantiatedSmartPointers + topologicalSortSmartPointers(const InstantiatedSmartPointers &instantiatedList) +{ + const auto size = instantiatedList.size(); + if (size < 2) + return instantiatedList; + + // Create a graph (using int indexes for sorting) with dependency edges for the inheritance + // within the pointee classes list. + Graph<InstantiatedSmartPointer> graph(instantiatedList); + for (qsizetype i = 0; i < size; ++i) { + const auto &smp = instantiatedList.at(i); + if (smp.pointee) { + for (const auto &base : smp.pointee->baseClasses()) { + const auto baseIndex = indexOfPointee(instantiatedList, base); + if (baseIndex != -1) + graph.addEdgeByIndexes(baseIndex, i); + } + } + } + + const auto sortedGraphResult = graph.topologicalSort(); + // Should not really fail since it is only by base classes ATM... + if (!sortedGraphResult.isValid()) + throw Exception("Failed to sort the list of instantiated smart pointers (cyclic dependency?)"_L1); + + return sortedGraphResult.result; +} + static inline void classListToCList(const AbstractMetaClassList &list, AbstractMetaClassCList *target) { target->reserve(list.size()); @@ -430,7 +473,8 @@ std::optional<ApiExtractorResult> ApiExtractor::run(ApiExtractorFlags flags) if (instantiationTe->isComplex()) smp.pointee = AbstractMetaClass::findClass(result.m_metaClasses, instantiationTe); } - qSwap(result.m_instantiatedSmartPointers, collectContext.instantiatedSmartPointers); + result.m_instantiatedSmartPointers = + topologicalSortSmartPointers(collectContext.instantiatedSmartPointers); return result; } |
