aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6')
-rw-r--r--sources/shiboken6/.cmake.conf5
-rw-r--r--sources/shiboken6/.gitattributes2
-rw-r--r--sources/shiboken6/.gitignore8
-rw-r--r--sources/shiboken6/AUTHORS12
-rw-r--r--sources/shiboken6/ApiExtractor/AUTHORS8
-rw-r--r--sources/shiboken6/ApiExtractor/CMakeLists.txt138
-rw-r--r--sources/shiboken6/ApiExtractor/COPYING342
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetaargument.cpp201
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetaargument.h66
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp3749
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.h152
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp202
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h254
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetaenum.cpp423
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetaenum.h125
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetafield.cpp254
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetafield.h88
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetafunction.cpp1707
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetafunction.h487
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang.cpp1983
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang.h393
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang_enums.h50
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang_helpers.h35
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h36
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetatype.cpp1120
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetatype.h276
-rw-r--r--sources/shiboken6/ApiExtractor/addedfunction.cpp216
-rw-r--r--sources/shiboken6/ApiExtractor/addedfunction.h113
-rw-r--r--sources/shiboken6/ApiExtractor/addedfunction_p.h45
-rw-r--r--sources/shiboken6/ApiExtractor/anystringview_helpers.cpp56
-rw-r--r--sources/shiboken6/ApiExtractor/anystringview_helpers.h18
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractor.cpp849
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractor.h87
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractorflags.h18
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractorresult.cpp103
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractorresult.h81
-rw-r--r--sources/shiboken6/ApiExtractor/arraytypeentry.h28
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp1296
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangbuilder.h37
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.cpp175
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.h26
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp323
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangparser.h88
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangutils.cpp320
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangutils.h108
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp456
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/compilersupport.h56
-rw-r--r--sources/shiboken6/ApiExtractor/classdocumentation.cpp381
-rw-r--r--sources/shiboken6/ApiExtractor/classdocumentation.h82
-rw-r--r--sources/shiboken6/ApiExtractor/cmake_uninstall.cmake24
-rw-r--r--sources/shiboken6/ApiExtractor/codesnip.cpp78
-rw-r--r--sources/shiboken6/ApiExtractor/codesnip.h107
-rw-r--r--sources/shiboken6/ApiExtractor/codesniphelpers.cpp77
-rw-r--r--sources/shiboken6/ApiExtractor/codesniphelpers.h17
-rw-r--r--sources/shiboken6/ApiExtractor/complextypeentry.h179
-rw-r--r--sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp211
-rw-r--r--sources/shiboken6/ApiExtractor/conditionalstreamreader.h90
-rw-r--r--sources/shiboken6/ApiExtractor/configurabletypeentry.h28
-rw-r--r--sources/shiboken6/ApiExtractor/constantvaluetypeentry.h23
-rw-r--r--sources/shiboken6/ApiExtractor/containertypeentry.h63
-rw-r--r--sources/shiboken6/ApiExtractor/customconversion.cpp197
-rw-r--r--sources/shiboken6/ApiExtractor/customconversion.h81
-rw-r--r--sources/shiboken6/ApiExtractor/customconversion_typedefs.h14
-rw-r--r--sources/shiboken6/ApiExtractor/customtypenentry.h30
-rw-r--r--sources/shiboken6/ApiExtractor/debughelpers_p.h56
-rw-r--r--sources/shiboken6/ApiExtractor/dependency.h22
-rw-r--r--sources/shiboken6/ApiExtractor/docparser.cpp232
-rw-r--r--sources/shiboken6/ApiExtractor/docparser.h125
-rw-r--r--sources/shiboken6/ApiExtractor/documentation.cpp65
-rw-r--r--sources/shiboken6/ApiExtractor/documentation.h65
-rw-r--r--sources/shiboken6/ApiExtractor/dotview.cpp58
-rw-r--r--sources/shiboken6/ApiExtractor/dotview.h14
-rw-r--r--sources/shiboken6/ApiExtractor/doxygenparser.cpp224
-rw-r--r--sources/shiboken6/ApiExtractor/doxygenparser.h18
-rw-r--r--sources/shiboken6/ApiExtractor/enclosingclassmixin.cpp14
-rw-r--r--sources/shiboken6/ApiExtractor/enclosingclassmixin.h24
-rw-r--r--sources/shiboken6/ApiExtractor/enumtypeentry.h51
-rw-r--r--sources/shiboken6/ApiExtractor/enumvaluetypeentry.h31
-rw-r--r--sources/shiboken6/ApiExtractor/exception.h27
-rw-r--r--sources/shiboken6/ApiExtractor/fileout.cpp198
-rw-r--r--sources/shiboken6/ApiExtractor/fileout.h43
-rw-r--r--sources/shiboken6/ApiExtractor/flagstypeentry.h36
-rw-r--r--sources/shiboken6/ApiExtractor/functiontypeentry.h35
-rw-r--r--sources/shiboken6/ApiExtractor/graph.h321
-rw-r--r--sources/shiboken6/ApiExtractor/header_paths.h46
-rw-r--r--sources/shiboken6/ApiExtractor/icecc.cmake14
-rw-r--r--sources/shiboken6/ApiExtractor/include.cpp79
-rw-r--r--sources/shiboken6/ApiExtractor/include.h95
-rw-r--r--sources/shiboken6/ApiExtractor/merge.xsl82
-rw-r--r--sources/shiboken6/ApiExtractor/messages.cpp1004
-rw-r--r--sources/shiboken6/ApiExtractor/messages.h267
-rw-r--r--sources/shiboken6/ApiExtractor/modifications.cpp672
-rw-r--r--sources/shiboken6/ApiExtractor/modifications.h342
-rw-r--r--sources/shiboken6/ApiExtractor/modifications_typedefs.h25
-rw-r--r--sources/shiboken6/ApiExtractor/namespacetypeentry.h51
-rw-r--r--sources/shiboken6/ApiExtractor/objecttypeentry.h21
-rw-r--r--sources/shiboken6/ApiExtractor/optionsparser.cpp232
-rw-r--r--sources/shiboken6/ApiExtractor/optionsparser.h98
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.cpp1562
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.h700
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel_enums.h61
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel_fwd.h61
-rw-r--r--sources/shiboken6/ApiExtractor/parser/enumvalue.cpp103
-rw-r--r--sources/shiboken6/ApiExtractor/parser/enumvalue.h61
-rw-r--r--sources/shiboken6/ApiExtractor/parser/typeinfo.cpp624
-rw-r--r--sources/shiboken6/ApiExtractor/parser/typeinfo.h128
-rw-r--r--sources/shiboken6/ApiExtractor/predefined_templates.cpp276
-rw-r--r--sources/shiboken6/ApiExtractor/predefined_templates.h27
-rw-r--r--sources/shiboken6/ApiExtractor/primitivetypeentry.h72
-rw-r--r--sources/shiboken6/ApiExtractor/propertyspec.cpp347
-rw-r--r--sources/shiboken6/ApiExtractor/propertyspec.h104
-rw-r--r--sources/shiboken6/ApiExtractor/pymethoddefentry.cpp53
-rw-r--r--sources/shiboken6/ApiExtractor/pymethoddefentry.h38
-rw-r--r--sources/shiboken6/ApiExtractor/pythontypeentry.h29
-rw-r--r--sources/shiboken6/ApiExtractor/qtcompat.h37
-rw-r--r--sources/shiboken6/ApiExtractor/qtdocparser.cpp445
-rw-r--r--sources/shiboken6/ApiExtractor/qtdocparser.h40
-rw-r--r--sources/shiboken6/ApiExtractor/reporthandler.cpp194
-rw-r--r--sources/shiboken6/ApiExtractor/reporthandler.h46
-rw-r--r--sources/shiboken6/ApiExtractor/smartpointertypeentry.h57
-rw-r--r--sources/shiboken6/ApiExtractor/sourcelocation.cpp75
-rw-r--r--sources/shiboken6/ApiExtractor/sourcelocation.h42
-rw-r--r--sources/shiboken6/ApiExtractor/symbols.filter7
-rw-r--r--sources/shiboken6/ApiExtractor/templateargumententry.h26
-rw-r--r--sources/shiboken6/ApiExtractor/tests/CMakeLists.txt66
-rw-r--r--sources/shiboken6/ApiExtractor/tests/a.xml14
-rw-r--r--sources/shiboken6/ApiExtractor/tests/injectedcode.txt5
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp778
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h38
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp229
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h24
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp522
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testaddfunction.h31
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp155
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testarrayargument.h18
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp164
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcodeinjection.h23
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcodeinjection.qrc6
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcontainer.cpp84
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcontainer.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp178
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testconversionoperator.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp240
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testconversionruletag.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp57
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testctorinformation.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp228
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h22
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp158
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testdtorinformation.h22
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testenum.cpp577
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testenum.h25
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp62
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testextrainclude.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp79
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testfunctiontag.h18
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp142
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h21
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp63
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testinserttemplate.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp117
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.qrc5
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp480
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h26
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp50
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h18
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnamespace.cpp77
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnamespace.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp115
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnestedtypes.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp90
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp40
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp84
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testrefcounttag.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp37
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremovefield.cpp76
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremovefield.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp48
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp98
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp281
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testresolvetype.h21
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp129
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreverseoperators.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtemplates.cpp628
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtemplates.h30
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtoposort.cpp61
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtoposort.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp92
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtyperevision.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testutil.h65
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp39
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp67
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testvoidarg.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/utf8code.txt1
-rw-r--r--sources/shiboken6/ApiExtractor/textstream.cpp263
-rw-r--r--sources/shiboken6/ApiExtractor/textstream.h227
-rw-r--r--sources/shiboken6/ApiExtractor/typedatabase.cpp1661
-rw-r--r--sources/shiboken6/ApiExtractor/typedatabase.h208
-rw-r--r--sources/shiboken6/ApiExtractor/typedatabase_p.h25
-rw-r--r--sources/shiboken6/ApiExtractor/typedatabase_typedefs.h33
-rw-r--r--sources/shiboken6/ApiExtractor/typedefentry.h37
-rw-r--r--sources/shiboken6/ApiExtractor/typeparser.cpp292
-rw-r--r--sources/shiboken6/ApiExtractor/typeparser.h17
-rw-r--r--sources/shiboken6/ApiExtractor/typesystem.cpp2649
-rw-r--r--sources/shiboken6/ApiExtractor/typesystem.h215
-rw-r--r--sources/shiboken6/ApiExtractor/typesystem_enums.h113
-rw-r--r--sources/shiboken6/ApiExtractor/typesystem_typedefs.h79
-rw-r--r--sources/shiboken6/ApiExtractor/typesystemparser.cpp3648
-rw-r--r--sources/shiboken6/ApiExtractor/typesystemparser_p.h297
-rw-r--r--sources/shiboken6/ApiExtractor/typesystemtypeentry.h40
-rw-r--r--sources/shiboken6/ApiExtractor/usingmember.h21
-rw-r--r--sources/shiboken6/ApiExtractor/valuetypeentry.h40
-rw-r--r--sources/shiboken6/ApiExtractor/varargstypeentry.h20
-rw-r--r--sources/shiboken6/ApiExtractor/voidtypeentry.h20
-rw-r--r--sources/shiboken6/ApiExtractor/xmlutils.cpp42
-rw-r--r--sources/shiboken6/ApiExtractor/xmlutils.h29
-rw-r--r--sources/shiboken6/ApiExtractor/xmlutils_libxslt.cpp208
-rw-r--r--sources/shiboken6/ApiExtractor/xmlutils_libxslt.h16
-rw-r--r--sources/shiboken6/ApiExtractor/xmlutils_qt.h16
-rw-r--r--sources/shiboken6/CMakeLists.txt36
-rw-r--r--sources/shiboken6/COPYING342
-rw-r--r--sources/shiboken6/COPYING.libsample501
-rw-r--r--sources/shiboken6/COPYING.libshiboken501
-rw-r--r--sources/shiboken6/Doxyfile311
-rw-r--r--sources/shiboken6/cmake/FindDocTools.cmake39
-rw-r--r--sources/shiboken6/cmake/ShibokenHelpers.cmake889
-rw-r--r--sources/shiboken6/cmake/ShibokenSetup.cmake192
-rw-r--r--sources/shiboken6/cmake_uninstall.cmake24
-rw-r--r--sources/shiboken6/config.tests/target_python_info/CMakeLists.txt47
-rw-r--r--sources/shiboken6/config.tests/target_qt_info/CMakeLists.txt39
-rw-r--r--sources/shiboken6/config.tests/target_qt_mkspec/CMakeLists.txt25
-rw-r--r--sources/shiboken6/data/CMakeLists.txt60
-rw-r--r--sources/shiboken6/data/GeneratorRunnerConfig.cmake.in17
-rw-r--r--sources/shiboken6/data/GeneratorRunnerConfigVersion.cmake.in10
-rw-r--r--sources/shiboken6/data/Shiboken6Config-spec.cmake.in41
-rw-r--r--sources/shiboken6/data/Shiboken6Config.cmake.in5
-rw-r--r--sources/shiboken6/data/Shiboken6ConfigVersion.cmake.in10
-rw-r--r--sources/shiboken6/data/Shiboken6ToolsConfig.cmake.in7
l---------sources/shiboken6/data/docgenerator.11
-rw-r--r--sources/shiboken6/data/generatorrunner.176
-rw-r--r--sources/shiboken6/data/generatorrunner.pc.in13
-rw-r--r--sources/shiboken6/data/shiboken6.pc.in12
-rw-r--r--sources/shiboken6/doc/CMakeLists.txt73
-rw-r--r--sources/shiboken6/doc/README.md12
-rw-r--r--sources/shiboken6/doc/_static/css/qt_font.css15
-rw-r--r--sources/shiboken6/doc/_static/css/qt_style.css100
-rw-r--r--sources/shiboken6/doc/_static/qtforpython.pngbin0 -> 4936 bytes
-rw-r--r--sources/shiboken6/doc/_static/shiboken.pngbin0 -> 17343 bytes
-rw-r--r--sources/shiboken6/doc/_static/shiboken.svg129
-rw-r--r--sources/shiboken6/doc/_templates/index.html35
-rw-r--r--sources/shiboken6/doc/_templates/layout.html53
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/domainindex.html57
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/fakebar.pngbin0 -> 101 bytes
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/logo_python.jpgbin0 -> 2660 bytes
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/logo_qt.pngbin0 -> 1936 bytes
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/minus.pngbin0 -> 199 bytes
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/plus.pngbin0 -> 199 bytes
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/pyside.css1943
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/pysidelogo.pngbin0 -> 4936 bytes
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/relbar_bg.pngbin0 -> 130 bytes
-rw-r--r--sources/shiboken6/doc/_themes/pysidedocs_qthelp/theme.conf7
-rw-r--r--sources/shiboken6/doc/conf.py.in211
-rw-r--r--sources/shiboken6/doc/considerations.rst196
-rw-r--r--sources/shiboken6/doc/dependency-pyside.svg527
-rw-r--r--sources/shiboken6/doc/examples/index.rst23
-rw-r--r--sources/shiboken6/doc/gettingstarted.rst74
-rw-r--r--sources/shiboken6/doc/images/.directory3
-rw-r--r--sources/shiboken6/doc/images/bindinggen-development.pngbin0 -> 32698 bytes
-rw-r--r--sources/shiboken6/doc/images/bindinggen-development.svg542
-rw-r--r--sources/shiboken6/doc/images/converter.pngbin0 -> 34204 bytes
-rw-r--r--sources/shiboken6/doc/images/converter.svg2227
-rw-r--r--sources/shiboken6/doc/images/icecream.pngbin0 -> 4272 bytes
-rw-r--r--sources/shiboken6/doc/images/qtforpython-underthehood.pngbin0 -> 62001 bytes
-rw-r--r--sources/shiboken6/doc/images/qtforpython-underthehood.svg1502
-rw-r--r--sources/shiboken6/doc/images/shibokenqtarch.pngbin0 -> 28655 bytes
-rw-r--r--sources/shiboken6/doc/images/shibokenqtarch.svg191
-rw-r--r--sources/shiboken6/doc/index.rst125
-rw-r--r--sources/shiboken6/doc/scripts/patch_qhp.py62
-rw-r--r--sources/shiboken6/doc/shiboken-genpyi.rst32
-rw-r--r--sources/shiboken6/doc/shibokengenerator.rst393
-rw-r--r--sources/shiboken6/doc/shibokenmodule.rst147
-rw-r--r--sources/shiboken6/doc/typediscovery.rst145
-rw-r--r--sources/shiboken6/doc/typesystem.rst68
-rw-r--r--sources/shiboken6/doc/typesystem_arguments.rst229
-rw-r--r--sources/shiboken6/doc/typesystem_builtin_types.rst58
-rw-r--r--sources/shiboken6/doc/typesystem_codegeneration.rst37
-rw-r--r--sources/shiboken6/doc/typesystem_codeinjection.rst397
-rw-r--r--sources/shiboken6/doc/typesystem_containers.rst284
-rw-r--r--sources/shiboken6/doc/typesystem_conversionrule.rst133
-rw-r--r--sources/shiboken6/doc/typesystem_converters.rst235
-rw-r--r--sources/shiboken6/doc/typesystem_documentation.rst62
-rw-r--r--sources/shiboken6/doc/typesystem_manipulating_objects.rst556
-rw-r--r--sources/shiboken6/doc/typesystem_modify_function.rst44
-rw-r--r--sources/shiboken6/doc/typesystem_ownership.rst291
-rw-r--r--sources/shiboken6/doc/typesystem_solving_compilation.rst80
-rw-r--r--sources/shiboken6/doc/typesystem_specialfunctions.rst54
-rw-r--r--sources/shiboken6/doc/typesystem_specifying_types.rst890
-rw-r--r--sources/shiboken6/doc/typesystem_templates.rst133
-rw-r--r--sources/shiboken6/doc/typesystem_variables.rst339
-rw-r--r--sources/shiboken6/generator/CMakeLists.txt121
-rw-r--r--sources/shiboken6/generator/__init__.py.in2
-rw-r--r--sources/shiboken6/generator/_config.py.in10
-rw-r--r--sources/shiboken6/generator/defaultvalue.cpp120
-rw-r--r--sources/shiboken6/generator/defaultvalue.h46
-rw-r--r--sources/shiboken6/generator/generator.cpp700
-rw-r--r--sources/shiboken6/generator/generator.h233
-rw-r--r--sources/shiboken6/generator/generatorcontext.cpp38
-rw-r--r--sources/shiboken6/generator/generatorcontext.h56
-rw-r--r--sources/shiboken6/generator/main.cpp435
-rw-r--r--sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp1591
-rw-r--r--sources/shiboken6/generator/qtdoc/qtdocgenerator.h130
-rw-r--r--sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp1643
-rw-r--r--sources/shiboken6/generator/qtdoc/qtxmltosphinx.h216
-rw-r--r--sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h68
-rw-r--r--sources/shiboken6/generator/qtdoc/rstformat.h99
-rw-r--r--sources/shiboken6/generator/shiboken/configurablescope.h33
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp6819
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.h565
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_container.cpp272
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp476
-rw-r--r--sources/shiboken6/generator/shiboken/ctypenames.h31
-rw-r--r--sources/shiboken6/generator/shiboken/generatorargument.cpp110
-rw-r--r--sources/shiboken6/generator/shiboken/generatorargument.h60
-rw-r--r--sources/shiboken6/generator/shiboken/generatorstrings.h39
-rw-r--r--sources/shiboken6/generator/shiboken/headergenerator.cpp961
-rw-r--r--sources/shiboken6/generator/shiboken/headergenerator.h76
-rw-r--r--sources/shiboken6/generator/shiboken/overloaddata.cpp1011
-rw-r--r--sources/shiboken6/generator/shiboken/overloaddata.h183
-rw-r--r--sources/shiboken6/generator/shiboken/pytypenames.h29
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.cpp2650
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.h491
-rw-r--r--sources/shiboken6/generator/shibokenconfig.h.in6
-rw-r--r--sources/shiboken6/generatorrunnerconfig.h.in13
-rw-r--r--sources/shiboken6/generatorrunnermacros.h23
-rw-r--r--sources/shiboken6/icecc.cmake14
-rw-r--r--sources/shiboken6/libshiboken/CMakeLists.txt199
-rw-r--r--sources/shiboken6/libshiboken/autodecref.h87
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.cpp1924
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.h519
-rw-r--r--sources/shiboken6/libshiboken/basewrapper_p.h167
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.cpp549
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.h93
-rw-r--r--sources/shiboken6/libshiboken/bufferprocs_py37.cpp360
-rw-r--r--sources/shiboken6/libshiboken/bufferprocs_py37.h109
-rw-r--r--sources/shiboken6/libshiboken/debugfreehook.cpp158
-rw-r--r--sources/shiboken6/libshiboken/debugfreehook.h25
-rw-r--r--sources/shiboken6/libshiboken/embed/embedding_generator.py220
-rw-r--r--sources/shiboken6/libshiboken/embed/module_collector.py71
-rw-r--r--sources/shiboken6/libshiboken/embed/qt_python_license.txt48
-rw-r--r--sources/shiboken6/libshiboken/embed/signature_bootstrap.py204
-rw-r--r--sources/shiboken6/libshiboken/gilstate.cpp38
-rw-r--r--sources/shiboken6/libshiboken/gilstate.h33
-rw-r--r--sources/shiboken6/libshiboken/helper.cpp637
-rw-r--r--sources/shiboken6/libshiboken/helper.h120
-rw-r--r--sources/shiboken6/libshiboken/pep384ext.h89
-rw-r--r--sources/shiboken6/libshiboken/pep384impl.cpp1319
-rw-r--r--sources/shiboken6/libshiboken/pep384impl.h611
-rw-r--r--sources/shiboken6/libshiboken/pyobjectholder.h86
-rw-r--r--sources/shiboken6/libshiboken/qt_attribution.json12
-rw-r--r--sources/shiboken6/libshiboken/sbkarrayconverter.cpp246
-rw-r--r--sources/shiboken6/libshiboken/sbkarrayconverter.h136
-rw-r--r--sources/shiboken6/libshiboken/sbkarrayconverter_p.h26
-rw-r--r--sources/shiboken6/libshiboken/sbkcontainer.cpp19
-rw-r--r--sources/shiboken6/libshiboken/sbkcontainer.h259
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter.cpp910
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter.h422
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter_p.h542
-rw-r--r--sources/shiboken6/libshiboken/sbkcppstring.cpp54
-rw-r--r--sources/shiboken6/libshiboken/sbkcppstring.h22
-rw-r--r--sources/shiboken6/libshiboken/sbkcpptonumpy.cpp67
-rw-r--r--sources/shiboken6/libshiboken/sbkcpptonumpy.h41
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.cpp454
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.h102
-rw-r--r--sources/shiboken6/libshiboken/sbkerrors.cpp215
-rw-r--r--sources/shiboken6/libshiboken/sbkerrors.h78
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.cpp424
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.h18
-rw-r--r--sources/shiboken6/libshiboken/sbkmodule.cpp525
-rw-r--r--sources/shiboken6/libshiboken/sbkmodule.h89
-rw-r--r--sources/shiboken6/libshiboken/sbknumpy.cpp57
-rw-r--r--sources/shiboken6/libshiboken/sbknumpyarrayconverter.cpp270
-rw-r--r--sources/shiboken6/libshiboken/sbknumpycheck.h30
-rw-r--r--sources/shiboken6/libshiboken/sbknumpyview.cpp265
-rw-r--r--sources/shiboken6/libshiboken/sbknumpyview.h47
-rw-r--r--sources/shiboken6/libshiboken/sbkpython.h75
-rw-r--r--sources/shiboken6/libshiboken/sbksmartpointer.cpp58
-rw-r--r--sources/shiboken6/libshiboken/sbksmartpointer.h18
-rw-r--r--sources/shiboken6/libshiboken/sbkstaticstrings.cpp88
-rw-r--r--sources/shiboken6/libshiboken/sbkstaticstrings.h61
-rw-r--r--sources/shiboken6/libshiboken/sbkstaticstrings_p.h37
-rw-r--r--sources/shiboken6/libshiboken/sbkstring.cpp254
-rw-r--r--sources/shiboken6/libshiboken/sbkstring.h42
-rw-r--r--sources/shiboken6/libshiboken/sbktypefactory.cpp407
-rw-r--r--sources/shiboken6/libshiboken/sbktypefactory.h26
-rw-r--r--sources/shiboken6/libshiboken/sbkversion.h.in17
-rw-r--r--sources/shiboken6/libshiboken/sbkwindows.h17
-rw-r--r--sources/shiboken6/libshiboken/shiboken.h27
-rw-r--r--sources/shiboken6/libshiboken/shibokenbuffer.cpp70
-rw-r--r--sources/shiboken6/libshiboken/shibokenbuffer.h57
-rw-r--r--sources/shiboken6/libshiboken/shibokenmacros.h26
-rw-r--r--sources/shiboken6/libshiboken/signature.h21
-rw-r--r--sources/shiboken6/libshiboken/signature/signature.cpp640
-rw-r--r--sources/shiboken6/libshiboken/signature/signature_extend.cpp230
-rw-r--r--sources/shiboken6/libshiboken/signature/signature_globals.cpp264
-rw-r--r--sources/shiboken6/libshiboken/signature/signature_helper.cpp389
-rw-r--r--sources/shiboken6/libshiboken/signature_p.h78
-rw-r--r--sources/shiboken6/libshiboken/threadstatesaver.cpp31
-rw-r--r--sources/shiboken6/libshiboken/threadstatesaver.h32
-rw-r--r--sources/shiboken6/libshiboken/voidptr.cpp434
-rw-r--r--sources/shiboken6/libshiboken/voidptr.h33
-rwxr-xr-xsources/shiboken6/shiboken_tool.py29
-rw-r--r--sources/shiboken6/shiboken_version.py19
-rw-r--r--sources/shiboken6/shibokenmodule/CMakeLists.txt84
-rw-r--r--sources/shiboken6/shibokenmodule/Shiboken.pyi37
-rw-r--r--sources/shiboken6/shibokenmodule/__init__.py.in27
-rw-r--r--sources/shiboken6/shibokenmodule/_config.py.in12
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py4
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py248
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py59
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/shibokensupport.pyproject16
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt43
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py4
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py150
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py65
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py247
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py4
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py304
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py334
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py110
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py158
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py719
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py552
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json13
-rw-r--r--sources/shiboken6/shibokenmodule/nothing.h3
-rw-r--r--sources/shiboken6/shibokenmodule/py.typed.in1
-rw-r--r--sources/shiboken6/shibokenmodule/shibokenmodule.cpp119
-rw-r--r--sources/shiboken6/shibokenmodule/shibokenmodule.txt.in16
-rw-r--r--sources/shiboken6/shibokenmodule/typesystem_shiboken.xml70
-rw-r--r--sources/shiboken6/tests/CMakeLists.txt92
-rw-r--r--sources/shiboken6/tests/dumpcodemodel/CMakeLists.txt16
-rw-r--r--sources/shiboken6/tests/dumpcodemodel/main.cpp260
-rw-r--r--sources/shiboken6/tests/libminimal/CMakeLists.txt21
-rw-r--r--sources/shiboken6/tests/libminimal/containeruser.cpp55
-rw-r--r--sources/shiboken6/tests/libminimal/containeruser.h36
-rw-r--r--sources/shiboken6/tests/libminimal/libminimalmacros.h49
-rw-r--r--sources/shiboken6/tests/libminimal/listuser.cpp133
-rw-r--r--sources/shiboken6/tests/libminimal/listuser.h72
-rw-r--r--sources/shiboken6/tests/libminimal/minbool.h48
-rw-r--r--sources/shiboken6/tests/libminimal/obj.cpp16
-rw-r--r--sources/shiboken6/tests/libminimal/obj.h34
-rw-r--r--sources/shiboken6/tests/libminimal/spanuser.cpp58
-rw-r--r--sources/shiboken6/tests/libminimal/spanuser.h35
-rw-r--r--sources/shiboken6/tests/libminimal/typedef.cpp50
-rw-r--r--sources/shiboken6/tests/libminimal/typedef.h29
-rw-r--r--sources/shiboken6/tests/libminimal/val.h36
-rw-r--r--sources/shiboken6/tests/libother/CMakeLists.txt23
-rw-r--r--sources/shiboken6/tests/libother/extendsnoimplicitconversion.h21
-rw-r--r--sources/shiboken6/tests/libother/libothermacros.h18
-rw-r--r--sources/shiboken6/tests/libother/number.cpp28
-rw-r--r--sources/shiboken6/tests/libother/number.h32
-rw-r--r--sources/shiboken6/tests/libother/otherderived.cpp33
-rw-r--r--sources/shiboken6/tests/libother/otherderived.h43
-rw-r--r--sources/shiboken6/tests/libother/othermultiplederived.cpp24
-rw-r--r--sources/shiboken6/tests/libother/othermultiplederived.h21
-rw-r--r--sources/shiboken6/tests/libother/otherobjecttype.cpp20
-rw-r--r--sources/shiboken6/tests/libother/otherobjecttype.h22
-rw-r--r--sources/shiboken6/tests/libother/othertypesystypedef.cpp19
-rw-r--r--sources/shiboken6/tests/libother/othertypesystypedef.h21
-rw-r--r--sources/shiboken6/tests/libother/smartptrtester.cpp30
-rw-r--r--sources/shiboken6/tests/libother/smartptrtester.h24
-rw-r--r--sources/shiboken6/tests/libsample/CMakeLists.txt95
-rw-r--r--sources/shiboken6/tests/libsample/abstract.cpp71
-rw-r--r--sources/shiboken6/tests/libsample/abstract.h91
-rw-r--r--sources/shiboken6/tests/libsample/blackbox.cpp81
-rw-r--r--sources/shiboken6/tests/libsample/blackbox.h44
-rw-r--r--sources/shiboken6/tests/libsample/bucket.cpp59
-rw-r--r--sources/shiboken6/tests/libsample/bucket.h34
-rw-r--r--sources/shiboken6/tests/libsample/bytearray.cpp166
-rw-r--r--sources/shiboken6/tests/libsample/bytearray.h64
-rw-r--r--sources/shiboken6/tests/libsample/collector.cpp37
-rw-r--r--sources/shiboken6/tests/libsample/collector.h37
-rw-r--r--sources/shiboken6/tests/libsample/complex.cpp24
-rw-r--r--sources/shiboken6/tests/libsample/complex.h32
-rw-r--r--sources/shiboken6/tests/libsample/ctorconvrule.h22
-rw-r--r--sources/shiboken6/tests/libsample/ctparam.cpp20
-rw-r--r--sources/shiboken6/tests/libsample/ctparam.h26
-rw-r--r--sources/shiboken6/tests/libsample/cvlist.h28
-rw-r--r--sources/shiboken6/tests/libsample/derived.cpp88
-rw-r--r--sources/shiboken6/tests/libsample/derived.h72
-rw-r--r--sources/shiboken6/tests/libsample/derivedusingct.cpp9
-rw-r--r--sources/shiboken6/tests/libsample/derivedusingct.h17
-rw-r--r--sources/shiboken6/tests/libsample/echo.cpp4
-rw-r--r--sources/shiboken6/tests/libsample/echo.h60
-rw-r--r--sources/shiboken6/tests/libsample/exceptiontest.cpp46
-rw-r--r--sources/shiboken6/tests/libsample/exceptiontest.h25
-rw-r--r--sources/shiboken6/tests/libsample/expression.cpp79
-rw-r--r--sources/shiboken6/tests/libsample/expression.h40
-rw-r--r--sources/shiboken6/tests/libsample/filter.cpp38
-rw-r--r--sources/shiboken6/tests/libsample/filter.h70
-rw-r--r--sources/shiboken6/tests/libsample/functions.cpp232
-rw-r--r--sources/shiboken6/tests/libsample/functions.h91
-rw-r--r--sources/shiboken6/tests/libsample/handle.cpp19
-rw-r--r--sources/shiboken6/tests/libsample/handle.h53
-rw-r--r--sources/shiboken6/tests/libsample/implicitconv.cpp39
-rw-r--r--sources/shiboken6/tests/libsample/implicitconv.h60
-rw-r--r--sources/shiboken6/tests/libsample/injectcode.cpp78
-rw-r--r--sources/shiboken6/tests/libsample/injectcode.h44
-rw-r--r--sources/shiboken6/tests/libsample/intwrapper.cpp36
-rw-r--r--sources/shiboken6/tests/libsample/intwrapper.h62
-rw-r--r--sources/shiboken6/tests/libsample/libsamplemacros.h18
-rw-r--r--sources/shiboken6/tests/libsample/list.h99
-rw-r--r--sources/shiboken6/tests/libsample/listuser.cpp63
-rw-r--r--sources/shiboken6/tests/libsample/listuser.h53
-rw-r--r--sources/shiboken6/tests/libsample/main.cpp209
-rw-r--r--sources/shiboken6/tests/libsample/mapuser.cpp48
-rw-r--r--sources/shiboken6/tests/libsample/mapuser.h45
-rw-r--r--sources/shiboken6/tests/libsample/modelindex.h50
-rw-r--r--sources/shiboken6/tests/libsample/modifications.cpp207
-rw-r--r--sources/shiboken6/tests/libsample/modifications.h145
-rw-r--r--sources/shiboken6/tests/libsample/modified_constructor.cpp16
-rw-r--r--sources/shiboken6/tests/libsample/modified_constructor.h21
-rw-r--r--sources/shiboken6/tests/libsample/multiple_derived.cpp24
-rw-r--r--sources/shiboken6/tests/libsample/multiple_derived.h202
-rw-r--r--sources/shiboken6/tests/libsample/noimplicitconversion.h27
-rw-r--r--sources/shiboken6/tests/libsample/nondefaultctor.h54
-rw-r--r--sources/shiboken6/tests/libsample/nontypetemplate.h27
-rw-r--r--sources/shiboken6/tests/libsample/null.h19
-rw-r--r--sources/shiboken6/tests/libsample/objectmodel.cpp24
-rw-r--r--sources/shiboken6/tests/libsample/objectmodel.h31
-rw-r--r--sources/shiboken6/tests/libsample/objecttype.cpp264
-rw-r--r--sources/shiboken6/tests/libsample/objecttype.h166
-rw-r--r--sources/shiboken6/tests/libsample/objecttypebyvalue.h31
-rw-r--r--sources/shiboken6/tests/libsample/objecttypeholder.cpp31
-rw-r--r--sources/shiboken6/tests/libsample/objecttypeholder.h29
-rw-r--r--sources/shiboken6/tests/libsample/objecttypelayout.cpp40
-rw-r--r--sources/shiboken6/tests/libsample/objecttypelayout.h32
-rw-r--r--sources/shiboken6/tests/libsample/objecttypeoperators.cpp38
-rw-r--r--sources/shiboken6/tests/libsample/objecttypeoperators.h36
-rw-r--r--sources/shiboken6/tests/libsample/objectview.cpp24
-rw-r--r--sources/shiboken6/tests/libsample/objectview.h31
-rw-r--r--sources/shiboken6/tests/libsample/oddbool.cpp27
-rw-r--r--sources/shiboken6/tests/libsample/oddbool.h106
-rw-r--r--sources/shiboken6/tests/libsample/onlycopy.cpp36
-rw-r--r--sources/shiboken6/tests/libsample/onlycopy.h42
-rw-r--r--sources/shiboken6/tests/libsample/overload.cpp203
-rw-r--r--sources/shiboken6/tests/libsample/overload.h121
-rw-r--r--sources/shiboken6/tests/libsample/overloadsort.cpp49
-rw-r--r--sources/shiboken6/tests/libsample/overloadsort.h54
-rw-r--r--sources/shiboken6/tests/libsample/pairuser.cpp24
-rw-r--r--sources/shiboken6/tests/libsample/pairuser.h32
-rw-r--r--sources/shiboken6/tests/libsample/pen.cpp83
-rw-r--r--sources/shiboken6/tests/libsample/pen.h72
-rw-r--r--sources/shiboken6/tests/libsample/photon.cpp31
-rw-r--r--sources/shiboken6/tests/libsample/photon.h110
-rw-r--r--sources/shiboken6/tests/libsample/point.cpp111
-rw-r--r--sources/shiboken6/tests/libsample/point.h76
-rw-r--r--sources/shiboken6/tests/libsample/pointerholder.h23
-rw-r--r--sources/shiboken6/tests/libsample/pointf.cpp86
-rw-r--r--sources/shiboken6/tests/libsample/pointf.h65
-rw-r--r--sources/shiboken6/tests/libsample/polygon.cpp39
-rw-r--r--sources/shiboken6/tests/libsample/polygon.h39
-rw-r--r--sources/shiboken6/tests/libsample/privatector.h42
-rw-r--r--sources/shiboken6/tests/libsample/privatedtor.h36
-rw-r--r--sources/shiboken6/tests/libsample/protected.cpp16
-rw-r--r--sources/shiboken6/tests/libsample/protected.h139
-rw-r--r--sources/shiboken6/tests/libsample/rect.h54
-rw-r--r--sources/shiboken6/tests/libsample/reference.cpp53
-rw-r--r--sources/shiboken6/tests/libsample/reference.h62
-rw-r--r--sources/shiboken6/tests/libsample/removednamespaces.h48
-rw-r--r--sources/shiboken6/tests/libsample/renaming.cpp21
-rw-r--r--sources/shiboken6/tests/libsample/renaming.h25
-rw-r--r--sources/shiboken6/tests/libsample/sample.cpp22
-rw-r--r--sources/shiboken6/tests/libsample/sample.h28
-rw-r--r--sources/shiboken6/tests/libsample/samplenamespace.cpp101
-rw-r--r--sources/shiboken6/tests/libsample/samplenamespace.h164
-rw-r--r--sources/shiboken6/tests/libsample/sbkdate.cpp23
-rw-r--r--sources/shiboken6/tests/libsample/sbkdate.h24
-rw-r--r--sources/shiboken6/tests/libsample/simplefile.cpp73
-rw-r--r--sources/shiboken6/tests/libsample/simplefile.h34
-rw-r--r--sources/shiboken6/tests/libsample/size.cpp11
-rw-r--r--sources/shiboken6/tests/libsample/size.h185
-rw-r--r--sources/shiboken6/tests/libsample/snakecasetest.cpp44
-rw-r--r--sources/shiboken6/tests/libsample/snakecasetest.h40
-rw-r--r--sources/shiboken6/tests/libsample/sometime.cpp67
-rw-r--r--sources/shiboken6/tests/libsample/sometime.h66
-rw-r--r--sources/shiboken6/tests/libsample/stdcomplex.cpp32
-rw-r--r--sources/shiboken6/tests/libsample/stdcomplex.h55
-rw-r--r--sources/shiboken6/tests/libsample/str.cpp137
-rw-r--r--sources/shiboken6/tests/libsample/str.h52
-rw-r--r--sources/shiboken6/tests/libsample/strlist.cpp25
-rw-r--r--sources/shiboken6/tests/libsample/strlist.h49
-rw-r--r--sources/shiboken6/tests/libsample/templateptr.cpp8
-rw-r--r--sources/shiboken6/tests/libsample/templateptr.h19
-rw-r--r--sources/shiboken6/tests/libsample/transform.cpp28
-rw-r--r--sources/shiboken6/tests/libsample/transform.h18
-rw-r--r--sources/shiboken6/tests/libsample/typesystypedef.cpp12
-rw-r--r--sources/shiboken6/tests/libsample/typesystypedef.h32
-rw-r--r--sources/shiboken6/tests/libsample/valueandvirtual.h25
-rw-r--r--sources/shiboken6/tests/libsample/virtualmethods.cpp66
-rw-r--r--sources/shiboken6/tests/libsample/virtualmethods.h145
-rw-r--r--sources/shiboken6/tests/libsample/voidholder.h32
-rw-r--r--sources/shiboken6/tests/libsmart/CMakeLists.txt23
-rw-r--r--sources/shiboken6/tests/libsmart/libsmartmacros.h18
-rw-r--r--sources/shiboken6/tests/libsmart/smart.cpp272
-rw-r--r--sources/shiboken6/tests/libsmart/smart.h16
-rw-r--r--sources/shiboken6/tests/libsmart/smart_integer.h69
-rw-r--r--sources/shiboken6/tests/libsmart/smart_obj.h45
-rw-r--r--sources/shiboken6/tests/libsmart/smart_registry.h43
-rw-r--r--sources/shiboken6/tests/libsmart/smart_sharedptr.h94
-rw-r--r--sources/shiboken6/tests/libsmart/smart_test.h13
-rw-r--r--sources/shiboken6/tests/libsmart/stdoptionaltestbench.cpp58
-rw-r--r--sources/shiboken6/tests/libsmart/stdoptionaltestbench.h30
-rw-r--r--sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp106
-rw-r--r--sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h49
-rw-r--r--sources/shiboken6/tests/libsmart/stduniqueptrtestbench.cpp133
-rw-r--r--sources/shiboken6/tests/libsmart/stduniqueptrtestbench.h50
-rw-r--r--sources/shiboken6/tests/minimalbinding/CMakeLists.txt47
-rw-r--r--sources/shiboken6/tests/minimalbinding/brace_pattern_test.py87
-rw-r--r--sources/shiboken6/tests/minimalbinding/containeruser_test.py44
-rw-r--r--sources/shiboken6/tests/minimalbinding/global.h10
-rw-r--r--sources/shiboken6/tests/minimalbinding/listuser_test.py376
-rw-r--r--sources/shiboken6/tests/minimalbinding/minbool_test.py46
-rw-r--r--sources/shiboken6/tests/minimalbinding/minimal-binding.txt.in16
-rw-r--r--sources/shiboken6/tests/minimalbinding/minimalbinding.pyproject10
-rw-r--r--sources/shiboken6/tests/minimalbinding/obj_test.py94
-rw-r--r--sources/shiboken6/tests/minimalbinding/spanuser_test.py42
-rw-r--r--sources/shiboken6/tests/minimalbinding/typedef_test.py107
-rw-r--r--sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml86
-rw-r--r--sources/shiboken6/tests/minimalbinding/val_test.py94
-rw-r--r--sources/shiboken6/tests/otherbinding/CMakeLists.txt58
-rw-r--r--sources/shiboken6/tests/otherbinding/collector_external_operator_test.py39
-rw-r--r--sources/shiboken6/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py61
-rw-r--r--sources/shiboken6/tests/otherbinding/extended_multiply_operator_test.py45
-rw-r--r--sources/shiboken6/tests/otherbinding/global.h11
-rw-r--r--sources/shiboken6/tests/otherbinding/module_reload_test.py38
-rw-r--r--sources/shiboken6/tests/otherbinding/new_ctor_operator_test.py39
-rw-r--r--sources/shiboken6/tests/otherbinding/objtypehashes_test.py34
-rw-r--r--sources/shiboken6/tests/otherbinding/other-binding.txt.in20
-rw-r--r--sources/shiboken6/tests/otherbinding/otherbinding.pyproject17
-rw-r--r--sources/shiboken6/tests/otherbinding/otherderived_test.py109
-rw-r--r--sources/shiboken6/tests/otherbinding/othertypesystypedef_test.py35
-rw-r--r--sources/shiboken6/tests/otherbinding/signature_test.py34
-rw-r--r--sources/shiboken6/tests/otherbinding/smartptr_test.py33
-rw-r--r--sources/shiboken6/tests/otherbinding/star_import_test.py99
-rw-r--r--sources/shiboken6/tests/otherbinding/test_module_template.py24
-rw-r--r--sources/shiboken6/tests/otherbinding/typediscovery_test.py53
-rw-r--r--sources/shiboken6/tests/otherbinding/typesystem_other.xml20
-rw-r--r--sources/shiboken6/tests/otherbinding/usersprimitivefromothermodule_test.py34
-rw-r--r--sources/shiboken6/tests/otherbinding/wrongctor_test.py35
-rw-r--r--sources/shiboken6/tests/qtxmltosphinx/CMakeLists.txt32
-rw-r--r--sources/shiboken6/tests/qtxmltosphinx/main.cpp115
-rw-r--r--sources/shiboken6/tests/qtxmltosphinxtest/CMakeLists.txt38
-rw-r--r--sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp517
-rw-r--r--sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h40
-rw-r--r--sources/shiboken6/tests/samplebinding/CMakeLists.txt176
-rw-r--r--sources/shiboken6/tests/samplebinding/__del___test.py36
-rw-r--r--sources/shiboken6/tests/samplebinding/abstract_test.py87
-rw-r--r--sources/shiboken6/tests/samplebinding/addedfunction_test.py44
-rw-r--r--sources/shiboken6/tests/samplebinding/addedfunction_with_container_args_test.py33
-rw-r--r--sources/shiboken6/tests/samplebinding/argumentmodifications_test.py98
-rw-r--r--sources/shiboken6/tests/samplebinding/array_numpy_test.py47
-rw-r--r--sources/shiboken6/tests/samplebinding/array_sequence_test.py36
-rw-r--r--sources/shiboken6/tests/samplebinding/bug_554_test.py25
-rw-r--r--sources/shiboken6/tests/samplebinding/bug_704_test.py36
-rw-r--r--sources/shiboken6/tests/samplebinding/bytearray_test.py129
-rw-r--r--sources/shiboken6/tests/samplebinding/child_return_test.py43
-rw-r--r--sources/shiboken6/tests/samplebinding/class_fields_test.py173
-rw-r--r--sources/shiboken6/tests/samplebinding/collector_test.py60
-rw-r--r--sources/shiboken6/tests/samplebinding/complex_test.py66
-rw-r--r--sources/shiboken6/tests/samplebinding/conversion_operator_test.py37
-rw-r--r--sources/shiboken6/tests/samplebinding/copy_test.py65
-rw-r--r--sources/shiboken6/tests/samplebinding/ctorconvrule_test.py30
-rw-r--r--sources/shiboken6/tests/samplebinding/cyclic_test.py89
-rw-r--r--sources/shiboken6/tests/samplebinding/date_test.py38
-rw-r--r--sources/shiboken6/tests/samplebinding/decisor_test.py52
-rw-r--r--sources/shiboken6/tests/samplebinding/delete_test.py28
-rw-r--r--sources/shiboken6/tests/samplebinding/deprecated_test.py26
-rw-r--r--sources/shiboken6/tests/samplebinding/derived_test.py143
-rw-r--r--sources/shiboken6/tests/samplebinding/duck_punching_test.py158
-rw-r--r--sources/shiboken6/tests/samplebinding/echo_test.py34
-rw-r--r--sources/shiboken6/tests/samplebinding/enum_test.py138
-rw-r--r--sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py51
-rw-r--r--sources/shiboken6/tests/samplebinding/event_loop_call_virtual_test.py49
-rw-r--r--sources/shiboken6/tests/samplebinding/event_loop_thread_test.py77
-rw-r--r--sources/shiboken6/tests/samplebinding/exception_test.py71
-rw-r--r--sources/shiboken6/tests/samplebinding/filter_test.py29
-rw-r--r--sources/shiboken6/tests/samplebinding/global.h73
-rw-r--r--sources/shiboken6/tests/samplebinding/handleholder_test.py39
-rw-r--r--sources/shiboken6/tests/samplebinding/hashabletype_test.py35
-rw-r--r--sources/shiboken6/tests/samplebinding/ignorederefop_test.py22
-rw-r--r--sources/shiboken6/tests/samplebinding/implicitconv_numerical_test.py136
-rw-r--r--sources/shiboken6/tests/samplebinding/implicitconv_test.py46
-rw-r--r--sources/shiboken6/tests/samplebinding/inheritanceandscope_test.py30
-rw-r--r--sources/shiboken6/tests/samplebinding/injectcode_test.py119
-rw-r--r--sources/shiboken6/tests/samplebinding/innerclass_test.py23
-rw-r--r--sources/shiboken6/tests/samplebinding/intlist_test.py80
-rw-r--r--sources/shiboken6/tests/samplebinding/intwrapper_test.py39
-rw-r--r--sources/shiboken6/tests/samplebinding/invalid_virtual_return_test.py45
-rw-r--r--sources/shiboken6/tests/samplebinding/keep_reference_test.py63
-rw-r--r--sources/shiboken6/tests/samplebinding/list_test.py104
-rw-r--r--sources/shiboken6/tests/samplebinding/lock_test.py78
-rw-r--r--sources/shiboken6/tests/samplebinding/map_test.py63
-rw-r--r--sources/shiboken6/tests/samplebinding/metaclass_test.py52
-rw-r--r--sources/shiboken6/tests/samplebinding/mi_virtual_methods_test.py68
-rw-r--r--sources/shiboken6/tests/samplebinding/mixed_mi_test.py54
-rw-r--r--sources/shiboken6/tests/samplebinding/modelindex_test.py33
-rw-r--r--sources/shiboken6/tests/samplebinding/modelview_test.py61
-rw-r--r--sources/shiboken6/tests/samplebinding/modifications_test.py224
-rw-r--r--sources/shiboken6/tests/samplebinding/modified_constructor_test.py28
-rw-r--r--sources/shiboken6/tests/samplebinding/modifiedvirtualmethods_test.py233
-rw-r--r--sources/shiboken6/tests/samplebinding/multi_cpp_inheritance_test.py97
-rw-r--r--sources/shiboken6/tests/samplebinding/multiple_derived_test.py223
-rw-r--r--sources/shiboken6/tests/samplebinding/namespace_test.py68
-rw-r--r--sources/shiboken6/tests/samplebinding/newdivision_test.py25
-rw-r--r--sources/shiboken6/tests/samplebinding/nondefaultctor_test.py53
-rw-r--r--sources/shiboken6/tests/samplebinding/nontypetemplate_test.py41
-rw-r--r--sources/shiboken6/tests/samplebinding/nonzero_test.py34
-rw-r--r--sources/shiboken6/tests/samplebinding/numericaltypedef_test.py38
-rw-r--r--sources/shiboken6/tests/samplebinding/numpy_test.py41
-rw-r--r--sources/shiboken6/tests/samplebinding/objecttype_test.py110
-rw-r--r--sources/shiboken6/tests/samplebinding/objecttype_with_named_args_test.py50
-rw-r--r--sources/shiboken6/tests/samplebinding/objecttypebyvalue_test.py27
-rw-r--r--sources/shiboken6/tests/samplebinding/objecttypelayout_test.py301
-rw-r--r--sources/shiboken6/tests/samplebinding/objecttypeoperators_test.py42
-rw-r--r--sources/shiboken6/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py31
-rw-r--r--sources/shiboken6/tests/samplebinding/oddbool_test.py79
-rw-r--r--sources/shiboken6/tests/samplebinding/onlycopyclass_test.py40
-rw-r--r--sources/shiboken6/tests/samplebinding/overflow_test.py75
-rw-r--r--sources/shiboken6/tests/samplebinding/overload_sorting_test.py85
-rw-r--r--sources/shiboken6/tests/samplebinding/overload_test.py189
-rw-r--r--sources/shiboken6/tests/samplebinding/overloadwithdefault_test.py44
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_argument_invalidation_test.py44
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_delete_child_in_cpp_test.py35
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_delete_child_in_python_test.py40
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_delete_parent_test.py71
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_invalidate_after_use_test.py95
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_invalidate_child_test.py54
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py33
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_invalidate_parent_test.py48
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_reparenting_test.py111
-rw-r--r--sources/shiboken6/tests/samplebinding/ownership_transference_test.py71
-rw-r--r--sources/shiboken6/tests/samplebinding/pair_test.py89
-rw-r--r--sources/shiboken6/tests/samplebinding/pen_test.py58
-rw-r--r--sources/shiboken6/tests/samplebinding/point_test.py98
-rw-r--r--sources/shiboken6/tests/samplebinding/pointerholder_test.py41
-rw-r--r--sources/shiboken6/tests/samplebinding/pointerprimitivetype_test.py56
-rw-r--r--sources/shiboken6/tests/samplebinding/pointf_test.py51
-rw-r--r--sources/shiboken6/tests/samplebinding/primitivereferenceargument_test.py35
-rw-r--r--sources/shiboken6/tests/samplebinding/privatector_test.py69
-rw-r--r--sources/shiboken6/tests/samplebinding/privatedtor_test.py85
-rw-r--r--sources/shiboken6/tests/samplebinding/protected_test.py401
-rw-r--r--sources/shiboken6/tests/samplebinding/pstrlist_test.py32
-rw-r--r--sources/shiboken6/tests/samplebinding/pystr_test.py29
-rw-r--r--sources/shiboken6/tests/samplebinding/python_thread_test.py96
-rw-r--r--sources/shiboken6/tests/samplebinding/receive_null_cstring_test.py36
-rw-r--r--sources/shiboken6/tests/samplebinding/reference_test.py107
-rw-r--r--sources/shiboken6/tests/samplebinding/referencetopointer_test.py78
-rw-r--r--sources/shiboken6/tests/samplebinding/renaming_test.py39
-rw-r--r--sources/shiboken6/tests/samplebinding/return_null_test.py40
-rw-r--r--sources/shiboken6/tests/samplebinding/richcompare_test.py28
-rw-r--r--sources/shiboken6/tests/samplebinding/sample-binding.txt.in16
-rw-r--r--sources/shiboken6/tests/samplebinding/sample_test.py76
-rw-r--r--sources/shiboken6/tests/samplebinding/samplebinding.pyproject131
-rw-r--r--sources/shiboken6/tests/samplebinding/samplesnippets.cpp54
-rw-r--r--sources/shiboken6/tests/samplebinding/simplefile_glue.cpp9
-rw-r--r--sources/shiboken6/tests/samplebinding/simplefile_test.py60
-rw-r--r--sources/shiboken6/tests/samplebinding/size_test.py100
-rw-r--r--sources/shiboken6/tests/samplebinding/snakecase_test.py60
-rw-r--r--sources/shiboken6/tests/samplebinding/static_nonstatic_methods_test.py91
-rw-r--r--sources/shiboken6/tests/samplebinding/stdcomplex_test.py71
-rw-r--r--sources/shiboken6/tests/samplebinding/str_test.py97
-rw-r--r--sources/shiboken6/tests/samplebinding/strlist_test.py94
-rw-r--r--sources/shiboken6/tests/samplebinding/templateinheritingclass_test.py63
-rw-r--r--sources/shiboken6/tests/samplebinding/time_test.py120
-rw-r--r--sources/shiboken6/tests/samplebinding/transform_test.py38
-rw-r--r--sources/shiboken6/tests/samplebinding/typeconverters_test.py190
-rw-r--r--sources/shiboken6/tests/samplebinding/typedealloc_test.py60
-rw-r--r--sources/shiboken6/tests/samplebinding/typedtordoublefree_test.py38
-rw-r--r--sources/shiboken6/tests/samplebinding/typesystem_sample.xml2457
-rw-r--r--sources/shiboken6/tests/samplebinding/typesystypedef_test.py29
-rw-r--r--sources/shiboken6/tests/samplebinding/unsafe_parent_test.py35
-rw-r--r--sources/shiboken6/tests/samplebinding/useraddedctor_test.py26
-rw-r--r--sources/shiboken6/tests/samplebinding/virtualdtor_test.py63
-rw-r--r--sources/shiboken6/tests/samplebinding/virtualmethods_test.py130
-rw-r--r--sources/shiboken6/tests/samplebinding/visibilitychange_test.py27
-rw-r--r--sources/shiboken6/tests/samplebinding/voidholder_test.py50
-rw-r--r--sources/shiboken6/tests/samplebinding/weakref_test.py50
-rw-r--r--sources/shiboken6/tests/samplebinding/writableclassdict_test.py37
-rw-r--r--sources/shiboken6/tests/shiboken_paths.py109
-rw-r--r--sources/shiboken6/tests/shiboken_test_helper.py13
-rw-r--r--sources/shiboken6/tests/shibokenmodule/module_test.py112
-rw-r--r--sources/shiboken6/tests/smartbinding/CMakeLists.txt65
-rw-r--r--sources/shiboken6/tests/smartbinding/global.h4
-rw-r--r--sources/shiboken6/tests/smartbinding/smart-binding.txt.in16
-rw-r--r--sources/shiboken6/tests/smartbinding/smart_pointer_test.py302
-rw-r--r--sources/shiboken6/tests/smartbinding/smartbinding.pyproject7
-rw-r--r--sources/shiboken6/tests/smartbinding/std_optional_test.py69
-rw-r--r--sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py87
-rw-r--r--sources/shiboken6/tests/smartbinding/std_unique_ptr_test.py94
-rw-r--r--sources/shiboken6/tests/smartbinding/typesystem_smart.xml81
-rw-r--r--sources/shiboken6/tests/test_generator/CMakeLists.txt65
-rw-r--r--sources/shiboken6/tests/test_generator/dummygenerator.cpp45
-rw-r--r--sources/shiboken6/tests/test_generator/dummygenerator.h24
-rw-r--r--sources/shiboken6/tests/test_generator/dummygentest-project.txt.in20
-rw-r--r--sources/shiboken6/tests/test_generator/dummygentest.cpp114
-rw-r--r--sources/shiboken6/tests/test_generator/dummygentest.h31
-rw-r--r--sources/shiboken6/tests/test_generator/dummygentestconfig.h.in15
-rw-r--r--sources/shiboken6/tests/test_generator/main.cpp14
-rw-r--r--sources/shiboken6/tests/test_generator/run_test.cmake14
-rw-r--r--sources/shiboken6/tests/test_generator/test_global.h1
-rw-r--r--sources/shiboken6/tests/test_generator/test_typesystem.xml3
818 files changed, 126965 insertions, 0 deletions
diff --git a/sources/shiboken6/.cmake.conf b/sources/shiboken6/.cmake.conf
new file mode 100644
index 000000000..ecc0a433d
--- /dev/null
+++ b/sources/shiboken6/.cmake.conf
@@ -0,0 +1,5 @@
+set(shiboken_MAJOR_VERSION "6")
+set(shiboken_MINOR_VERSION "7")
+set(shiboken_MICRO_VERSION "0")
+set(shiboken_PRE_RELEASE_VERSION_TYPE "a")
+set(shiboken_PRE_RELEASE_VERSION "1")
diff --git a/sources/shiboken6/.gitattributes b/sources/shiboken6/.gitattributes
new file mode 100644
index 000000000..adbe833c1
--- /dev/null
+++ b/sources/shiboken6/.gitattributes
@@ -0,0 +1,2 @@
+.gitignore export-ignore
+.gitattributes export-ignore
diff --git a/sources/shiboken6/.gitignore b/sources/shiboken6/.gitignore
new file mode 100644
index 000000000..adb1e4594
--- /dev/null
+++ b/sources/shiboken6/.gitignore
@@ -0,0 +1,8 @@
+build
+.kdev4
+*.log
+*.pyc
+*.o
+*.so
+.*.swp
+*.kdev4
diff --git a/sources/shiboken6/AUTHORS b/sources/shiboken6/AUTHORS
new file mode 100644
index 000000000..4bb16b2dd
--- /dev/null
+++ b/sources/shiboken6/AUTHORS
@@ -0,0 +1,12 @@
+John Cummings <jcummings2@users.sf.net>
+John Ehresman <jpe@wingware.com>
+Roman Lacko <backup.rlacko@gmail.com>
+Matthew Woehlke <matthew.woehlke@kitware.com>
+Anderson Lizardo <anderson.lizardo@openbossa.org>
+Bruno Araujo <bruno.araujo@openbossa.org>
+Hugo Parente Lima <hugo.lima@openbossa.org>
+Lauro Moura <lauro.neto@openbossa.org>
+Luciano Wolf <luciano.wolf@openbossa.org>
+Marcelo Lira <marcelo.lira@openbossa.org>
+Renato Araujo Oliveira Filho <renato.filho@openbossa.org>
+
diff --git a/sources/shiboken6/ApiExtractor/AUTHORS b/sources/shiboken6/ApiExtractor/AUTHORS
new file mode 100644
index 000000000..6e802fb53
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/AUTHORS
@@ -0,0 +1,8 @@
+Anderson Lizardo <anderson.lizardo@openbossa.org>
+Bruno Araujo <bruno.araujo@openbossa.org>
+Hugo Parente Lima <hugo.lima@openbossa.org>
+Lauro Moura <lauro.neto@openbossa.org>
+Luciano Wolf <luciano.wolf@openbossa.org>
+Marcelo Lira <marcelo.lira@openbossa.org>
+Renato Araujo Oliveira Filho <renato.filho@openbossa.org>
+
diff --git a/sources/shiboken6/ApiExtractor/CMakeLists.txt b/sources/shiboken6/ApiExtractor/CMakeLists.txt
new file mode 100644
index 000000000..7aa2fbd11
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/CMakeLists.txt
@@ -0,0 +1,138 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(apiextractor)
+
+cmake_minimum_required(VERSION 3.18)
+cmake_policy(VERSION 3.18)
+
+set(CMAKE_AUTOMOC ON)
+
+set(apiextractor_SRC
+abstractmetaargument.cpp abstractmetaargument.h
+abstractmetabuilder.cpp abstractmetabuilder.h abstractmetabuilder_p.h
+abstractmetabuilder_helpers.cpp
+abstractmetaenum.cpp abstractmetaenum.h
+abstractmetafield.cpp abstractmetafield.h
+abstractmetafunction.cpp abstractmetafunction.h
+abstractmetalang.cpp abstractmetalang.h abstractmetalang_helpers.h abstractmetalang_typedefs.h
+abstractmetatype.cpp abstractmetatype.h
+addedfunction.cpp addedfunction.h addedfunction_p.h
+anystringview_helpers.cpp anystringview_helpers.h
+apiextractor.cpp apiextractor.h apiextractorflags.h
+apiextractorresult.cpp apiextractorresult.h
+arraytypeentry.h
+classdocumentation.cpp classdocumentation.h
+codesnip.cpp codesnip.h
+codesniphelpers.cpp codesniphelpers.h
+complextypeentry.h
+conditionalstreamreader.cpp conditionalstreamreader.h
+configurabletypeentry.h
+constantvaluetypeentry.h
+containertypeentry.h
+customconversion.cpp customconversion.h customconversion_typedefs.h
+customtypenentry.h
+debughelpers_p.h
+dependency.h
+documentation.cpp documentation.h
+dotview.cpp dotview.h
+enclosingclassmixin.cpp enclosingclassmixin.h
+enumtypeentry.h
+enumvaluetypeentry.h
+exception.h
+fileout.cpp fileout.h
+flagstypeentry.h
+functiontypeentry.h
+graph.h
+header_paths.h
+include.cpp include.h
+messages.cpp messages.h
+modifications.cpp modifications.h modifications_typedefs.h
+namespacetypeentry.h
+objecttypeentry.h
+optionsparser.cpp optionsparser.h
+predefined_templates.cpp predefined_templates.h
+primitivetypeentry.h
+propertyspec.cpp propertyspec.h
+pymethoddefentry.cpp pymethoddefentry.h
+pythontypeentry.h
+reporthandler.cpp reporthandler.h
+smartpointertypeentry.h
+sourcelocation.cpp sourcelocation.h
+templateargumententry.h
+textstream.cpp textstream.h
+typedatabase.cpp typedatabase.h typedatabase_p.h typedatabase_typedefs.h
+typedefentry.h
+typeparser.cpp typeparser.h
+typesystem.cpp typesystem.h typesystem_enums.h typesystem_typedefs.h
+typesystemparser.cpp typesystemparser_p.h
+usingmember.h
+valuetypeentry.h
+varargstypeentry.h
+voidtypeentry.h
+xmlutils.cpp xmlutils.h xmlutils_libxslt.h xmlutils_qt.h
+# Clang
+clangparser/clangbuilder.cpp clangparser/clangbuilder.h
+clangparser/clangdebugutils.cpp clangparser/clangdebugutils.h
+clangparser/clangparser.cpp clangparser/clangparser.h
+clangparser/clangutils.cpp clangparser/clangutils.h
+clangparser/compilersupport.cpp clangparser/compilersupport.h
+# Old parser
+parser/codemodel.cpp parser/codemodel.h parser/codemodel_fwd.h parser/codemodel_enums.h
+parser/enumvalue.cpp parser/enumvalue.h
+parser/typeinfo.cpp parser/typeinfo.h
+)
+
+find_package(LibXml2 2.6.32)
+find_package(LibXslt 1.1.19)
+
+set(HAS_LIBXSLT 0)
+if (LIBXSLT_FOUND AND LIBXML2_FOUND)
+ set(HAS_LIBXSLT 1)
+endif()
+
+if(NOT HAS_LIBXSLT)
+ set(DISABLE_DOCSTRINGS TRUE)
+ message(WARNING
+ "Documentation will not be built due to missing dependency (libxslt not found).")
+endif()
+
+# Export to parent scope so that generator/CMakeLists.txt gets it
+set(DISABLE_DOCSTRINGS ${DISABLE_DOCSTRINGS} PARENT_SCOPE)
+
+add_library(apiextractor STATIC ${apiextractor_SRC})
+target_include_directories(apiextractor PRIVATE ${CLANG_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/parser)
+target_link_libraries(apiextractor PUBLIC Qt::Core)
+target_link_libraries(apiextractor PRIVATE libclang)
+
+if (HAS_LIBXSLT)
+ target_compile_definitions(apiextractor PUBLIC HAVE_LIBXSLT)
+ target_sources(apiextractor PRIVATE xmlutils_libxslt.cpp)
+ target_include_directories(apiextractor
+ PRIVATE ${LIBXSLT_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})
+ target_link_libraries(apiextractor
+ PRIVATE ${LIBXSLT_LIBRARIES} ${LIBXML2_LIBRARIES})
+endif()
+
+if (NOT DISABLE_DOCSTRINGS)
+ target_sources(apiextractor PRIVATE
+ docparser.cpp docparser.h
+ doxygenparser.cpp doxygenparser.h
+ qtdocparser.cpp qtdocparser.h)
+endif()
+
+target_compile_definitions(apiextractor
+ PRIVATE CMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}"
+ PRIVATE QT_LEAN_HEADERS=1)
+
+set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE)
+
+if (BUILD_TESTS)
+ find_package(Qt6 REQUIRED COMPONENTS Test)
+ set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/tests)
+ enable_testing()
+ add_subdirectory(tests)
+endif()
diff --git a/sources/shiboken6/ApiExtractor/COPYING b/sources/shiboken6/ApiExtractor/COPYING
new file mode 100644
index 000000000..4ccd71466
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/COPYING
@@ -0,0 +1,342 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+-------------------------------------------------------------------------
diff --git a/sources/shiboken6/ApiExtractor/abstractmetaargument.cpp b/sources/shiboken6/ApiExtractor/abstractmetaargument.cpp
new file mode 100644
index 000000000..05cebe10a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetaargument.cpp
@@ -0,0 +1,201 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstractmetaargument.h"
+#include "abstractmetatype.h"
+#include "documentation.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QSharedData>
+
+using namespace Qt::StringLiterals;
+
+class AbstractMetaArgumentData : public QSharedData
+{
+public:
+ QString toString() const;
+
+ QString m_name;
+ AbstractMetaType m_type;
+ AbstractMetaType m_modifiedType;
+ bool m_hasName = false;
+ Documentation m_doc;
+ QString m_expression;
+ QString m_originalExpression;
+ int m_argumentIndex = 0;
+ bool m_modifiedRemoved = false;
+};
+
+AbstractMetaArgument::AbstractMetaArgument() : d(new AbstractMetaArgumentData)
+{
+}
+
+AbstractMetaArgument::~AbstractMetaArgument() = default;
+
+AbstractMetaArgument::AbstractMetaArgument(const AbstractMetaArgument &) = default;
+
+AbstractMetaArgument &AbstractMetaArgument::operator=(const AbstractMetaArgument &) = default;
+
+AbstractMetaArgument::AbstractMetaArgument(AbstractMetaArgument &&) noexcept = default;
+
+AbstractMetaArgument &AbstractMetaArgument::operator=(AbstractMetaArgument &&) noexcept = default;
+
+const AbstractMetaType &AbstractMetaArgument::type() const
+{
+ return d->m_type;
+}
+
+void AbstractMetaArgument::setType(const AbstractMetaType &type)
+{
+ if (d->m_type != type)
+ d->m_type = d->m_modifiedType = type;
+}
+
+const AbstractMetaType &AbstractMetaArgument::modifiedType() const
+{
+ return d->m_modifiedType;
+}
+
+bool AbstractMetaArgument::isTypeModified() const
+{
+ return modifiedType() != type();
+}
+
+bool AbstractMetaArgument::isModifiedRemoved() const
+{
+ return d->m_modifiedRemoved;
+}
+
+void AbstractMetaArgument::setModifiedRemoved(bool v)
+{
+ if (d->m_modifiedRemoved != v)
+ d->m_modifiedRemoved = v;
+}
+
+void AbstractMetaArgument::setModifiedType(const AbstractMetaType &type)
+{
+ if (d->m_modifiedType != type)
+ d->m_modifiedType = type;
+}
+
+QString AbstractMetaArgument::name() const
+{
+ return d->m_name;
+}
+
+void AbstractMetaArgument::setName(const QString &name, bool realName)
+{
+ if (d->m_name != name || d->m_hasName != realName) {
+ d->m_name = name;
+ d->m_hasName = realName;
+ }
+}
+
+bool AbstractMetaArgument::hasName() const
+{
+ return d->m_hasName;
+}
+
+void AbstractMetaArgument::setDocumentation(const Documentation &doc)
+{
+ if (d->m_doc != doc)
+ d->m_doc = doc;
+}
+
+Documentation AbstractMetaArgument::documentation() const
+{
+ return d->m_doc;
+}
+
+QString AbstractMetaArgument::defaultValueExpression() const
+{
+ return d->m_expression;
+}
+
+void AbstractMetaArgument::setDefaultValueExpression(const QString &expr)
+{
+ if (d->m_expression != expr)
+ d->m_expression = expr;
+}
+
+QString AbstractMetaArgument::originalDefaultValueExpression() const
+{
+ return d->m_originalExpression;
+}
+
+void AbstractMetaArgument::setOriginalDefaultValueExpression(const QString &expr)
+{
+ if (d->m_originalExpression != expr)
+ d->m_originalExpression = expr;
+}
+
+bool AbstractMetaArgument::hasOriginalDefaultValueExpression() const
+{
+ return !d->m_originalExpression.isEmpty();
+}
+
+bool AbstractMetaArgument::hasDefaultValueExpression() const
+{
+ return !d->m_expression.isEmpty();
+}
+
+bool AbstractMetaArgument::hasUnmodifiedDefaultValueExpression() const
+{
+ return !d->m_originalExpression.isEmpty() && d->m_originalExpression == d->m_expression;
+}
+
+bool AbstractMetaArgument::hasModifiedDefaultValueExpression() const
+{
+ return !d->m_expression.isEmpty() && d->m_originalExpression != d->m_expression;
+}
+
+QString AbstractMetaArgumentData::toString() const
+{
+ QString result = m_type.name() + u' ' + m_name;
+ if (!m_expression.isEmpty())
+ result += u" = "_s + m_expression;
+ return result;
+}
+
+QString AbstractMetaArgument::toString() const
+{
+ return d->toString();
+}
+
+int AbstractMetaArgument::argumentIndex() const
+{
+ return d->m_argumentIndex;
+}
+
+void AbstractMetaArgument::setArgumentIndex(int argIndex)
+{
+ if (d->m_argumentIndex != argIndex)
+ d->m_argumentIndex = argIndex;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaArgument &aa)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaArgument(" << aa.toString() << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaArgument *aa)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaArgument(";
+ if (aa != nullptr)
+ d << aa->toString();
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/abstractmetaargument.h b/sources/shiboken6/ApiExtractor/abstractmetaargument.h
new file mode 100644
index 000000000..38402e369
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetaargument.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETAARGUMENT_H
+#define ABSTRACTMETAARGUMENT_H
+
+#include <QtCore/QSharedDataPointer>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class AbstractMetaType;
+class AbstractMetaArgumentData;
+class Documentation;
+
+class AbstractMetaArgument
+{
+public:
+ AbstractMetaArgument();
+ ~AbstractMetaArgument();
+ AbstractMetaArgument(const AbstractMetaArgument &);
+ AbstractMetaArgument &operator=(const AbstractMetaArgument &);
+ AbstractMetaArgument(AbstractMetaArgument &&) noexcept;
+ AbstractMetaArgument &operator=(AbstractMetaArgument &&) noexcept;
+
+ const AbstractMetaType &type() const;
+ void setType(const AbstractMetaType &type);
+ void setModifiedType(const AbstractMetaType &type);
+ const AbstractMetaType &modifiedType() const;
+ bool isTypeModified() const;
+
+ bool isModifiedRemoved() const;
+ void setModifiedRemoved(bool v);
+
+ QString name() const;
+ void setName(const QString &name, bool realName = true);
+ bool hasName() const;
+
+ void setDocumentation(const Documentation& doc);
+ Documentation documentation() const;
+
+ QString defaultValueExpression() const;
+ void setDefaultValueExpression(const QString &expr);
+
+ QString originalDefaultValueExpression() const;
+ void setOriginalDefaultValueExpression(const QString &expr);
+
+ bool hasDefaultValueExpression() const;
+ bool hasOriginalDefaultValueExpression() const;
+ bool hasUnmodifiedDefaultValueExpression() const;
+ bool hasModifiedDefaultValueExpression() const;
+
+ QString toString() const;
+
+ int argumentIndex() const;
+ void setArgumentIndex(int argIndex);
+
+private:
+ QSharedDataPointer<AbstractMetaArgumentData> d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaArgument &aa);
+QDebug operator<<(QDebug d, const AbstractMetaArgument *aa);
+#endif
+
+#endif // ABSTRACTMETAARGUMENT_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
new file mode 100644
index 000000000..fa0767a62
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
@@ -0,0 +1,3749 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstractmetabuilder_p.h"
+#include "abstractmetaargument.h"
+#include "abstractmetaenum.h"
+#include "abstractmetafield.h"
+#include "abstractmetafunction.h"
+#include "abstractmetatype.h"
+#include "addedfunction.h"
+#include "graph.h"
+#include "debughelpers_p.h"
+#include "exception.h"
+#include "messages.h"
+#include "propertyspec.h"
+#include "reporthandler.h"
+#include "sourcelocation.h"
+#include "typedatabase.h"
+#include "enumtypeentry.h"
+#include "enumvaluetypeentry.h"
+#include "arraytypeentry.h"
+#include "constantvaluetypeentry.h"
+#include "containertypeentry.h"
+#include "flagstypeentry.h"
+#include "functiontypeentry.h"
+#include "namespacetypeentry.h"
+#include "primitivetypeentry.h"
+#include "smartpointertypeentry.h"
+#include "templateargumententry.h"
+#include "typedefentry.h"
+#include "typesystemtypeentry.h"
+#include "usingmember.h"
+
+#include "parser/codemodel.h"
+
+#include <clangparser/clangbuilder.h>
+#include <clangparser/clangutils.h>
+#include <clangparser/compilersupport.h>
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QMetaObject>
+#include <QtCore/QQueue>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QTextStream>
+
+#include <cstdio>
+#include <algorithm>
+#include <memory>
+
+using namespace Qt::StringLiterals;
+
+static QString stripTemplateArgs(const QString &name)
+{
+ const auto pos = name.indexOf(u'<');
+ return pos < 0 ? name : name.left(pos);
+}
+
+static void fixArgumentIndexes(AbstractMetaArgumentList *list)
+{
+ for (qsizetype i = 0, size = list->size(); i < size; ++i)
+ (*list)[i].setArgumentIndex(i);
+}
+
+bool operator<(const RejectEntry &re1, const RejectEntry &re2)
+{
+ return re1.reason != re2.reason
+ ? (re1.reason < re2.reason) : (re1.sortkey < re2.sortkey);
+}
+
+QTextStream &operator<<(QTextStream &str, const RejectEntry &re)
+{
+ str << re.signature;
+ if (!re.message.isEmpty())
+ str << ": " << re.message;
+ return str;
+}
+
+static void applyCachedFunctionModifications(AbstractMetaFunction *metaFunction,
+ const FunctionModificationList &functionMods)
+{
+ for (const FunctionModification &mod : functionMods) {
+ if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified)
+ metaFunction->setExceptionHandlingModification(mod.exceptionHandling());
+ if (mod.allowThread() != TypeSystem::AllowThread::Unspecified)
+ metaFunction->setAllowThreadModification(mod.allowThread());
+ }
+}
+
+bool AbstractMetaBuilderPrivate::m_useGlobalHeader = false;
+bool AbstractMetaBuilderPrivate::m_codeModelTestMode = false;
+
+AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() :
+ m_logDirectory(u"."_s + QDir::separator())
+{
+}
+
+AbstractMetaBuilder::AbstractMetaBuilder() : d(new AbstractMetaBuilderPrivate)
+{
+ d->q = this;
+}
+
+AbstractMetaBuilder::~AbstractMetaBuilder()
+{
+ delete d;
+}
+
+const AbstractMetaClassList &AbstractMetaBuilder::classes() const
+{
+ return d->m_metaClasses;
+}
+
+AbstractMetaClassList AbstractMetaBuilder::takeClasses()
+{
+ AbstractMetaClassList result;
+ qSwap(result, d->m_metaClasses);
+ return result;
+}
+
+const AbstractMetaClassList &AbstractMetaBuilder::templates() const
+{
+ return d->m_templates;
+}
+
+AbstractMetaClassList AbstractMetaBuilder::takeTemplates()
+{
+ AbstractMetaClassList result;
+ qSwap(result, d->m_templates);
+ return result;
+}
+
+const AbstractMetaClassList &AbstractMetaBuilder::smartPointers() const
+{
+ return d->m_smartPointers;
+}
+
+AbstractMetaClassList AbstractMetaBuilder::takeSmartPointers()
+{
+ AbstractMetaClassList result;
+ qSwap(result, d->m_smartPointers);
+ return result;
+}
+
+const AbstractMetaFunctionCList &AbstractMetaBuilder::globalFunctions() const
+{
+ return d->m_globalFunctions;
+}
+
+const AbstractMetaEnumList &AbstractMetaBuilder::globalEnums() const
+{
+ return d->m_globalEnums;
+}
+
+const QHash<TypeEntryCPtr, AbstractMetaEnum> &AbstractMetaBuilder::typeEntryToEnumsHash() const
+{
+ return d->m_enums;
+}
+
+const QMultiHash<QString, QString> &AbstractMetaBuilder::typedefTargetToName() const
+{
+ return d->m_typedefTargetToName;
+}
+
+void AbstractMetaBuilderPrivate::checkFunctionModifications() const
+{
+ const auto &entries = TypeDatabase::instance()->entries();
+
+ for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
+ TypeEntryCPtr entry = it.value();
+ if (!entry)
+ continue;
+ if (!entry->isComplex() || !entry->generateCode())
+ continue;
+
+ auto centry = std::static_pointer_cast<const ComplexTypeEntry>(entry);
+
+ if (!centry->generateCode())
+ continue;
+
+ FunctionModificationList modifications = centry->functionModifications();
+
+ for (const FunctionModification &modification : std::as_const(modifications)) {
+ QString signature = modification.signature();
+
+ QString name = signature.trimmed();
+ name.truncate(name.indexOf(u'('));
+
+ const auto clazz = AbstractMetaClass::findClass(m_metaClasses, centry);
+ if (!clazz)
+ continue;
+
+ bool found = false;
+ QStringList possibleSignatures;
+ for (const auto &function : clazz->functions()) {
+ if (function->implementingClass() == clazz
+ && modification.matches(function->modificationSignatures())) {
+ found = true;
+ break;
+ }
+
+ if (function->originalName() == name) {
+ const QString signatures = function->modificationSignatures().join(u'/');
+ possibleSignatures.append(signatures + u" in "_s
+ + function->implementingClass()->name());
+ }
+ }
+
+ if (!found) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << msgNoFunctionForModification(clazz, signature,
+ modification.originalSignature(),
+ possibleSignatures, clazz->functions());
+ }
+ }
+ }
+}
+
+AbstractMetaClassPtr AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument,
+ const AbstractMetaClassCPtr &currentClass)
+{
+ AbstractMetaClassPtr returned;
+ auto type = translateType(argument->type(), currentClass);
+ if (!type.has_value())
+ return returned;
+ TypeEntryCPtr entry = type->typeEntry();
+ if (entry && entry->isComplex())
+ returned = AbstractMetaClass::findClass(m_metaClasses, entry);
+ return returned;
+}
+
+/**
+ * Checks the argument of a hash function and flags the type if it is a complex type
+ */
+void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &function_item,
+ const AbstractMetaClassPtr &currentClass)
+{
+ if (function_item->isDeleted())
+ return;
+ ArgumentList arguments = function_item->arguments();
+ if (arguments.size() >= 1) { // (Class, Hash seed).
+ if (AbstractMetaClassPtr cls = argumentToClass(arguments.at(0), currentClass))
+ cls->setHashFunction(function_item->name());
+ }
+}
+
+void AbstractMetaBuilderPrivate::registerToStringCapabilityIn(const NamespaceModelItem &nsItem)
+{
+ const FunctionList &streamOps = nsItem->findFunctions("operator<<");
+ for (const FunctionModelItem &item : streamOps)
+ registerToStringCapability(item, nullptr);
+ for (const NamespaceModelItem &ni : nsItem->namespaces())
+ registerToStringCapabilityIn(ni);
+}
+
+/**
+ * Check if a class has a debug stream operator that can be used as toString
+ */
+
+void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelItem &function_item,
+ const AbstractMetaClassPtr &currentClass)
+{
+ ArgumentList arguments = function_item->arguments();
+ if (arguments.size() == 2) {
+ if (arguments.at(0)->type().toString() == u"QDebug") {
+ const ArgumentModelItem &arg = arguments.at(1);
+ if (AbstractMetaClassPtr cls = argumentToClass(arg, currentClass)) {
+ if (arg->type().indirections() < 2)
+ cls->setToStringCapability(true, int(arg->type().indirections()));
+ }
+ }
+ }
+}
+
+void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelItem &item,
+ const AbstractMetaClassPtr &currentClass)
+{
+ if (item->accessPolicy() != Access::Public)
+ return;
+
+ const ArgumentList &itemArguments = item->arguments();
+ bool firstArgumentIsSelf = true;
+ bool unaryOperator = false;
+
+ auto baseoperandClass = argumentToClass(itemArguments.at(0), currentClass);
+
+ if (itemArguments.size() == 1) {
+ unaryOperator = true;
+ } else if (!baseoperandClass
+ || !baseoperandClass->typeEntry()->generateCode()) {
+ baseoperandClass = argumentToClass(itemArguments.at(1), currentClass);
+ firstArgumentIsSelf = false;
+ } else {
+ auto type = translateType(item->type(), currentClass);
+ const auto retType = type.has_value() ? type->typeEntry() : TypeEntryCPtr{};
+ const auto otherArgClass = argumentToClass(itemArguments.at(1), currentClass);
+ if (otherArgClass && retType
+ && (retType->isValue() || retType->isObject())
+ && retType != baseoperandClass->typeEntry()
+ && retType == otherArgClass->typeEntry()) {
+ baseoperandClass = AbstractMetaClass::findClass(m_metaClasses, retType);
+ firstArgumentIsSelf = false;
+ }
+ }
+ if (!baseoperandClass) {
+ rejectFunction(item, currentClass, AbstractMetaBuilder::UnmatchedOperator,
+ u"base operand class not found."_s);
+ return;
+ }
+
+ if (item->isSpaceshipOperator() && !item->isDeleted()) {
+ AbstractMetaClass::addSynthesizedComparisonOperators(baseoperandClass);
+ return;
+ }
+
+ AbstractMetaFunction *metaFunction = traverseFunction(item, baseoperandClass);
+ if (metaFunction == nullptr)
+ return;
+
+ auto flags = metaFunction->flags();
+ // Strip away first argument, since that is the containing object
+ AbstractMetaArgumentList arguments = metaFunction->arguments();
+ if (firstArgumentIsSelf || unaryOperator) {
+ AbstractMetaArgument first = arguments.takeFirst();
+ fixArgumentIndexes(&arguments);
+ if (!unaryOperator && first.type().indirections())
+ metaFunction->setPointerOperator(true);
+ metaFunction->setArguments(arguments);
+ flags.setFlag(AbstractMetaFunction::Flag::OperatorLeadingClassArgumentRemoved);
+ if (first.type().passByValue())
+ flags.setFlag(AbstractMetaFunction::Flag::OperatorClassArgumentByValue);
+ } else {
+ // If the operator method is not unary and the first operator is
+ // not of the same type of its owning class we suppose that it
+ // must be an reverse operator (e.g. CLASS::operator(TYPE, CLASS)).
+ // All operator overloads that operate over a class are already
+ // being added as member functions of that class by the API Extractor.
+ AbstractMetaArgument last = arguments.takeLast();
+ if (last.type().indirections())
+ metaFunction->setPointerOperator(true);
+ metaFunction->setArguments(arguments);
+ metaFunction->setReverseOperator(true);
+ flags.setFlag(AbstractMetaFunction::Flag::OperatorTrailingClassArgumentRemoved);
+ if (last.type().passByValue())
+ flags.setFlag(AbstractMetaFunction::Flag::OperatorClassArgumentByValue);
+ }
+ metaFunction->setFlags(flags);
+ metaFunction->setAccess(Access::Public);
+ AbstractMetaClass::addFunction(baseoperandClass, AbstractMetaFunctionCPtr(metaFunction));
+ if (!metaFunction->arguments().isEmpty()) {
+ const auto include = metaFunction->arguments().constFirst().type().typeEntry()->include();
+ baseoperandClass->typeEntry()->addArgumentInclude(include);
+ }
+ Q_ASSERT(!metaFunction->wasPrivate());
+}
+
+bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem &item,
+ const AbstractMetaClassPtr &currentClass)
+{
+ ArgumentList itemArguments = item->arguments();
+ if (itemArguments.size() != 2 || item->accessPolicy() != Access::Public)
+ return false;
+ auto streamClass = argumentToClass(itemArguments.at(0), currentClass);
+ if (streamClass == nullptr || !streamClass->isStream())
+ return false;
+ auto streamedClass = argumentToClass(itemArguments.at(1), currentClass);
+ if (streamedClass == nullptr)
+ return false;
+
+ AbstractMetaFunction *streamFunction = traverseFunction(item, streamedClass);
+ if (!streamFunction)
+ return false;
+
+ // Strip first argument, since that is the containing object
+ AbstractMetaArgumentList arguments = streamFunction->arguments();
+ if (!streamClass->typeEntry()->generateCode()) {
+ arguments.takeLast();
+ } else {
+ arguments.takeFirst();
+ fixArgumentIndexes(&arguments);
+ }
+
+ streamFunction->setArguments(arguments);
+
+ streamFunction->setAccess(Access::Public);
+
+ AbstractMetaClassPtr funcClass;
+
+ if (!streamClass->typeEntry()->generateCode()) {
+ AbstractMetaArgumentList reverseArgs = streamFunction->arguments();
+ std::reverse(reverseArgs.begin(), reverseArgs.end());
+ fixArgumentIndexes(&reverseArgs);
+ streamFunction->setArguments(reverseArgs);
+ streamFunction->setReverseOperator(true);
+ funcClass = streamedClass;
+ } else {
+ funcClass = streamClass;
+ }
+
+ AbstractMetaClass::addFunction(funcClass, AbstractMetaFunctionCPtr(streamFunction));
+ auto funcTe = funcClass->typeEntry();
+ if (funcClass == streamClass)
+ funcTe->addArgumentInclude(streamedClass->typeEntry()->include());
+ else
+ funcTe->addArgumentInclude(streamClass->typeEntry()->include());
+ return true;
+}
+
+static bool metaEnumLessThan(const AbstractMetaEnum &e1, const AbstractMetaEnum &e2)
+{ return e1.fullName() < e2.fullName(); }
+
+static bool metaClassLessThan(const AbstractMetaClassCPtr &c1, const AbstractMetaClassCPtr &c2)
+{ return c1->fullName() < c2->fullName(); }
+
+static bool metaFunctionLessThan(const AbstractMetaFunctionCPtr &f1, const AbstractMetaFunctionCPtr &f2)
+{ return f1->name() < f2->name(); }
+
+void AbstractMetaBuilderPrivate::sortLists()
+{
+ // Ensure indepedent classes are in alphabetical order,
+ std::sort(m_metaClasses.begin(), m_metaClasses.end(), metaClassLessThan);
+ // this is a temporary solution before new type revision implementation
+ // We need move QMetaObject register before QObject.
+ Dependencies additionalDependencies;
+ if (auto qObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QObject")) {
+ if (auto qMetaObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QMetaObject")) {
+ Dependency dependency;
+ dependency.parent = qMetaObjectClass;
+ dependency.child = qObjectClass;
+ additionalDependencies.append(dependency);
+ }
+ }
+ m_metaClasses = classesTopologicalSorted(m_metaClasses, additionalDependencies);
+
+ for (const auto &cls : std::as_const(m_metaClasses))
+ cls->sortFunctions();
+
+ // Ensure that indexes are in alphabetical order, roughly, except
+ // for classes, which are in topological order
+ std::sort(m_globalEnums.begin(), m_globalEnums.end(), metaEnumLessThan);
+ std::sort(m_templates.begin(), m_templates.end(), metaClassLessThan);
+ std::sort(m_smartPointers.begin(), m_smartPointers.end(), metaClassLessThan);
+ std::sort(m_globalFunctions.begin(), m_globalFunctions.end(), metaFunctionLessThan);
+}
+
+FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments,
+ bool addCompilerSupportArguments,
+ LanguageLevel level,
+ unsigned clangFlags)
+{
+ clang::Builder builder;
+ builder.setForceProcessSystemIncludes(TypeDatabase::instance()->forceProcessSystemIncludes());
+ if (addCompilerSupportArguments) {
+ if (level == LanguageLevel::Default)
+ level = clang::emulatedCompilerLanguageLevel();
+ arguments.prepend(QByteArrayLiteral("-std=")
+ + clang::languageLevelOption(level));
+ }
+ FileModelItem result = clang::parse(arguments, addCompilerSupportArguments,
+ level, clangFlags, builder)
+ ? builder.dom() : FileModelItem();
+ const clang::BaseVisitor::Diagnostics &diagnostics = builder.diagnostics();
+ if (const auto diagnosticsCount = diagnostics.size()) {
+ QDebug d = qWarning();
+ d.nospace();
+ d.noquote();
+ d << "Clang: " << diagnosticsCount << " diagnostic messages:\n";
+ for (qsizetype i = 0; i < diagnosticsCount; ++i)
+ d << " " << diagnostics.at(i) << '\n';
+ }
+ return result;
+}
+
+// List of candidates for a mismatched added global function.
+static QStringList functionCandidates(const AbstractMetaFunctionCList &list,
+ const QString &signature)
+{
+ QString name = signature;
+ const auto parenPos = name.indexOf(u'(');
+ if (parenPos > 0)
+ name.truncate(parenPos);
+ QStringList result;
+ for (const auto &func : list) {
+ if (name == func->name())
+ result += func->minimalSignature();
+ }
+ return result;
+}
+
+void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom,
+ ApiExtractorFlags flags)
+{
+ const TypeDatabase *types = TypeDatabase::instance();
+
+ pushScope(dom);
+
+ // Start the generation...
+ const ClassList &typeValues = dom->classes();
+
+ ReportHandler::startProgress("Generated class model ("
+ + QByteArray::number(typeValues.size()) + ").");
+ for (const ClassModelItem &item : typeValues) {
+ if (const auto cls = traverseClass(dom, item, nullptr))
+ addAbstractMetaClass(cls, item.get());
+ }
+
+ // We need to know all global enums
+ const EnumList &enums = dom->enums();
+
+ ReportHandler::startProgress("Generated enum model ("
+ + QByteArray::number(enums.size()) + ").");
+ for (const EnumModelItem &item : enums) {
+ auto metaEnum = traverseEnum(item, nullptr, QSet<QString>());
+ if (metaEnum.has_value()) {
+ if (metaEnum->typeEntry()->generateCode())
+ m_globalEnums << metaEnum.value();
+ }
+ }
+
+ const auto &namespaceTypeValues = dom->namespaces();
+ ReportHandler::startProgress("Generated namespace model ("
+ + QByteArray::number(namespaceTypeValues.size()) + ").");
+ for (const NamespaceModelItem &item : namespaceTypeValues)
+ traverseNamespace(dom, item);
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ const TypeDefList typeDefs = dom->typeDefs();
+ ReportHandler::startProgress("Resolved typedefs ("
+ + QByteArray::number(typeDefs.size()) + ").");
+ for (const TypeDefModelItem &typeDef : typeDefs) {
+ if (const auto cls = traverseTypeDef(dom, typeDef, nullptr))
+ addAbstractMetaClass(cls, typeDef.get());
+ }
+
+ traverseTypesystemTypedefs();
+
+ for (const ClassModelItem &item : typeValues)
+ traverseClassMembers(item);
+
+ for (const NamespaceModelItem &item : namespaceTypeValues)
+ traverseNamespaceMembers(item);
+
+ // Global functions
+ const FunctionList &functions = dom->functions();
+ for (const FunctionModelItem &func : functions) {
+ if (func->accessPolicy() != Access::Public || func->name().startsWith(u"operator"))
+ continue;
+
+ FunctionTypeEntryPtr funcEntry = types->findFunctionType(func->name());
+ if (!funcEntry || !funcEntry->generateCode())
+ continue;
+
+ AbstractMetaFunction *metaFunc = traverseFunction(func, nullptr);
+ if (!metaFunc)
+ continue;
+
+ AbstractMetaFunctionCPtr metaFuncPtr(metaFunc);
+ if (!funcEntry->hasSignature(metaFunc->minimalSignature()))
+ continue;
+
+ metaFunc->setTypeEntry(funcEntry);
+ applyFunctionModifications(metaFunc);
+ metaFunc->applyTypeModifications();
+
+ setInclude(funcEntry, func->fileName());
+
+ m_globalFunctions << metaFuncPtr;
+ }
+
+ ReportHandler::startProgress("Fixed class inheritance.");
+ for (const auto &cls : std::as_const(m_metaClasses)) {
+ if (cls->needsInheritanceSetup()) {
+ setupInheritance(cls);
+ traverseUsingMembers(cls);
+ if (cls->templateBaseClass())
+ inheritTemplateFunctions(cls);
+ if (!cls->hasVirtualDestructor() && cls->baseClass()
+ && cls->baseClass()->hasVirtualDestructor())
+ cls->setHasVirtualDestructor(true);
+ }
+ }
+
+ ReportHandler::startProgress("Checked for inconsistencies in class model.");
+ for (const auto &cls : std::as_const(m_metaClasses)) {
+ AbstractMetaClass::fixFunctions(cls);
+
+ if (cls->canAddDefaultConstructor())
+ AbstractMetaClass::addDefaultConstructor(cls);
+ if (cls->canAddDefaultCopyConstructor())
+ AbstractMetaClass::addDefaultCopyConstructor(cls);
+
+ const bool avoidProtectedHack = flags.testFlag(ApiExtractorFlag::AvoidProtectedHack);
+ const bool vco =
+ AbstractMetaClass::determineValueTypeWithCopyConstructorOnly(cls, avoidProtectedHack);
+ cls->setValueTypeWithCopyConstructorOnly(vco);
+ cls->typeEntry()->setValueTypeWithCopyConstructorOnly(vco);
+ }
+
+ const auto &allEntries = types->entries();
+
+ ReportHandler::startProgress("Checked for inconsistencies in typesystem ("
+ + QByteArray::number(allEntries.size()) + ").");
+ for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
+ const TypeEntryPtr &entry = it.value();
+ if (!entry->isPrimitive()) {
+ if ((entry->isValue() || entry->isObject())
+ && !types->shouldDropTypeEntry(entry->qualifiedCppName())
+ && !entry->isContainer()
+ && !entry->isCustom()
+ && entry->generateCode()
+ && !AbstractMetaClass::findClass(m_metaClasses, entry)) {
+ qCWarning(lcShiboken, "%s", qPrintable(msgTypeNotDefined(entry)));
+ } else if (entry->generateCode() && entry->type() == TypeEntry::FunctionType) {
+ auto fte = std::static_pointer_cast<const FunctionTypeEntry>(entry);
+ const QStringList &signatures = fte->signatures();
+ for (const QString &signature : signatures) {
+ bool ok = false;
+ for (const auto &func : std::as_const(m_globalFunctions)) {
+ if (signature == func->minimalSignature()) {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok) {
+ const QStringList candidates = functionCandidates(m_globalFunctions,
+ signatures.constFirst());
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgGlobalFunctionNotDefined(fte, signature, candidates)));
+ }
+ }
+ } else if (entry->isEnum() && entry->generateCode()) {
+ const auto enumEntry = std::static_pointer_cast<const EnumTypeEntry>(entry);
+ const auto cls = AbstractMetaClass::findClass(m_metaClasses,
+ enumEntry->parent());
+
+ const bool enumFound = cls
+ ? cls->findEnum(entry->targetLangEntryName()).has_value()
+ : m_enums.contains(entry);
+
+ if (!enumFound) {
+ entry->setCodeGeneration(TypeEntry::GenerateNothing);
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgEnumNotDefined(enumEntry)));
+ }
+
+ }
+ }
+ }
+
+ {
+ const FunctionList &hashFunctions = dom->findFunctions("qHash");
+ for (const FunctionModelItem &item : hashFunctions)
+ registerHashFunction(item, nullptr);
+ }
+
+ registerToStringCapabilityIn(dom);
+
+ for (const auto &func : dom->functions()) {
+ switch (func->functionType()) {
+ case CodeModel::ComparisonOperator:
+ case CodeModel::ArithmeticOperator:
+ case CodeModel::BitwiseOperator:
+ case CodeModel::LogicalOperator:
+ traverseOperatorFunction(func, nullptr);
+ break;
+ case CodeModel::ShiftOperator:
+ if (!traverseStreamOperator(func, nullptr))
+ traverseOperatorFunction(func, nullptr);
+ default:
+ break;
+ }
+ }
+
+ ReportHandler::startProgress("Checked for inconsistencies in function modifications.");
+
+ checkFunctionModifications();
+
+ ReportHandler::startProgress("Wrote log files.");
+
+ for (const auto &cls : std::as_const(m_metaClasses)) {
+// setupEquals(cls);
+// setupComparable(cls);
+ setupExternalConversion(cls);
+
+ // sort all inner classes topologically
+ if (!cls->typeEntry()->codeGeneration() || cls->innerClasses().size() < 2)
+ continue;
+
+ cls->setInnerClasses(classesTopologicalSorted(cls->innerClasses()));
+ }
+
+ fixSmartPointers();
+
+ dumpLog();
+
+ sortLists();
+
+ // Functions added to the module on the type system.
+ QString errorMessage;
+ const AddedFunctionList &globalUserFunctions = types->globalUserFunctions();
+ for (const AddedFunctionPtr &addedFunc : globalUserFunctions) {
+ if (!traverseAddedGlobalFunction(addedFunc, &errorMessage))
+ throw Exception(errorMessage);
+ }
+
+ if (!m_codeModelTestMode) {
+ m_itemToClass.clear();
+ m_classToItem.clear();
+ m_typeSystemTypeDefs.clear();
+ m_scopes.clear();
+ }
+
+ ReportHandler::endProgress();
+}
+
+bool AbstractMetaBuilder::build(const QByteArrayList &arguments,
+ ApiExtractorFlags apiExtractorFlags,
+ bool addCompilerSupportArguments,
+ LanguageLevel level,
+ unsigned clangFlags)
+{
+ const FileModelItem dom = d->buildDom(arguments, addCompilerSupportArguments,
+ level, clangFlags);
+ if (!dom)
+ return false;
+ if (ReportHandler::isDebug(ReportHandler::MediumDebug))
+ qCDebug(lcShiboken) << dom.get();
+ d->traverseDom(dom, apiExtractorFlags);
+
+ return true;
+}
+
+void AbstractMetaBuilder::setLogDirectory(const QString &logDir)
+{
+ d->m_logDirectory = logDir;
+ if (!d->m_logDirectory.endsWith(QDir::separator()))
+ d->m_logDirectory.append(QDir::separator());
+}
+
+void AbstractMetaBuilderPrivate::addAbstractMetaClass(const AbstractMetaClassPtr &cls,
+ const _CodeModelItem *item)
+{
+ m_itemToClass.insert(item, cls);
+ m_classToItem.insert(cls, item);
+ if (cls->typeEntry()->isContainer()) {
+ m_templates << cls;
+ } else if (cls->typeEntry()->isSmartPointer()) {
+ m_smartPointers << cls;
+ } else {
+ m_metaClasses << cls;
+ }
+}
+
+AbstractMetaClassPtr
+ AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom,
+ const NamespaceModelItem &namespaceItem)
+{
+ QString namespaceName = currentScope()->qualifiedName().join(u"::"_s);
+ if (!namespaceName.isEmpty())
+ namespaceName.append(u"::"_s);
+ namespaceName.append(namespaceItem->name());
+
+ if (TypeDatabase::instance()->isClassRejected(namespaceName)) {
+ m_rejectedClasses.insert({AbstractMetaBuilder::GenerationDisabled,
+ namespaceName, namespaceName, QString{}});
+ return {};
+ }
+
+ auto type = TypeDatabase::instance()->findNamespaceType(namespaceName, namespaceItem->fileName());
+ if (!type) {
+ const QString rejectReason = msgNamespaceNoTypeEntry(namespaceItem, namespaceName);
+ qCWarning(lcShiboken, "%s", qPrintable(rejectReason));
+ m_rejectedClasses.insert({AbstractMetaBuilder::GenerationDisabled,
+ namespaceName, namespaceName, rejectReason});
+ return nullptr;
+ }
+
+ if (namespaceItem->type() == NamespaceType::Inline) {
+ type->setInlineNamespace(true);
+ TypeDatabase::instance()->addInlineNamespaceLookups(type);
+ }
+
+ // Continue populating namespace?
+ AbstractMetaClassPtr metaClass = AbstractMetaClass::findClass(m_metaClasses, type);
+ if (!metaClass) {
+ metaClass.reset(new AbstractMetaClass);
+ metaClass->setTypeEntry(type);
+ addAbstractMetaClass(metaClass, namespaceItem.get());
+ if (auto extendsType = type->extends()) {
+ const auto extended = AbstractMetaClass::findClass(m_metaClasses, extendsType);
+ if (!extended) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgNamespaceToBeExtendedNotFound(extendsType->name(), extendsType->targetLangPackage())));
+ return {};
+ }
+ metaClass->setExtendedNamespace(extended);
+ }
+ } else {
+ m_itemToClass.insert(namespaceItem.get(), metaClass);
+ }
+
+ traverseEnums(namespaceItem, metaClass, namespaceItem->enumsDeclarations());
+
+ pushScope(namespaceItem);
+
+ const ClassList &classes = namespaceItem->classes();
+ for (const ClassModelItem &cls : classes) {
+ const auto mjc = traverseClass(dom, cls, metaClass);
+ if (mjc) {
+ metaClass->addInnerClass(mjc);
+ mjc->setEnclosingClass(metaClass);
+ addAbstractMetaClass(mjc, cls.get());
+ }
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ const TypeDefList typeDefs = namespaceItem->typeDefs();
+ for (const TypeDefModelItem &typeDef : typeDefs) {
+ const auto cls = traverseTypeDef(dom, typeDef, metaClass);
+ if (cls) {
+ metaClass->addInnerClass(cls);
+ cls->setEnclosingClass(metaClass);
+ addAbstractMetaClass(cls, typeDef.get());
+ }
+ }
+
+ // Traverse namespaces recursively
+ for (const NamespaceModelItem &ni : namespaceItem->namespaces()) {
+ const auto mjc = traverseNamespace(dom, ni);
+ if (mjc) {
+ metaClass->addInnerClass(mjc);
+ mjc->setEnclosingClass(metaClass);
+ m_classToItem.insert(mjc, ni.get()); // Add for enum lookup.
+ m_itemToClass.insert(ni.get(), mjc);
+ }
+ }
+
+ popScope();
+
+ if (!type->include().isValid())
+ setInclude(type, namespaceItem->fileName());
+
+ return metaClass;
+}
+
+std::optional<AbstractMetaEnum>
+ AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem &enumItem,
+ const AbstractMetaClassPtr &enclosing,
+ const QSet<QString> &enumsDeclarations)
+{
+ QString qualifiedName = enumItem->qualifiedName().join(u"::"_s);
+
+ TypeEntryPtr typeEntry;
+ const auto enclosingTypeEntry = enclosing ? enclosing->typeEntry() : TypeEntryCPtr{};
+ if (enumItem->accessPolicy() == Access::Private) {
+ typeEntry.reset(new EnumTypeEntry(enumItem->qualifiedName().constLast(),
+ QVersionNumber(0, 0), enclosingTypeEntry));
+ TypeDatabase::instance()->addType(typeEntry);
+ } else if (enumItem->enumKind() != AnonymousEnum) {
+ typeEntry = TypeDatabase::instance()->findType(qualifiedName);
+ } else {
+ QStringList tmpQualifiedName = enumItem->qualifiedName();
+ const EnumeratorList &enums = enumItem->enumerators();
+ for (const EnumeratorModelItem &enumValue : enums) {
+ tmpQualifiedName.removeLast();
+ tmpQualifiedName << enumValue->name();
+ qualifiedName = tmpQualifiedName.join(u"::"_s);
+ typeEntry = TypeDatabase::instance()->findType(qualifiedName);
+ if (typeEntry)
+ break;
+ }
+ }
+
+ QString enumName = enumItem->name();
+
+ QString className;
+ if (enclosingTypeEntry)
+ className = enclosingTypeEntry->qualifiedCppName();
+
+ QString rejectReason;
+ if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) {
+ if (typeEntry)
+ typeEntry->setCodeGeneration(TypeEntry::GenerateNothing);
+ m_rejectedEnums.insert({AbstractMetaBuilder::GenerationDisabled, qualifiedName,
+ qualifiedName, rejectReason});
+ return {};
+ }
+
+ const bool rejectionWarning = !enclosing || enclosing->typeEntry()->generateCode();
+
+ if (!typeEntry) {
+ const QString rejectReason = msgNoEnumTypeEntry(enumItem, className);
+ if (rejectionWarning)
+ qCWarning(lcShiboken, "%s", qPrintable(rejectReason));
+ m_rejectedEnums.insert({AbstractMetaBuilder::NotInTypeSystem, qualifiedName,
+ qualifiedName, rejectReason});
+ return {};
+ }
+
+ if (!typeEntry->isEnum()) {
+ const QString rejectReason = msgNoEnumTypeConflict(enumItem, className, typeEntry);
+ if (rejectionWarning)
+ qCWarning(lcShiboken, "%s", qPrintable(rejectReason));
+ m_rejectedEnums.insert({AbstractMetaBuilder::NotInTypeSystem, qualifiedName,
+ qualifiedName, rejectReason});
+ return {};
+ }
+
+ AbstractMetaEnum metaEnum;
+ metaEnum.setEnumKind(enumItem->enumKind());
+ metaEnum.setDeprecated(enumItem->isDeprecated());
+ metaEnum.setUnderlyingType(enumItem->underlyingType());
+ metaEnum.setSigned(enumItem->isSigned());
+ if (enumsDeclarations.contains(qualifiedName)
+ || enumsDeclarations.contains(enumName)) {
+ metaEnum.setHasQEnumsDeclaration(true);
+ }
+
+ auto enumTypeEntry = std::static_pointer_cast<EnumTypeEntry>(typeEntry);
+ metaEnum.setTypeEntry(enumTypeEntry);
+ metaEnum.setAccess(enumItem->accessPolicy());
+ if (metaEnum.access() == Access::Private)
+ typeEntry->setCodeGeneration(TypeEntry::GenerateNothing);
+ // PYSIDE-2088, MSVC signedness issue in Qt
+ const bool castToUnsigned = enumItem->isSigned()
+ && enumTypeEntry->cppType().contains(u"unsigned"_s);
+ const EnumeratorList &enums = enumItem->enumerators();
+ for (const EnumeratorModelItem &valueItem : enums) {
+
+ AbstractMetaEnumValue metaEnumValue;
+ metaEnumValue.setName(valueItem->name());
+ // Deciding the enum value...
+
+ metaEnumValue.setStringValue(valueItem->stringValue());
+ const auto value = valueItem->value();
+ metaEnumValue.setValue(castToUnsigned ? value.toUnsigned() : value);
+ metaEnumValue.setDeprecated(valueItem->isDeprecated());
+ metaEnum.addEnumValue(metaEnumValue);
+ }
+
+ if (!metaEnum.typeEntry()->include().isValid()) {
+ auto te = std::const_pointer_cast<EnumTypeEntry>(metaEnum.typeEntry());
+ setInclude(te, enumItem->fileName());
+ }
+
+ // Register all enum values on Type database
+ const bool isScopedEnum = enumItem->enumKind() == EnumClass;
+ const EnumeratorList &enumerators = enumItem->enumerators();
+ for (const EnumeratorModelItem &e : enumerators) {
+ auto enumValue = std::make_shared<EnumValueTypeEntry>(e->name(), e->stringValue(),
+ enumTypeEntry, isScopedEnum,
+ enumTypeEntry->version());
+ TypeDatabase::instance()->addType(enumValue);
+ if (e->value().isNullValue())
+ enumTypeEntry->setNullValue(enumValue);
+ }
+
+ metaEnum.setEnclosingClass(enclosing);
+ m_enums.insert(typeEntry, metaEnum);
+
+ return metaEnum;
+}
+
+AbstractMetaClassPtr
+ AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &dom,
+ const TypeDefModelItem &typeDef,
+ const AbstractMetaClassPtr &currentClass)
+{
+ auto result = traverseTypeDefHelper(dom, typeDef, currentClass);
+ if (!result && typeDef->type().isPlain()) {
+ const auto &type = typeDef->type();
+ QString fullName;
+ if (currentClass)
+ fullName += currentClass->qualifiedCppName() + "::"_L1;
+ fullName += typeDef->name();
+ QString targetName = typeDef->type().toString();
+ m_typedefTargetToName.insert(targetName, fullName);
+ const QByteArray normalized = QMetaObject::normalizedType(targetName.toUtf8().constData());
+ if (targetName != QLatin1StringView(normalized))
+ m_typedefTargetToName.insert(QString::fromUtf8(normalized), fullName);
+ }
+ return result;
+}
+
+AbstractMetaClassPtr
+ AbstractMetaBuilderPrivate::traverseTypeDefHelper(const FileModelItem &,
+ const TypeDefModelItem &typeDef,
+ const AbstractMetaClassPtr &currentClass)
+{
+ TypeDatabase *types = TypeDatabase::instance();
+ QString className = stripTemplateArgs(typeDef->name());
+
+ QString fullClassName = className;
+ // we have an inner class
+ if (currentClass) {
+ fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName())
+ + u"::"_s + fullClassName;
+ }
+
+ // If this is the alias for a primitive type
+ // we store the aliased type on the alias
+ // TypeEntry
+ const auto ptype = types->findPrimitiveType(className);
+ const auto &targetNames = typeDef->type().qualifiedName();
+ const auto pTarget = targetNames.size() == 1
+ ? types->findPrimitiveType(targetNames.constFirst()) : PrimitiveTypeEntryPtr{};
+ if (ptype) {
+ ptype->setReferencedTypeEntry(pTarget);
+ return nullptr;
+ }
+
+ // It is a (nested?) global typedef to a primitive type
+ // (like size_t = unsigned)? Add it to the type DB.
+ if (pTarget && isCppPrimitive(basicReferencedNonBuiltinTypeEntry(pTarget))
+ && currentClass == nullptr) {
+ auto pte = std::make_shared<PrimitiveTypeEntry>(className, QVersionNumber{},
+ TypeEntryCPtr{});
+ pte->setReferencedTypeEntry(pTarget);
+ pte->setBuiltIn(true);
+ types->addType(pte);
+ return nullptr;
+ }
+
+ // If we haven't specified anything for the typedef, then we don't care
+ auto type = types->findComplexType(fullClassName);
+ if (!type)
+ return nullptr;
+
+ auto metaClass = std::make_shared<AbstractMetaClass>();
+ metaClass->setTypeDef(true);
+ metaClass->setTypeEntry(type);
+ metaClass->setBaseClassNames(QStringList(typeDef->type().toString()));
+
+ // Set the default include file name
+ if (!type->include().isValid())
+ setInclude(type, typeDef->fileName());
+
+ fillAddedFunctions(metaClass);
+
+ return metaClass;
+}
+
+// Add the typedef'ed classes
+void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs()
+{
+ const auto &entries = TypeDatabase::instance()->typedefEntries();
+ for (auto it = entries.begin(), end = entries.end(); it != end; ++it) {
+ const TypedefEntryPtr &te = it.value();
+ auto metaClass = std::make_shared<AbstractMetaClass>();
+ metaClass->setTypeDef(true);
+ metaClass->setTypeEntry(te->target());
+ metaClass->setBaseClassNames(QStringList(te->sourceType()));
+ fillAddedFunctions(metaClass);
+ addAbstractMetaClass(metaClass, nullptr);
+ // Ensure base classes are set up when traversing functions for the
+ // type to be resolved.
+ if (setupInheritance(metaClass)) {
+ // Create an entry to look up up types obtained from parsing
+ // functions in reverse. As opposed to container specializations,
+ // which are generated into every instantiating module (indicated
+ // by ContainerTypeEntry::targetLangPackage() being empty), the
+ // correct index array of the module needs to be found by reverse
+ // mapping the instantiations to the typedef entry.
+ // Synthesize a AbstractMetaType which would be found by an
+ // instantiation.
+ AbstractMetaType sourceType;
+ sourceType.setTypeEntry(metaClass->templateBaseClass()->typeEntry());
+ sourceType.setInstantiations(metaClass->templateBaseClassInstantiations());
+ sourceType.decideUsagePattern();
+ m_typeSystemTypeDefs.append({sourceType, metaClass});
+ }
+ }
+}
+
+AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom,
+ const ClassModelItem &classItem,
+ const AbstractMetaClassPtr &currentClass)
+{
+ QString className = stripTemplateArgs(classItem->name());
+ QString fullClassName = className;
+
+ // we have inner an class
+ if (currentClass) {
+ fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName())
+ + u"::"_s + fullClassName;
+ }
+
+ const auto type = TypeDatabase::instance()->findComplexType(fullClassName);
+ AbstractMetaBuilder::RejectReason reason = AbstractMetaBuilder::NoReason;
+
+ if (TypeDatabase::instance()->isClassRejected(fullClassName)) {
+ reason = AbstractMetaBuilder::GenerationDisabled;
+ } else if (!type) {
+ TypeEntryPtr te = TypeDatabase::instance()->findType(fullClassName);
+ if (te && !te->isComplex()) {
+ reason = AbstractMetaBuilder::RedefinedToNotClass;
+ // Set the default include file name
+ if (!te->include().isValid())
+ setInclude(te, classItem->fileName());
+ } else {
+ reason = AbstractMetaBuilder::NotInTypeSystem;
+ }
+ } else if (type->codeGeneration() == TypeEntry::GenerateNothing) {
+ reason = AbstractMetaBuilder::GenerationDisabled;
+ }
+ if (reason != AbstractMetaBuilder::NoReason) {
+ if (fullClassName.isEmpty()) {
+ QTextStream(&fullClassName) << "anonymous struct at " << classItem->fileName()
+ << ':' << classItem->startLine();
+ }
+ m_rejectedClasses.insert({reason, fullClassName, fullClassName, QString{}});
+ return nullptr;
+ }
+
+ auto metaClass = std::make_shared<AbstractMetaClass>();
+ metaClass->setSourceLocation(classItem->sourceLocation());
+ metaClass->setTypeEntry(type);
+ if ((type->typeFlags() & ComplexTypeEntry::ForceAbstract) != 0)
+ *metaClass += AbstractMetaClass::Abstract;
+
+ if (classItem->isFinal())
+ *metaClass += AbstractMetaClass::FinalCppClass;
+
+ if (classItem->classType() == CodeModel::Struct)
+ *metaClass += AbstractMetaClass::Struct;
+
+ QStringList baseClassNames;
+ const QList<_ClassModelItem::BaseClass> &baseClasses = classItem->baseClasses();
+ for (const _ClassModelItem::BaseClass &baseClass : baseClasses) {
+ if (baseClass.accessPolicy == Access::Public)
+ baseClassNames.append(baseClass.name);
+ }
+
+ metaClass->setBaseClassNames(baseClassNames);
+ if (type->stream())
+ metaClass->setStream(true);
+
+ if (ReportHandler::isDebug(ReportHandler::MediumDebug)) {
+ const QString message = type->isContainer()
+ ? u"container: '"_s + fullClassName + u'\''
+ : u"class: '"_s + metaClass->fullName() + u'\'';
+ qCInfo(lcShiboken, "%s", qPrintable(message));
+ }
+
+ TemplateParameterList template_parameters = classItem->templateParameters();
+ TypeEntryCList template_args;
+ template_args.clear();
+ auto argumentParent = typeSystemTypeEntry(metaClass->typeEntry());
+ for (qsizetype i = 0; i < template_parameters.size(); ++i) {
+ const TemplateParameterModelItem &param = template_parameters.at(i);
+ auto param_type =
+ std::make_shared<TemplateArgumentEntry>(param->name(), type->version(),
+ argumentParent);
+ param_type->setOrdinal(i);
+ template_args.append(TypeEntryCPtr(param_type));
+ }
+ metaClass->setTemplateArguments(template_args);
+
+ parseQ_Properties(metaClass, classItem->propertyDeclarations());
+
+ traverseEnums(classItem, metaClass, classItem->enumsDeclarations());
+
+ // Inner classes
+ {
+ const ClassList &innerClasses = classItem->classes();
+ for (const ClassModelItem &ci : innerClasses) {
+ const auto cl = traverseClass(dom, ci, metaClass);
+ if (cl) {
+ cl->setEnclosingClass(metaClass);
+ metaClass->addInnerClass(cl);
+ addAbstractMetaClass(cl, ci.get());
+ }
+ }
+
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ const TypeDefList typeDefs = classItem->typeDefs();
+ for (const TypeDefModelItem &typeDef : typeDefs) {
+ const auto cls = traverseTypeDef(dom, typeDef, metaClass);
+ if (cls) {
+ cls->setEnclosingClass(metaClass);
+ addAbstractMetaClass(cls, typeDef.get());
+ }
+ }
+
+ // Set the default include file name
+ if (!type->include().isValid())
+ setInclude(type, classItem->fileName());
+
+ return metaClass;
+}
+
+void AbstractMetaBuilderPrivate::traverseScopeMembers(const ScopeModelItem &item,
+ const AbstractMetaClassPtr &metaClass)
+{
+ // Classes/Namespace members
+ traverseFields(item, metaClass);
+ traverseFunctions(item, metaClass);
+
+ // Inner classes
+ const ClassList &innerClasses = item->classes();
+ for (const ClassModelItem &ci : innerClasses)
+ traverseClassMembers(ci);
+}
+
+void AbstractMetaBuilderPrivate::traverseClassMembers(const ClassModelItem &item)
+{
+ const auto metaClass = m_itemToClass.value(item.get());
+ if (metaClass) // Class members
+ traverseScopeMembers(item, metaClass);
+}
+
+void AbstractMetaBuilderPrivate::traverseUsingMembers(const AbstractMetaClassPtr &metaClass) const
+{
+ const _CodeModelItem *item = m_classToItem.value(metaClass);
+ if (item == nullptr || item->kind() != _CodeModelItem::Kind_Class)
+ return;
+ const auto *classItem = static_cast<const _ClassModelItem *>(item);
+ for (const auto &um : classItem->usingMembers()) {
+ QString className = um.className;
+ auto pos = className.indexOf(u'<'); // strip "QList<value>"
+ if (pos != -1)
+ className.truncate(pos);
+ if (auto baseClass = findBaseClass(metaClass, className)) {
+ QString name = um.memberName;
+ const auto lastQualPos = name.lastIndexOf(u"::"_s);
+ if (lastQualPos != -1)
+ name.remove(0, lastQualPos + 2);
+ metaClass->addUsingMember({name, baseClass, um.access});
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUsingMemberClassNotFound(metaClass, um.className,
+ um.memberName)));
+ }
+ }
+}
+
+void AbstractMetaBuilderPrivate::traverseNamespaceMembers(const NamespaceModelItem &item)
+{
+ const auto metaClass = m_itemToClass.value(item.get());
+ if (!metaClass)
+ return;
+
+ // Namespace members
+ traverseScopeMembers(item, metaClass);
+
+ // Inner namespaces
+ for (const NamespaceModelItem &ni : item->namespaces())
+ traverseNamespaceMembers(ni);
+
+}
+
+static inline QString fieldSignatureWithType(const VariableModelItem &field)
+{
+ return field->name() + " -> "_L1 + field->type().toString();
+}
+
+static inline QString qualifiedFieldSignatureWithType(const QString &className,
+ const VariableModelItem &field)
+{
+ return className + u"::"_s + fieldSignatureWithType(field);
+}
+
+std::optional<AbstractMetaField>
+ AbstractMetaBuilderPrivate::traverseField(const VariableModelItem &field,
+ const AbstractMetaClassCPtr &cls)
+{
+ QString fieldName = field->name();
+ QString className = cls->typeEntry()->qualifiedCppName();
+
+ // Ignore friend decl.
+ if (field->isFriend())
+ return {};
+
+ if (field->accessPolicy() == Access::Private)
+ return {};
+
+ QString rejectReason;
+ if (TypeDatabase::instance()->isFieldRejected(className, fieldName, &rejectReason)) {
+ const QString signature = qualifiedFieldSignatureWithType(className, field);
+ m_rejectedFields.insert({AbstractMetaBuilder::GenerationDisabled,
+ signature, signature, rejectReason});
+ return {};
+ }
+
+
+ AbstractMetaField metaField;
+ metaField.setName(fieldName);
+ metaField.setEnclosingClass(cls);
+
+ TypeInfo fieldType = field->type();
+ auto metaType = translateType(fieldType, cls);
+
+ if (!metaType.has_value()) {
+ const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(u"::"_s);
+ if (cls->typeEntry()->generateCode()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgSkippingField(field, cls->name(), type)));
+ }
+ return {};
+ }
+
+ metaField.setType(metaType.value());
+
+ metaField.setStatic(field->isStatic());
+ metaField.setAccess(field->accessPolicy());
+
+ return metaField;
+}
+
+static bool applyFieldModifications(AbstractMetaField *f)
+{
+ const auto &modifications = f->modifications();
+ for (const auto &mod : modifications) {
+ if (mod.isRemoved())
+ return false;
+ if (mod.isRenameModifier()) {
+ f->setOriginalName(f->name());
+ f->setName(mod.renamedToName());
+ } else if (!mod.isReadable()) {
+ f->setGetterEnabled(false);
+ } else if (!mod.isWritable()) {
+ f->setSetterEnabled(false);
+ }
+ }
+ return true;
+}
+
+void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item,
+ const AbstractMetaClassPtr &metaClass)
+{
+ const VariableList &variables = scope_item->variables();
+ for (const VariableModelItem &field : variables) {
+ auto metaFieldO = traverseField(field, metaClass);
+ if (metaFieldO.has_value()) {
+ AbstractMetaField metaField = metaFieldO.value();
+ if (applyFieldModifications(&metaField))
+ metaClass->addField(metaField);
+ }
+ }
+}
+
+void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction)
+{
+ if (!metaFunction->isConversionOperator())
+ return;
+
+ TypeDatabase *types = TypeDatabase::instance();
+ static const QRegularExpression operatorRegExp("^operator "_L1);
+ Q_ASSERT(operatorRegExp.isValid());
+ QString castTo = metaFunction->name().remove(operatorRegExp).trimmed();
+
+ if (castTo.endsWith(u'&'))
+ castTo.chop(1);
+ if (castTo.startsWith(u"const "))
+ castTo.remove(0, 6);
+
+ TypeEntryPtr retType = types->findType(castTo);
+ if (!retType)
+ return;
+
+ AbstractMetaType metaType(retType);
+ metaType.decideUsagePattern();
+ metaFunction->setType(metaType);
+}
+
+AbstractMetaFunctionRawPtrList
+ AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem,
+ AbstractMetaClass::Attributes *constructorAttributes,
+ const AbstractMetaClassPtr &currentClass)
+{
+ *constructorAttributes = {};
+ AbstractMetaFunctionRawPtrList result;
+ const FunctionList &scopeFunctionList = scopeItem->functions();
+ result.reserve(scopeFunctionList.size());
+ const bool isNamespace = currentClass->isNamespace();
+ for (const FunctionModelItem &function : scopeFunctionList) {
+ if (isNamespace && function->isOperator()) {
+ traverseOperatorFunction(function, currentClass);
+ } else if (function->isSpaceshipOperator() && !function->isDeleted()) {
+ if (currentClass)
+ AbstractMetaClass::addSynthesizedComparisonOperators(currentClass);
+ } else if (auto *metaFunction = traverseFunction(function, currentClass)) {
+ result.append(metaFunction);
+ } else if (!function->isDeleted() && function->functionType() == CodeModel::Constructor) {
+ auto arguments = function->arguments();
+ *constructorAttributes |= AbstractMetaClass::HasRejectedConstructor;
+ if (arguments.isEmpty() || arguments.constFirst()->defaultValue())
+ *constructorAttributes |= AbstractMetaClass::HasRejectedDefaultConstructor;
+ }
+ }
+ return result;
+}
+
+void AbstractMetaBuilderPrivate::traverseFunctions(const ScopeModelItem& scopeItem,
+ const AbstractMetaClassPtr &metaClass)
+{
+ AbstractMetaClass::Attributes constructorAttributes;
+ const AbstractMetaFunctionRawPtrList functions =
+ classFunctionList(scopeItem, &constructorAttributes, metaClass);
+ metaClass->setAttributes(metaClass->attributes() | constructorAttributes);
+
+ for (AbstractMetaFunction *metaFunction : functions) {
+ if (metaClass->isNamespace())
+ metaFunction->setCppAttribute(FunctionAttribute::Static);
+
+ const auto propertyFunction = metaClass->searchPropertyFunction(metaFunction->name());
+ if (propertyFunction.index >= 0) {
+ QPropertySpec prop = metaClass->propertySpecs().at(propertyFunction.index);
+ switch (propertyFunction.function) {
+ case AbstractMetaClass::PropertyFunction::Read:
+ // Property reader must be in the form "<type> name()"
+ if (!metaFunction->isSignal()
+ && prop.typeEntry() == metaFunction->type().typeEntry()
+ && metaFunction->arguments().isEmpty()) {
+ *metaFunction += AbstractMetaFunction::PropertyReader;
+ metaFunction->setPropertySpecIndex(propertyFunction.index);
+ }
+ break;
+ case AbstractMetaClass::PropertyFunction::Write:
+ // Property setter must be in the form "void name(<type>)"
+ // Make sure the function was created with all arguments; some
+ // argument can be missing during the parsing because of errors
+ // in the typesystem.
+ if (metaFunction->isVoid() && metaFunction->arguments().size() == 1
+ && (prop.typeEntry() == metaFunction->arguments().at(0).type().typeEntry())) {
+ *metaFunction += AbstractMetaFunction::PropertyWriter;
+ metaFunction->setPropertySpecIndex(propertyFunction.index);
+ }
+ break;
+ case AbstractMetaClass::PropertyFunction::Reset:
+ // Property resetter must be in the form "void name()"
+ if (metaFunction->isVoid() && metaFunction->arguments().isEmpty()) {
+ *metaFunction += AbstractMetaFunction::PropertyResetter;
+ metaFunction->setPropertySpecIndex(propertyFunction.index);
+ }
+ break;
+ case AbstractMetaClass::PropertyFunction::Notify:
+ if (metaFunction->isSignal()) {
+ *metaFunction += AbstractMetaFunction::PropertyNotify;
+ metaFunction->setPropertySpecIndex(propertyFunction.index);
+ }
+ }
+ }
+
+ if (metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction
+ && metaFunction->isPrivate()) {
+ metaClass->setHasPrivateConstructor(true);
+ }
+ if (metaFunction->isConstructor() && !metaFunction->isPrivate()) // Including Copy CT
+ metaClass->setHasNonPrivateConstructor(true);
+
+ if (!metaFunction->isDestructor()
+ && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) {
+
+ if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction))
+ qCWarning(lcShiboken, "%s", qPrintable(msgSignalOverloaded(metaClass, metaFunction)));
+
+ if (metaFunction->isConversionOperator())
+ fixReturnTypeOfConversionOperator(metaFunction);
+
+ AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(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);
+}
+
+void AbstractMetaBuilderPrivate::fillAddedFunctions(const AbstractMetaClassPtr &metaClass)
+{
+ // Add the functions added by the typesystem
+ QString errorMessage;
+ const AddedFunctionList &addedFunctions = metaClass->typeEntry()->addedFunctions();
+ for (const AddedFunctionPtr &addedFunc : addedFunctions) {
+ if (!traverseAddedMemberFunction(addedFunc, metaClass, &errorMessage))
+ throw Exception(qPrintable(errorMessage));
+ }
+}
+
+QString AbstractMetaBuilder::getSnakeCaseName(const QString &name)
+{
+ const auto size = name.size();
+ if (size < 3)
+ return name;
+ QString result;
+ result.reserve(size + 4);
+ for (qsizetype i = 0; i < size; ++i) {
+ const QChar c = name.at(i);
+ if (c.isUpper()) {
+ if (i > 0) {
+ if (name.at(i - 1).isUpper())
+ return name; // Give up at consecutive upper chars
+ result.append(u'_');
+ }
+ result.append(c.toLower());
+ } else {
+ result.append(c);
+ }
+ }
+ return result;
+}
+
+// Names under which an item will be registered to Python depending on snakeCase
+QStringList AbstractMetaBuilder::definitionNames(const QString &name,
+ TypeSystem::SnakeCase snakeCase)
+{
+ QStringList result;
+ switch (snakeCase) {
+ case TypeSystem::SnakeCase::Unspecified:
+ case TypeSystem::SnakeCase::Disabled:
+ result.append(name);
+ break;
+ case TypeSystem::SnakeCase::Enabled:
+ result.append(AbstractMetaBuilder::getSnakeCaseName(name));
+ break;
+ case TypeSystem::SnakeCase::Both:
+ result.append(AbstractMetaBuilder::getSnakeCaseName(name));
+ if (name != result.constFirst())
+ result.append(name);
+ break;
+ }
+ return result;
+}
+
+void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction *func)
+{
+ AbstractMetaFunction& funcRef = *func;
+ for (const FunctionModification &mod : func->modifications(func->implementingClass())) {
+ if (mod.isRenameModifier()) {
+ func->setOriginalName(func->name());
+ func->setName(mod.renamedToName());
+ } else if (mod.isAccessModifier()) {
+ if (mod.isPublic())
+ funcRef.modifyAccess(Access::Public);
+ else if (mod.isProtected())
+ funcRef.modifyAccess(Access::Protected);
+ else if (mod.isPrivate())
+ funcRef.modifyAccess(Access::Private);
+ }
+ }
+}
+
+bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &metaClass)
+{
+ if (metaClass->inheritanceDone())
+ return true;
+
+ metaClass->setInheritanceDone(true);
+
+ QStringList baseClasses = metaClass->baseClassNames();
+
+ // we only support our own containers and ONLY if there is only one baseclass
+ if (baseClasses.size() == 1 && baseClasses.constFirst().contains(u'<')) {
+ TypeInfo info;
+ ComplexTypeEntryPtr baseContainerType;
+ const auto templ = findTemplateClass(baseClasses.constFirst(), metaClass,
+ &info, &baseContainerType);
+ if (templ) {
+ setupInheritance(templ);
+ if (!inheritTemplate(metaClass, templ, info))
+ return false;
+ metaClass->typeEntry()->setBaseContainerType(templ->typeEntry());
+ return true;
+ }
+
+ if (baseContainerType) {
+ // Container types are not necessarily wrapped as 'real' classes,
+ // but there may still be classes derived from them. In such case,
+ // we still need to set the base container type in order to
+ // generate correct code for type conversion checking.
+ //
+ // Additionally, we consider this case as successfully setting up
+ // inheritance.
+ metaClass->typeEntry()->setBaseContainerType(baseContainerType);
+ return true;
+ }
+
+ qCWarning(lcShiboken, "template baseclass '%s' of '%s' is not known",
+ qPrintable(baseClasses.constFirst()),
+ qPrintable(metaClass->name()));
+ return false;
+ }
+
+ auto *types = TypeDatabase::instance();
+
+ for (const auto &baseClassName : baseClasses) {
+ if (!types->isClassRejected(baseClassName)) {
+ auto typeEntry = types->findType(baseClassName);
+ if (typeEntry == nullptr || !typeEntry->isComplex()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgBaseNotInTypeSystem(metaClass, baseClassName)));
+ return false;
+ }
+ auto baseClass = AbstractMetaClass::findClass(m_metaClasses, typeEntry);
+ if (!baseClass) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnknownBase(metaClass, baseClassName)));
+ return false;
+ }
+ metaClass->addBaseClass(baseClass);
+
+ setupInheritance(baseClass);
+ }
+ }
+
+ // Super class set by attribute "default-superclass".
+ const QString defaultSuperclassName = metaClass->typeEntry()->defaultSuperclass();
+ if (!defaultSuperclassName.isEmpty()) {
+ auto defaultSuper = AbstractMetaClass::findClass(m_metaClasses, defaultSuperclassName);
+ if (defaultSuper != nullptr) {
+ metaClass->setDefaultSuperclass(defaultSuper);
+ } else {
+ QString message;
+ QTextStream(&message) << "Class \"" << defaultSuperclassName
+ << R"(" specified as "default-superclass" of ")" << metaClass->name()
+ << "\" could not be found in the code model.";
+ qCWarning(lcShiboken, "%s", qPrintable(message));
+ }
+ }
+
+ return true;
+}
+
+void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem,
+ const AbstractMetaClassPtr &metaClass,
+ const QStringList &enumsDeclarations)
+{
+ const EnumList &enums = scopeItem->enums();
+ const QSet<QString> enumsDeclarationSet(enumsDeclarations.cbegin(), enumsDeclarations.cend());
+ for (const EnumModelItem &enumItem : enums) {
+ auto metaEnum = traverseEnum(enumItem, metaClass, enumsDeclarationSet);
+ if (metaEnum.has_value()) {
+ metaClass->addEnum(metaEnum.value());
+ }
+ }
+}
+
+static void applyDefaultExpressionModifications(const FunctionModificationList &functionMods,
+ int i, AbstractMetaArgument *metaArg)
+{
+ // use replace/remove-default-expression for set default value
+ for (const auto &modification : functionMods) {
+ for (const auto &argumentModification : modification.argument_mods()) {
+ if (argumentModification.index() == i + 1) {
+ if (argumentModification.removedDefaultExpression()) {
+ metaArg->setDefaultValueExpression(QString());
+ break;
+ }
+ if (!argumentModification.replacedDefaultExpression().isEmpty()) {
+ metaArg->setDefaultValueExpression(argumentModification.replacedDefaultExpression());
+ break;
+ }
+ }
+ }
+ }
+}
+
+static AbstractMetaFunction::FunctionType functionTypeFromName(const QString &);
+
+bool AbstractMetaBuilderPrivate::traverseAddedGlobalFunction(const AddedFunctionPtr &addedFunc,
+ QString *errorMessage)
+{
+ AbstractMetaFunction *metaFunction =
+ traverseAddedFunctionHelper(addedFunc, nullptr, errorMessage);
+ if (metaFunction == nullptr)
+ return false;
+ m_globalFunctions << AbstractMetaFunctionCPtr(metaFunction);
+ return true;
+}
+
+AbstractMetaFunction *
+ AbstractMetaBuilderPrivate::traverseAddedFunctionHelper(const AddedFunctionPtr &addedFunc,
+ const AbstractMetaClassPtr &metaClass /* = {} */,
+ QString *errorMessage)
+{
+ auto returnType = translateType(addedFunc->returnType(), metaClass, {}, errorMessage);
+ if (!returnType.has_value()) {
+ *errorMessage =
+ msgAddedFunctionInvalidReturnType(addedFunc->name(),
+ addedFunc->returnType().qualifiedName(),
+ *errorMessage, metaClass);
+ return nullptr;
+ }
+
+ auto *metaFunction = new AbstractMetaFunction(addedFunc);
+ metaFunction->setType(returnType.value());
+ metaFunction->setFunctionType(functionTypeFromName(addedFunc->name()));
+
+ const auto &args = addedFunc->arguments();
+
+ qsizetype argCount = args.size();
+ // Check "foo(void)"
+ if (argCount == 1 && args.constFirst().typeInfo.isVoid())
+ argCount = 0;
+ for (qsizetype i = 0; i < argCount; ++i) {
+ const AddedFunction::Argument &arg = args.at(i);
+ auto type = translateType(arg.typeInfo, metaClass, {}, errorMessage);
+ if (Q_UNLIKELY(!type.has_value())) {
+ *errorMessage =
+ msgAddedFunctionInvalidArgType(addedFunc->name(),
+ arg.typeInfo.qualifiedName(), i + 1,
+ *errorMessage, metaClass);
+ delete metaFunction;
+ return nullptr;
+ }
+ type->decideUsagePattern();
+
+ AbstractMetaArgument metaArg;
+ if (!args.at(i).name.isEmpty())
+ metaArg.setName(args.at(i).name);
+ metaArg.setType(type.value());
+ metaArg.setArgumentIndex(i);
+ metaArg.setDefaultValueExpression(arg.defaultValue);
+ metaArg.setOriginalDefaultValueExpression(arg.defaultValue);
+ metaFunction->addArgument(metaArg);
+ }
+
+ AbstractMetaArgumentList &metaArguments = metaFunction->arguments();
+
+ if (metaFunction->isOperatorOverload() && !metaFunction->isCallOperator()) {
+ if (metaArguments.size() > 2) {
+ qCWarning(lcShiboken) << "An operator overload need to have 0, 1 or 2 arguments if it's reverse.";
+ } else if (metaArguments.size() == 2) {
+ // Check if it's a reverse operator
+ if (metaArguments[1].type().typeEntry() == metaClass->typeEntry()) {
+ metaFunction->setReverseOperator(true);
+ // we need to call these two function to cache the old signature (with two args)
+ // we do this buggy behaviour to comply with the original apiextractor buggy behaviour.
+ metaFunction->signature();
+ metaFunction->minimalSignature();
+ metaArguments.removeLast();
+ metaFunction->setArguments(metaArguments);
+ } else {
+ qCWarning(lcShiboken) << "Operator overload can have two arguments only if it's a reverse operator!";
+ }
+ }
+ }
+
+
+ // Find the correct default values
+ const FunctionModificationList functionMods = metaFunction->modifications(metaClass);
+ applyCachedFunctionModifications(metaFunction, functionMods);
+ for (qsizetype i = 0; i < metaArguments.size(); ++i) {
+ AbstractMetaArgument &metaArg = metaArguments[i];
+
+ // use replace-default-expression for set default value
+ applyDefaultExpressionModifications(functionMods, i, &metaArg);
+ metaArg.setOriginalDefaultValueExpression(metaArg.defaultValueExpression()); // appear unmodified
+ }
+
+ if (!metaArguments.isEmpty())
+ fixArgumentNames(metaFunction, metaFunction->modifications(metaClass));
+
+ return metaFunction;
+}
+
+bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunctionPtr &addedFunc,
+ const AbstractMetaClassPtr &metaClass,
+ QString *errorMessage)
+{
+ AbstractMetaFunction *metaFunction =
+ traverseAddedFunctionHelper(addedFunc, metaClass, errorMessage);
+ if (metaFunction == nullptr)
+ return false;
+
+ const AbstractMetaArgumentList fargs = metaFunction->arguments();
+ if (metaClass->isNamespace())
+ metaFunction->setCppAttribute(FunctionAttribute::Static);
+ if (metaFunction->name() == metaClass->name()) {
+ metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ if (fargs.size() == 1) {
+ const auto te = fargs.constFirst().type().typeEntry();
+ if (te->isCustom())
+ metaFunction->setExplicit(true);
+ if (te->name() == metaFunction->name())
+ metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction);
+ }
+ }
+
+ metaFunction->setDeclaringClass(metaClass);
+ metaFunction->setImplementingClass(metaClass);
+ AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(metaFunction));
+ metaClass->setHasNonPrivateConstructor(true);
+ return true;
+}
+
+void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func, const FunctionModificationList &mods)
+{
+ AbstractMetaArgumentList &arguments = func->arguments();
+
+ for (const FunctionModification &mod : mods) {
+ for (const ArgumentModification &argMod : mod.argument_mods()) {
+ if (!argMod.renamedToName().isEmpty())
+ arguments[argMod.index() - 1].setName(argMod.renamedToName(), false);
+ }
+ }
+
+ for (qsizetype i = 0, size = arguments.size(); i < size; ++i) {
+ if (arguments.at(i).name().isEmpty())
+ arguments[i].setName(u"arg__"_s + QString::number(i + 1), false);
+ }
+}
+
+static QString functionSignature(const FunctionModelItem &functionItem)
+{
+ QStringList args;
+ const ArgumentList &arguments = functionItem->arguments();
+ for (const ArgumentModelItem &arg : arguments)
+ args << arg->type().toString();
+ return functionItem->name() + u'(' + args.join(u',') + u')';
+}
+
+static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem &functionItem,
+ const QString &className = QString())
+{
+ QString result = functionItem->type().toString() + u' ';
+ if (!className.isEmpty())
+ result += className + u"::"_s;
+ result += functionSignature(functionItem);
+ return result;
+}
+static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeModel::FunctionType ft)
+{
+ AbstractMetaFunction::FunctionType result = AbstractMetaFunction::NormalFunction;
+ switch (ft) {
+ case CodeModel::Constructor:
+ result = AbstractMetaFunction::ConstructorFunction;
+ break;
+ case CodeModel::CopyConstructor:
+ result = AbstractMetaFunction::CopyConstructorFunction;
+ break;
+ case CodeModel::MoveConstructor:
+ result = AbstractMetaFunction::MoveConstructorFunction;
+ break;
+ case CodeModel::Destructor:
+ result = AbstractMetaFunction::DestructorFunction;
+ break;
+ case CodeModel::AssignmentOperator:
+ result = AbstractMetaFunction::AssignmentOperatorFunction;
+ break;
+ case CodeModel::CallOperator:
+ result = AbstractMetaFunction::CallOperator;
+ break;
+ case CodeModel::ConversionOperator:
+ result = AbstractMetaFunction::ConversionOperator;
+ break;
+ case CodeModel::DereferenceOperator:
+ result = AbstractMetaFunction::DereferenceOperator;
+ break;
+ case CodeModel::ReferenceOperator:
+ result = AbstractMetaFunction::ReferenceOperator;
+ break;
+ case CodeModel::ArrowOperator:
+ result = AbstractMetaFunction::ArrowOperator;
+ break;
+ case CodeModel::ArithmeticOperator:
+ result = AbstractMetaFunction::ArithmeticOperator;
+ break;
+ case CodeModel::IncrementOperator:
+ result = AbstractMetaFunction::IncrementOperator;
+ break;
+ case CodeModel::DecrementOperator:
+ result = AbstractMetaFunction::DecrementOperator;
+ break;
+ case CodeModel::BitwiseOperator:
+ result = AbstractMetaFunction::BitwiseOperator;
+ break;
+ case CodeModel::LogicalOperator:
+ result = AbstractMetaFunction::LogicalOperator;
+ break;
+ case CodeModel::ShiftOperator:
+ result = AbstractMetaFunction::ShiftOperator;
+ break;
+ case CodeModel::SubscriptOperator:
+ result = AbstractMetaFunction::SubscriptOperator;
+ break;
+ case CodeModel::ComparisonOperator:
+ result = AbstractMetaFunction::ComparisonOperator;
+ break;
+ case CodeModel::Normal:
+ break;
+ case CodeModel::Signal:
+ result = AbstractMetaFunction::SignalFunction;
+ break;
+ case CodeModel::Slot:
+ result = AbstractMetaFunction::SlotFunction;
+ break;
+ }
+ return result;
+}
+
+static AbstractMetaFunction::FunctionType functionTypeFromName(const QString &name)
+{
+ if (name == u"__getattro__")
+ return AbstractMetaFunction::GetAttroFunction;
+ if (name == u"__setattro__")
+ return AbstractMetaFunction::SetAttroFunction;
+ const auto typeOpt = _FunctionModelItem::functionTypeFromName(name);
+ if (typeOpt.has_value())
+ return functionTypeFromCodeModel(typeOpt.value());
+ return AbstractMetaFunction::NormalFunction;
+}
+
+// Apply the <array> modifications of the arguments
+static bool applyArrayArgumentModifications(const FunctionModificationList &functionMods,
+ AbstractMetaFunction *func,
+ QString *errorMessage)
+{
+ for (const FunctionModification &mod : functionMods) {
+ for (const ArgumentModification &argMod : mod.argument_mods()) {
+ if (argMod.isArray()) {
+ const int i = argMod.index() - 1;
+ if (i < 0 || i >= func->arguments().size()) {
+ *errorMessage = msgCannotSetArrayUsage(func->minimalSignature(), i,
+ u"Index out of range."_s);
+ return false;
+ }
+ auto t = func->arguments().at(i).type();
+ if (!t.applyArrayModification(errorMessage)) {
+ *errorMessage = msgCannotSetArrayUsage(func->minimalSignature(), i, *errorMessage);
+ return false;
+ }
+ func->arguments()[i].setType(t);
+ }
+ }
+ }
+ return true;
+}
+
+// Create the meta type for a view (std::string_view -> std::string)
+static AbstractMetaType createViewOnType(const AbstractMetaType &metaType,
+ const TypeEntryCPtr &viewOnTypeEntry)
+{
+ auto result = metaType;
+ result.setTypeEntry(viewOnTypeEntry);
+ if (!metaType.isContainer() || !viewOnTypeEntry->isContainer())
+ return result;
+ // For containers, when sth with several template parameters
+ // (std::span<T, int N>) is mapped onto a std::vector<T>,
+ // remove the superfluous template parameters and strip 'const'.
+ const auto vcte = std::static_pointer_cast<const ContainerTypeEntry>(viewOnTypeEntry);
+ const auto &instantiations = metaType.instantiations();
+ AbstractMetaTypeList viewInstantiations;
+ const auto size = std::min(vcte->templateParameterCount(), instantiations.size());
+ for (qsizetype i = 0; i < size; ++i) {
+ auto ins = instantiations.at(i);
+ ins.setConstant(false);
+ viewInstantiations.append(ins);
+ }
+ result.setInstantiations(viewInstantiations);
+ return result;
+}
+
+void AbstractMetaBuilderPrivate::rejectFunction(const FunctionModelItem &functionItem,
+ const AbstractMetaClassPtr &currentClass,
+ AbstractMetaBuilder::RejectReason reason,
+ const QString &rejectReason)
+{
+ QString sortKey;
+ if (currentClass)
+ sortKey += currentClass->typeEntry()->qualifiedCppName() + u"::"_s;
+ sortKey += functionSignature(functionItem); // Sort without return type
+ const QString signatureWithType = functionItem->type().toString() + u' ' + sortKey;
+ m_rejectedFunctions.insert({reason, signatureWithType, sortKey, rejectReason});
+}
+
+AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem,
+ const AbstractMetaClassPtr &currentClass)
+{
+ const auto *tdb = TypeDatabase::instance();
+
+ if (!functionItem->templateParameters().isEmpty())
+ return nullptr;
+
+ if (functionItem->isDeleted()) {
+ switch (functionItem->functionType()) {
+ case CodeModel::Constructor:
+ if (functionItem->isDefaultConstructor())
+ currentClass->setHasDeletedDefaultConstructor(true);
+ break;
+ case CodeModel::CopyConstructor:
+ currentClass->setHasDeletedCopyConstructor(true);
+ break;
+ default:
+ break;
+ }
+ return nullptr;
+ }
+ const QString &functionName = functionItem->name();
+ const QString className = currentClass != nullptr ?
+ currentClass->typeEntry()->qualifiedCppName() : QString{};
+
+ if (m_apiExtractorFlags.testFlag(ApiExtractorFlag::UsePySideExtensions)) {
+ // Skip enum helpers generated by Q_ENUM
+ if ((currentClass == nullptr || currentClass->isNamespace())
+ && (functionName == u"qt_getEnumMetaObject" || functionName == u"qt_getEnumName")) {
+ return nullptr;
+ }
+
+ // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT
+ // and overridden metaObject(), QGADGET helpers
+ if (currentClass != nullptr) {
+ if (functionName == u"qt_check_for_QGADGET_macro"
+ || functionName.startsWith(u"qt_meta")) {
+ return nullptr;
+ }
+ if (functionName == u"metaObject" && className != u"QObject")
+ return nullptr;
+ }
+ } // PySide extensions
+
+ QString rejectReason;
+ if (tdb->isFunctionRejected(className, functionName, &rejectReason)) {
+ rejectFunction(functionItem, currentClass,
+ AbstractMetaBuilder::GenerationDisabled, rejectReason);
+ return nullptr;
+ }
+
+ const QString &signature = functionSignature(functionItem);
+ if (tdb->isFunctionRejected(className, signature, &rejectReason)) {
+ rejectFunction(functionItem, currentClass,
+ AbstractMetaBuilder::GenerationDisabled, rejectReason);
+ if (ReportHandler::isDebug(ReportHandler::MediumDebug)) {
+ qCInfo(lcShiboken, "%s::%s was rejected by the type database (%s).",
+ qPrintable(className), qPrintable(signature), qPrintable(rejectReason));
+ }
+ return nullptr;
+ }
+
+ if (functionItem->isFriend())
+ return nullptr;
+
+ 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;
+ }
+
+ AbstractMetaFunction::Flags flags;
+ auto *metaFunction = new AbstractMetaFunction(functionName);
+ metaFunction->setCppAttributes(cppAttributes);
+ const QByteArray cSignature = signature.toUtf8();
+ const QString unresolvedSignature =
+ QString::fromUtf8(QMetaObject::normalizedSignature(cSignature.constData()));
+ metaFunction->setUnresolvedSignature(unresolvedSignature);
+ if (functionItem->isHiddenFriend())
+ flags.setFlag(AbstractMetaFunction::Flag::HiddenFriend);
+ metaFunction->setSourceLocation(functionItem->sourceLocation());
+
+ // Additional check for assignment/move assignment down below
+ metaFunction->setFunctionType(functionTypeFromCodeModel(functionItem->functionType()));
+ metaFunction->setConstant(functionItem->isConstant());
+ metaFunction->setExceptionSpecification(functionItem->exceptionSpecification());
+
+ // Access rights
+ metaFunction->setAccess(functionItem->accessPolicy());
+
+ QString errorMessage;
+ switch (metaFunction->functionType()) {
+ case AbstractMetaFunction::DestructorFunction:
+ metaFunction->setType(AbstractMetaType::createVoid());
+ break;
+ case AbstractMetaFunction::ConstructorFunction:
+ metaFunction->setName(currentClass->name());
+ metaFunction->setType(AbstractMetaType::createVoid());
+ break;
+ default: {
+ TypeInfo returnType = functionItem->type();
+
+ if (tdb->isReturnTypeRejected(className, returnType.toString(), &rejectReason)) {
+ rejectFunction(functionItem, currentClass,
+ AbstractMetaBuilder::GenerationDisabled, rejectReason);
+ delete metaFunction;
+ return nullptr;
+ }
+
+ TranslateTypeFlags flags;
+ if (functionItem->scopeResolution())
+ flags.setFlag(AbstractMetaBuilder::NoClassScopeLookup);
+ auto type = translateType(returnType, currentClass, flags, &errorMessage);
+ if (!type.has_value()) {
+ const QString reason = msgUnmatchedReturnType(functionItem, errorMessage);
+ const QString signature = qualifiedFunctionSignatureWithType(functionItem, className);
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgSkippingFunction(functionItem, signature, reason)));
+ rejectFunction(functionItem, currentClass,
+ AbstractMetaBuilder::UnmatchedReturnType, reason);
+ delete metaFunction;
+ return nullptr;
+ }
+
+ metaFunction->setType(type.value());
+ }
+ break;
+ }
+
+ ArgumentList arguments = functionItem->arguments();
+ // Add private signals for documentation purposes
+ if (!arguments.isEmpty()
+ && m_apiExtractorFlags.testFlag(ApiExtractorFlag::UsePySideExtensions)
+ && functionItem->functionType() == CodeModel::Signal
+ && arguments.constLast()->type().qualifiedName().constLast() == u"QPrivateSignal") {
+ flags.setFlag(AbstractMetaFunction::Flag::PrivateSignal);
+ arguments.removeLast();
+ }
+
+ if (arguments.size() == 1) {
+ ArgumentModelItem arg = arguments.at(0);
+ TypeInfo type = arg->type();
+ if (type.qualifiedName().constFirst() == u"void" && type.indirections() == 0)
+ arguments.pop_front();
+ }
+
+ for (qsizetype i = 0; i < arguments.size(); ++i) {
+ const ArgumentModelItem &arg = arguments.at(i);
+
+ if (tdb->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) {
+ rejectFunction(functionItem, currentClass,
+ AbstractMetaBuilder::GenerationDisabled, rejectReason);
+ delete metaFunction;
+ return nullptr;
+ }
+
+ TranslateTypeFlags flags;
+ if (arg->scopeResolution())
+ flags.setFlag(AbstractMetaBuilder::NoClassScopeLookup);
+ auto metaTypeO = translateType(arg->type(), currentClass, flags, &errorMessage);
+ if (!metaTypeO.has_value()) {
+ // If an invalid argument has a default value, simply remove it
+ // unless the function is virtual (since the override in the
+ // wrapper can then not correctly be generated).
+ if (arg->defaultValue()
+ && !functionItem->attributes().testFlag(FunctionAttribute::Virtual)) {
+ if (!currentClass || currentClass->typeEntry()->generateCode()) {
+ const QString signature = qualifiedFunctionSignatureWithType(functionItem, className);
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgStrippingArgument(functionItem, i, signature,
+ arg, errorMessage)));
+ }
+ break;
+ }
+ const QString reason = msgUnmatchedParameterType(arg, i, errorMessage);
+ const QString signature = qualifiedFunctionSignatureWithType(functionItem, className);
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgSkippingFunction(functionItem, signature, reason)));
+ rejectFunction(functionItem, currentClass,
+ AbstractMetaBuilder::UnmatchedArgumentType, reason);
+ delete metaFunction;
+ return nullptr;
+ }
+
+ auto metaType = metaTypeO.value();
+ // Add view substitution for simple view types of function arguments
+ // std::string_view -> std::string for foo(std::string_view)
+ auto viewOnTypeEntry = metaType.typeEntry()->viewOn();
+ if (viewOnTypeEntry != nullptr && metaType.indirections() == 0
+ && metaType.arrayElementType() == nullptr
+ && (!metaType.hasInstantiations() || metaType.isContainer())) {
+ metaType.setViewOn(createViewOnType(metaType, viewOnTypeEntry));
+ }
+
+ AbstractMetaArgument metaArgument;
+ metaArgument.setType(metaType);
+ metaArgument.setName(arg->name());
+ metaArgument.setArgumentIndex(i);
+ metaFunction->addArgument(metaArgument);
+ }
+
+ AbstractMetaArgumentList &metaArguments = metaFunction->arguments();
+
+ const FunctionModificationList functionMods = currentClass
+ ? AbstractMetaFunction::findClassModifications(metaFunction, currentClass)
+ : AbstractMetaFunction::findGlobalModifications(metaFunction);
+
+ applyCachedFunctionModifications(metaFunction, functionMods);
+
+ // Find the correct default values
+ for (qsizetype i = 0, size = metaArguments.size(); i < size; ++i) {
+ const ArgumentModelItem &arg = arguments.at(i);
+ AbstractMetaArgument &metaArg = metaArguments[i];
+
+ const QString originalDefaultExpression =
+ fixDefaultValue(arg->defaultValueExpression(), metaArg.type(), currentClass);
+
+ metaArg.setOriginalDefaultValueExpression(originalDefaultExpression);
+ metaArg.setDefaultValueExpression(originalDefaultExpression);
+
+ applyDefaultExpressionModifications(functionMods, i, &metaArg);
+
+ //Check for missing argument name
+ if (!metaArg.defaultValueExpression().isEmpty()
+ && !metaArg.hasName()
+ && !metaFunction->isOperatorOverload()
+ && !metaFunction->isSignal()
+ && metaFunction->argumentName(i + 1, false, currentClass).isEmpty()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnnamedArgumentDefaultExpression(currentClass, i + 1,
+ className, metaFunction)));
+ }
+
+ }
+
+ if (!metaArguments.isEmpty()) {
+ fixArgumentNames(metaFunction, functionMods);
+ QString errorMessage;
+ if (!applyArrayArgumentModifications(functionMods, metaFunction, &errorMessage)) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgArrayModificationFailed(functionItem, className, errorMessage)));
+ }
+ }
+
+ // Determine class special functions
+ if (currentClass && metaFunction->arguments().size() == 1) {
+ const AbstractMetaType &argType = metaFunction->arguments().constFirst().type();
+ if (argType.typeEntry() == currentClass->typeEntry() && argType.indirections() == 0) {
+ if (metaFunction->name() == u"operator=") {
+ switch (argType.referenceType()) {
+ case NoReference:
+ metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction);
+ break;
+ case LValueReference:
+ if (argType.isConstant())
+ metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction);
+ break;
+ case RValueReference:
+ metaFunction->setFunctionType(AbstractMetaFunction::MoveAssignmentOperatorFunction);
+ break;
+ }
+ }
+ }
+ }
+ metaFunction->setFlags(flags);
+ return metaFunction;
+}
+
+static TypeEntryCPtr findTypeEntryUsingContext(const AbstractMetaClassCPtr &metaClass,
+ const QString& qualifiedName)
+{
+ TypeEntryCPtr type;
+ QStringList context = metaClass->qualifiedCppName().split(u"::"_s);
+ while (!type && !context.isEmpty()) {
+ type = TypeDatabase::instance()->findType(context.join(u"::"_s) + u"::"_s + qualifiedName);
+ context.removeLast();
+ }
+ return type;
+}
+
+// Helper for findTypeEntries/translateTypeStatic()
+TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qualifiedName,
+ const QString &name,
+ TranslateTypeFlags flags,
+ const AbstractMetaClassCPtr &currentClass,
+ AbstractMetaBuilderPrivate *d)
+{
+ // 5.1 - Try first using the current scope
+ if (currentClass != nullptr
+ && !flags.testFlag(AbstractMetaBuilder::NoClassScopeLookup)) {
+ if (auto type = findTypeEntryUsingContext(currentClass, qualifiedName))
+ return {type};
+
+ // 5.1.1 - Try using the class parents' scopes
+ if (d && !currentClass->baseClassNames().isEmpty()) {
+ const auto &baseClasses = d->getBaseClasses(currentClass);
+ for (const auto &cls : baseClasses) {
+ if (auto type = findTypeEntryUsingContext(cls, qualifiedName))
+ return {type};
+ }
+ }
+ }
+
+ // 5.2 - Try without scope
+ auto types = TypeDatabase::instance()->findCppTypes(qualifiedName);
+ if (!types.isEmpty())
+ return types;
+
+ // 6. No? Try looking it up as a flags type
+ if (auto type = TypeDatabase::instance()->findFlagsType(qualifiedName))
+ return {type};
+
+ // 7. No? Try looking it up as a container type
+ if (auto type = TypeDatabase::instance()->findContainerType(name))
+ return {type};
+
+ // 8. No? Check if the current class is a template and this type is one
+ // of the parameters.
+ if (currentClass) {
+ const auto &template_args = currentClass->templateArguments();
+ for (const auto &te : template_args) {
+ if (te->name() == qualifiedName)
+ return {te};
+ }
+ }
+ return {};
+}
+
+// Helper for translateTypeStatic() that calls findTypeEntriesHelper()
+// and does some error checking.
+TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualifiedName,
+ const QString &name,
+ TranslateTypeFlags flags,
+ const AbstractMetaClassCPtr &currentClass,
+ AbstractMetaBuilderPrivate *d,
+ QString *errorMessage)
+{
+ TypeEntryCList types = findTypeEntriesHelper(qualifiedName, name, flags,
+ currentClass, d);
+ if (types.isEmpty()) {
+ if (errorMessage != nullptr)
+ *errorMessage = msgCannotFindTypeEntry(qualifiedName);
+ return {};
+ }
+
+ // Resolve entries added by metabuilder (for example, "GLenum") to match
+ // the signatures for modifications.
+ for (qsizetype i = 0, size = types.size(); i < size; ++i) {
+ const auto &e = types.at(i);
+ if (e->isPrimitive()) {
+ const auto pte = std::static_pointer_cast<const PrimitiveTypeEntry>(e);
+ types[i] = basicReferencedNonBuiltinTypeEntry(pte);
+ }
+ }
+
+ if (types.size() == 1)
+ return types;
+
+ const auto typeEntryType = types.constFirst()->type();
+ const bool sameType = std::all_of(types.cbegin() + 1, types.cend(),
+ [typeEntryType](const TypeEntryCPtr &e) {
+ return e->type() == typeEntryType;
+ });
+
+ if (!sameType) {
+ if (errorMessage != nullptr)
+ *errorMessage = msgAmbiguousVaryingTypesFound(qualifiedName, types);
+ return {};
+ }
+ // Ambiguous primitive/smart pointer types are possible (when
+ // including type systems).
+ if (typeEntryType != TypeEntry::PrimitiveType
+ && typeEntryType != TypeEntry::SmartPointerType) {
+ if (errorMessage != nullptr)
+ *errorMessage = msgAmbiguousTypesFound(qualifiedName, types);
+ return {};
+ }
+ return types;
+}
+
+// Reverse lookup of AbstractMetaType representing a template specialization
+// found during traversing function arguments to its type system typedef'ed
+// class.
+AbstractMetaClassCPtr AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(const AbstractMetaType &t) const
+{
+ if (t.hasInstantiations()) {
+ auto pred = [t](const TypeClassEntry &e) { return e.type == t; };
+ auto it = std::find_if(m_typeSystemTypeDefs.cbegin(), m_typeSystemTypeDefs.cend(), pred);
+ if (it != m_typeSystemTypeDefs.cend())
+ return it->klass;
+ }
+ return nullptr;
+}
+
+// The below helpers and AbstractMetaBuilderPrivate::fixSmartPointers()
+// synthesize missing smart pointer functions and classes. For example for
+// std::shared_ptr, the full class declaration or base classes from
+// internal, compiler-dependent STL implementation headers might not be exposed
+// to the parser unless those headers are specified as <system-include>.
+
+static void synthesizeWarning(const AbstractMetaFunctionCPtr &f)
+{
+ qCWarning(lcShiboken, "Synthesizing \"%s\"...",
+ qPrintable(f->classQualifiedSignature()));
+}
+
+static AbstractMetaFunctionPtr
+ addMethod(const AbstractMetaClassPtr &s, const AbstractMetaType &returnType,
+ const QString &name, bool isConst = true)
+{
+ auto function = std::make_shared<AbstractMetaFunction>(name);
+ function->setType(returnType);
+ AbstractMetaClass::addFunction(s, function);
+ function->setConstant(isConst);
+ synthesizeWarning(function);
+ return function;
+}
+
+static AbstractMetaFunctionPtr
+ addMethod(const AbstractMetaClassPtr &s, const QString &returnTypeName,
+ const QString &name, bool isConst = true)
+{
+ auto typeEntry = TypeDatabase::instance()->findPrimitiveType(returnTypeName);
+ Q_ASSERT(typeEntry);
+ AbstractMetaType returnType(typeEntry);
+ returnType.decideUsagePattern();
+ return addMethod(s, returnType, name, isConst);
+}
+
+// Create the instantiation type of a smart pointer
+static AbstractMetaType instantiationType(const AbstractMetaClassCPtr &s,
+ const SmartPointerTypeEntryCPtr &ste)
+{
+ AbstractMetaType type(s->templateArguments().constFirst());
+ if (ste->smartPointerType() != TypeSystem::SmartPointerType::ValueHandle)
+ type.addIndirection();
+ type.decideUsagePattern();
+ return type;
+}
+
+// Create the pointee argument of a smart pointer constructor or reset()
+static AbstractMetaArgument pointeeArgument(const AbstractMetaClassCPtr &s,
+ const SmartPointerTypeEntryCPtr &ste)
+{
+ AbstractMetaArgument pointee;
+ pointee.setType(instantiationType(s, ste));
+ pointee.setName(u"pointee"_s);
+ return pointee;
+}
+
+// Add the smart pointer constructors. For MSVC, (when not specifying
+// <system-header>), clang only sees the default constructor.
+static void fixSmartPointerConstructors(const AbstractMetaClassPtr &s,
+ const SmartPointerTypeEntryCPtr &ste)
+{
+ const auto ctors = s->queryFunctions(FunctionQueryOption::Constructors);
+ bool seenDefaultConstructor = false;
+ bool seenParameter = false;
+ for (const auto &ctor : ctors) {
+ if (ctor->arguments().isEmpty())
+ seenDefaultConstructor = true;
+ else
+ seenParameter = true;
+ }
+
+ if (!seenParameter) {
+ auto constructor = std::make_shared<AbstractMetaFunction>(s->name());
+ constructor->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ constructor->addArgument(pointeeArgument(s, ste));
+ AbstractMetaClass::addFunction(s, constructor);
+ synthesizeWarning(constructor);
+ }
+
+ if (!seenDefaultConstructor) {
+ auto constructor = std::make_shared<AbstractMetaFunction>(s->name());
+ constructor->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ AbstractMetaClass::addFunction(s, constructor);
+ synthesizeWarning(constructor);
+ }
+}
+
+// Similarly, add the smart pointer reset() functions
+static void fixSmartPointerReset(const AbstractMetaClassPtr &s,
+ const SmartPointerTypeEntryCPtr &ste)
+{
+ const QString resetMethodName = ste->resetMethod();
+ const auto functions = s->findFunctions(resetMethodName);
+ bool seenParameterLess = false;
+ bool seenParameter = false;
+ for (const auto &function : functions) {
+ if (function->arguments().isEmpty())
+ seenParameterLess = true;
+ else
+ seenParameter = true;
+ }
+
+ if (!seenParameter) {
+ auto f = std::make_shared<AbstractMetaFunction>(resetMethodName);
+ f->addArgument(pointeeArgument(s, ste));
+ AbstractMetaClass::addFunction(s, f);
+ synthesizeWarning(f);
+ }
+
+ if (!seenParameterLess) {
+ auto f = std::make_shared<AbstractMetaFunction>(resetMethodName);
+ AbstractMetaClass::addFunction(s, f);
+ synthesizeWarning(f);
+ }
+}
+
+// Add the relevant missing smart pointer functions.
+static void fixSmartPointerClass(const AbstractMetaClassPtr &s,
+ const SmartPointerTypeEntryCPtr &ste)
+{
+ fixSmartPointerConstructors(s, ste);
+
+ if (!ste->resetMethod().isEmpty())
+ fixSmartPointerReset(s, ste);
+
+ const QString getterName = ste->getter();
+ if (!s->findFunction(getterName))
+ addMethod(s, instantiationType(s, ste), getterName);
+
+ const QString refCountName = ste->refCountMethodName();
+ if (!refCountName.isEmpty() && !s->findFunction(refCountName))
+ addMethod(s, u"int"_s, refCountName);
+
+ const QString valueCheckMethod = ste->valueCheckMethod();
+ if (!valueCheckMethod.isEmpty() && !s->findFunction(valueCheckMethod)) {
+ auto f = addMethod(s, u"bool"_s, valueCheckMethod);
+ if (valueCheckMethod == u"operator bool")
+ f->setFunctionType(AbstractMetaFunction::ConversionOperator);
+ }
+
+ const QString nullCheckMethod = ste->nullCheckMethod();
+ if (!nullCheckMethod.isEmpty() && !s->findFunction(nullCheckMethod))
+ addMethod(s, u"bool"_s, nullCheckMethod);
+}
+
+// Create a missing smart pointer class
+static AbstractMetaClassPtr createSmartPointerClass(const SmartPointerTypeEntryCPtr &ste,
+ const AbstractMetaClassList &allClasses)
+{
+ auto result = std::make_shared<AbstractMetaClass>();
+ result->setTypeEntry(std::const_pointer_cast<SmartPointerTypeEntry>(ste));
+ auto templateArg = std::make_shared<TemplateArgumentEntry>(u"T"_s, ste->version(),
+ typeSystemTypeEntry(ste));
+ result->setTemplateArguments({templateArg});
+ fixSmartPointerClass(result, ste);
+ auto enclosingTe = ste->parent();
+ if (!enclosingTe->isTypeSystem()) {
+ const auto enclosing = AbstractMetaClass::findClass(allClasses, enclosingTe);
+ if (!enclosing)
+ throw Exception(msgEnclosingClassNotFound(ste));
+ result->setEnclosingClass(enclosing);
+ auto inner = enclosing->innerClasses();
+ inner.append(std::const_pointer_cast<const AbstractMetaClass>(result));
+ enclosing->setInnerClasses(inner);
+ }
+ return result;
+}
+
+void AbstractMetaBuilderPrivate::fixSmartPointers()
+{
+ const auto smartPointerTypes = TypeDatabase::instance()->smartPointerTypes();
+ for (const auto &ste : smartPointerTypes) {
+ const auto smartPointerClass =
+ AbstractMetaClass::findClass(m_smartPointers, ste);
+ if (smartPointerClass) {
+ fixSmartPointerClass(std::const_pointer_cast<AbstractMetaClass>(smartPointerClass),
+ ste);
+ } else {
+ qCWarning(lcShiboken, "Synthesizing smart pointer \"%s\"...",
+ qPrintable(ste->qualifiedCppName()));
+ m_smartPointers.append(createSmartPointerClass(ste, m_metaClasses));
+ }
+ }
+}
+
+std::optional<AbstractMetaType>
+ AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei,
+ const AbstractMetaClassCPtr &currentClass,
+ TranslateTypeFlags flags,
+ QString *errorMessage)
+{
+ return translateTypeStatic(_typei, currentClass, this, flags, errorMessage);
+}
+
+static bool isNumber(const QString &s)
+{
+ return std::all_of(s.cbegin(), s.cend(),
+ [](QChar c) { return c.isDigit(); });
+}
+
+// A type entry relevant only for non type template "X<5>"
+static bool isNonTypeTemplateArgument(const TypeEntryCPtr &te)
+{
+ const auto type = te->type();
+ return type == TypeEntry::EnumValue || type == TypeEntry::ConstantValueType;
+}
+
+std::optional<AbstractMetaType>
+ AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei,
+ const AbstractMetaClassCPtr &currentClass,
+ AbstractMetaBuilderPrivate *d,
+ TranslateTypeFlags flags,
+ QString *errorMessageIn)
+{
+ if (_typei.isVoid())
+ return AbstractMetaType::createVoid();
+
+ // 1. Test the type info without resolving typedefs in case this is present in the
+ // type system
+ const bool resolveType = !flags.testFlag(AbstractMetaBuilder::DontResolveType);
+ if (resolveType) {
+ auto resolved =
+ translateTypeStatic(_typei, currentClass, d,
+ flags | AbstractMetaBuilder::DontResolveType,
+ errorMessageIn);
+ if (resolved.has_value())
+ return resolved;
+ }
+
+ TypeInfo typeInfo = _typei;
+ if (resolveType) {
+ // Go through all parts of the current scope (including global namespace)
+ // to resolve typedefs. The parser does not properly resolve typedefs in
+ // the global scope when they are referenced from inside a namespace.
+ // This is a work around to fix this bug since fixing it in resolveType
+ // seemed non-trivial
+ qsizetype i = d ? d->m_scopes.size() - 1 : -1;
+ while (i >= 0) {
+ typeInfo = TypeInfo::resolveType(_typei, d->m_scopes.at(i--));
+ if (typeInfo.qualifiedName().join(u"::"_s) != _typei.qualifiedName().join(u"::"_s))
+ break;
+ }
+
+ }
+
+ if (typeInfo.isFunctionPointer()) {
+ if (errorMessageIn)
+ *errorMessageIn = msgUnableToTranslateType(_typei, u"Unsupported function pointer."_s);
+ return {};
+ }
+
+ QString errorMessage;
+
+ // 2. Handle arrays.
+ // 2.1 Handle char arrays with unspecified size (aka "const char[]") as "const char*" with
+ // NativePointerPattern usage.
+ bool oneDimensionalArrayOfUnspecifiedSize =
+ typeInfo.arrayElements().size() == 1
+ && typeInfo.arrayElements().at(0).isEmpty();
+
+ bool isConstCharStarCase =
+ oneDimensionalArrayOfUnspecifiedSize
+ && typeInfo.qualifiedName().size() == 1
+ && typeInfo.qualifiedName().at(0) == "char"_L1
+ && typeInfo.indirections() == 0
+ && typeInfo.isConstant()
+ && typeInfo.referenceType() == NoReference
+ && typeInfo.arguments().isEmpty();
+
+ if (isConstCharStarCase)
+ typeInfo.setIndirections(typeInfo.indirections() + typeInfo.arrayElements().size());
+
+ // 2.2 Handle regular arrays.
+ if (!typeInfo.arrayElements().isEmpty() && !isConstCharStarCase) {
+ TypeInfo newInfo;
+ //newInfo.setArguments(typeInfo.arguments());
+ newInfo.setIndirectionsV(typeInfo.indirectionsV());
+ newInfo.setConstant(typeInfo.isConstant());
+ newInfo.setVolatile(typeInfo.isVolatile());
+ newInfo.setFunctionPointer(typeInfo.isFunctionPointer());
+ newInfo.setQualifiedName(typeInfo.qualifiedName());
+ newInfo.setReferenceType(typeInfo.referenceType());
+ newInfo.setVolatile(typeInfo.isVolatile());
+
+ auto elementType = translateTypeStatic(newInfo, currentClass, d, flags, &errorMessage);
+ if (!elementType.has_value()) {
+ if (errorMessageIn) {
+ errorMessage.prepend(u"Unable to translate array element: "_s);
+ *errorMessageIn = msgUnableToTranslateType(_typei, errorMessage);
+ }
+ return {};
+ }
+
+ for (auto i = typeInfo.arrayElements().size() - 1; i >= 0; --i) {
+ AbstractMetaType arrayType;
+ arrayType.setArrayElementType(elementType.value());
+ const QString &arrayElement = typeInfo.arrayElements().at(i);
+ if (!arrayElement.isEmpty()) {
+ bool _ok;
+ const qint64 elems = d
+ ? d->findOutValueFromString(arrayElement, _ok)
+ : arrayElement.toLongLong(&_ok, 0);
+ if (_ok)
+ arrayType.setArrayElementCount(int(elems));
+ }
+ auto elementTypeEntry = elementType->typeEntry();
+ auto at = std::make_shared<ArrayTypeEntry>(elementTypeEntry, elementTypeEntry->version(),
+ elementTypeEntry->parent());
+ arrayType.setTypeEntry(at);
+ arrayType.decideUsagePattern();
+
+ elementType = arrayType;
+ }
+
+ return elementType;
+ }
+
+ QStringList qualifierList = typeInfo.qualifiedName();
+ if (qualifierList.isEmpty()) {
+ errorMessage = msgUnableToTranslateType(_typei, u"horribly broken type"_s);
+ if (errorMessageIn)
+ *errorMessageIn = errorMessage;
+ else
+ qCWarning(lcShiboken,"%s", qPrintable(errorMessage));
+ return {};
+ }
+
+ QString qualifiedName = qualifierList.join(u"::"_s);
+ QString name = qualifierList.takeLast();
+
+ // 4. Special case QFlags (include instantiation in name)
+ if (qualifiedName == u"QFlags") {
+ qualifiedName = typeInfo.toString();
+ typeInfo.clearInstantiations();
+ }
+
+ TypeEntryCList types = findTypeEntries(qualifiedName, name, flags,
+ currentClass, d, errorMessageIn);
+ if (!flags.testFlag(AbstractMetaBuilder::TemplateArgument)) {
+ // Avoid clashes between QByteArray and enum value QMetaType::QByteArray
+ // unless we are looking for template arguments.
+ auto end = std::remove_if(types.begin(), types.end(),
+ isNonTypeTemplateArgument);
+ types.erase(end, types.end());
+ }
+
+ if (types.isEmpty()) {
+ if (errorMessageIn != nullptr)
+ *errorMessageIn = msgUnableToTranslateType(_typei, *errorMessageIn);
+ return {};
+ }
+
+ TypeEntryCPtr type = types.constFirst();
+ const TypeEntry::Type typeEntryType = type->type();
+
+ AbstractMetaType metaType;
+ metaType.setIndirectionsV(typeInfo.indirectionsV());
+ metaType.setReferenceType(typeInfo.referenceType());
+ metaType.setConstant(typeInfo.isConstant());
+ metaType.setVolatile(typeInfo.isVolatile());
+ metaType.setOriginalTypeDescription(_typei.toString());
+
+ const auto &templateArguments = typeInfo.instantiations();
+ for (qsizetype t = 0, size = templateArguments.size(); t < size; ++t) {
+ const TypeInfo &ti = templateArguments.at(t);
+ auto targType = translateTypeStatic(ti, currentClass, d,
+ flags | AbstractMetaBuilder::TemplateArgument,
+ &errorMessage);
+ // For non-type template parameters, create a dummy type entry on the fly
+ // as is done for classes.
+ if (!targType.has_value()) {
+ const QString value = ti.qualifiedName().join(u"::"_s);
+ if (isNumber(value)) {
+ auto module = typeSystemTypeEntry(type);
+ TypeDatabase::instance()->addConstantValueTypeEntry(value, module);
+ targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage);
+ }
+ }
+ if (!targType) {
+ if (errorMessageIn)
+ *errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage);
+ return {};
+ }
+
+ metaType.addInstantiation(targType.value());
+ }
+
+ if (typeEntryType == TypeEntry::SmartPointerType) {
+ // Find a matching instantiation
+ if (metaType.instantiations().size() != 1) {
+ if (errorMessageIn)
+ *errorMessageIn = msgInvalidSmartPointerType(_typei);
+ return {};
+ }
+ auto instantiationType = metaType.instantiations().constFirst().typeEntry();
+ if (instantiationType->type() == TypeEntry::TemplateArgumentType) {
+ // Member functions of the template itself, SharedPtr(const SharedPtr &)
+ type = instantiationType;
+ } else {
+ auto it = std::find_if(types.cbegin(), types.cend(),
+ [instantiationType](const TypeEntryCPtr &e) {
+ auto smartPtr = std::static_pointer_cast<const SmartPointerTypeEntry>(e);
+ return smartPtr->matchesInstantiation(instantiationType);
+ });
+ if (it == types.cend()) {
+ if (errorMessageIn)
+ *errorMessageIn = msgCannotFindSmartPointerInstantion(_typei);
+ return {};
+ }
+ type =*it;
+ }
+ }
+
+ metaType.setTypeEntry(type);
+
+ // The usage pattern *must* be decided *after* the possible template
+ // instantiations have been determined, or else the absence of
+ // such instantiations will break the caching scheme of
+ // AbstractMetaType::cppSignature().
+ metaType.decideUsagePattern();
+
+ if (d) {
+ // Reverse lookup of type system typedefs. Replace by class.
+ if (auto klass = d->resolveTypeSystemTypeDef(metaType)) {
+ metaType = AbstractMetaType{};
+ metaType.setTypeEntry(klass->typeEntry());
+ metaType.decideUsagePattern();
+ }
+ }
+
+ return metaType;
+}
+
+std::optional<AbstractMetaType>
+ AbstractMetaBuilder::translateType(const TypeInfo &_typei,
+ const AbstractMetaClassPtr &currentClass,
+ TranslateTypeFlags flags,
+ QString *errorMessage)
+{
+ return AbstractMetaBuilderPrivate::translateTypeStatic(_typei, currentClass,
+ nullptr, flags,
+ errorMessage);
+}
+
+std::optional<AbstractMetaType>
+ AbstractMetaBuilder::translateType(const QString &t,
+ const AbstractMetaClassPtr &currentClass,
+ TranslateTypeFlags flags,
+ QString *errorMessageIn)
+{
+ QString errorMessage;
+ TypeInfo typeInfo = TypeParser::parse(t, &errorMessage);
+ if (typeInfo.qualifiedName().isEmpty()) {
+ errorMessage = msgUnableToTranslateType(t, errorMessage);
+ if (errorMessageIn)
+ *errorMessageIn = errorMessage;
+ else
+ qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
+ return {};
+ }
+ return translateType(typeInfo, currentClass, flags, errorMessageIn);
+}
+
+qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringValue, bool &ok)
+{
+ qint64 value = stringValue.toLongLong(&ok);
+ if (ok)
+ return value;
+
+ if (stringValue == u"true" || stringValue == u"false") {
+ ok = true;
+ return (stringValue == u"true");
+ }
+
+ // This is a very lame way to handle expression evaluation,
+ // but it is not critical and will do for the time being.
+ static const QRegularExpression variableNameRegExp("^[a-zA-Z_][a-zA-Z0-9_]*$"_L1);
+ Q_ASSERT(variableNameRegExp.isValid());
+ if (!variableNameRegExp.match(stringValue).hasMatch()) {
+ ok = true;
+ return 0;
+ }
+
+ auto enumValue = AbstractMetaClass::findEnumValue(m_metaClasses, stringValue);
+ if (enumValue.has_value()) {
+ ok = true;
+ return enumValue->value().value();
+ }
+
+ for (const AbstractMetaEnum &metaEnum : std::as_const(m_globalEnums)) {
+ auto ev = metaEnum.findEnumValue(stringValue);
+ if (ev.has_value()) {
+ ok = true;
+ return ev->value().value();
+ }
+ }
+
+ ok = false;
+ return 0;
+}
+
+// Return whether candidate is some underqualified specification of qualifiedType
+// ("B::C" should be qualified to "A::B::C")
+static bool isUnderQualifiedSpec(QStringView qualifiedType, QStringView candidate)
+{
+ const auto candidateSize = candidate.size();
+ const auto qualifiedTypeSize = qualifiedType.size();
+ return candidateSize < qualifiedTypeSize
+ && qualifiedType.endsWith(candidate)
+ && qualifiedType.at(qualifiedTypeSize - candidateSize - 1) == u':';
+}
+
+QString AbstractMetaBuilder::fixEnumDefault(const AbstractMetaType &type,
+ const QString &expr,
+ const AbstractMetaClassCPtr &klass) const
+{
+ return d->fixEnumDefault(type, expr, klass);
+}
+
+void AbstractMetaBuilder::setCodeModelTestMode(bool b)
+{
+ AbstractMetaBuilderPrivate::m_codeModelTestMode = b;
+}
+
+// Helper to fix a simple default value (field or enum reference) in a
+// class context.
+QString AbstractMetaBuilderPrivate::fixSimpleDefaultValue(QStringView expr,
+ const AbstractMetaClassCPtr &klass) const
+{
+ const QString field = qualifyStaticField(klass, expr);
+
+ if (!field.isEmpty())
+ return field;
+ const auto cit = m_classToItem.constFind(klass);
+ if (cit == m_classToItem.cend())
+ return {};
+ auto *scope = dynamic_cast<const _ScopeModelItem *>(cit.value());
+ if (!scope)
+ return {};
+ if (auto enumValue = scope->findEnumByValue(expr))
+ return enumValue.qualifiedName;
+ return {};
+}
+
+// see TestResolveType::testFixDefaultArguments()
+QString AbstractMetaBuilderPrivate::fixDefaultValue(QString expr, const AbstractMetaType &type,
+ const AbstractMetaClassCPtr &implementingClass) const
+{
+ expr.replace(u'\n', u' '); // breaks signature parser
+
+ if (AbstractMetaBuilder::dontFixDefaultValue(expr))
+ return expr;
+
+ if (type.isFlags() || type.isEnum()) {
+ expr = fixEnumDefault(type, expr, implementingClass);
+ } else if (type.isContainer() && expr.contains(u'<')) {
+ // Expand a container of a nested class, fex
+ // "QList<FormatRange>()" -> "QList<QTextLayout::FormatRange>()"
+ if (type.instantiations().size() != 1)
+ return expr; // Only simple types are handled, not QMap<int, int>.
+ auto innerTypeEntry = type.instantiations().constFirst().typeEntry();
+ if (!innerTypeEntry->isComplex())
+ return expr;
+ const QString &qualifiedInnerTypeName = innerTypeEntry->qualifiedCppName();
+ if (!qualifiedInnerTypeName.contains(u"::")) // Nothing to qualify here
+ return expr;
+ const auto openPos = expr.indexOf(u'<');
+ const auto closingPos = expr.lastIndexOf(u'>');
+ if (openPos == -1 || closingPos == -1)
+ return expr;
+ const auto innerPos = openPos + 1;
+ const auto innerLen = closingPos - innerPos;
+ const auto innerType = QStringView{expr}.mid(innerPos, innerLen).trimmed();
+ if (isUnderQualifiedSpec(qualifiedInnerTypeName, innerType))
+ expr.replace(innerPos, innerLen, qualifiedInnerTypeName);
+ } else {
+ // Here the default value is supposed to be a constructor, a class field,
+ // a constructor receiving a static class field or an enum. Consider
+ // class QSqlDatabase { ...
+ // static const char *defaultConnection;
+ // QSqlDatabase(const QString &connection = QLatin1String(defaultConnection))
+ // -> = QLatin1String(QSqlDatabase::defaultConnection)
+ // static void foo(QSqlDatabase db = QSqlDatabase(defaultConnection));
+ // -> = QSqlDatabase(QSqlDatabase::defaultConnection)
+ //
+ // Enum values from the class as defaults of int and others types (via
+ // implicit conversion) are handled here as well:
+ // class QStyleOption { ...
+ // enum StyleOptionType { Type = SO_Default };
+ // QStyleOption(..., int type = SO_Default);
+ // -> = QStyleOption::StyleOptionType::SO_Default
+
+ // Is this a single field or an enum?
+ if (isQualifiedCppIdentifier(expr)) {
+ const QString fixed = fixSimpleDefaultValue(expr, implementingClass);
+ return fixed.isEmpty() ? expr : fixed;
+ }
+
+ // Is this sth like "QLatin1String(field)", "Class(Field)", "Class()"?
+ const auto parenPos = expr.indexOf(u'(');
+ if (parenPos == -1 || !expr.endsWith(u')'))
+ return expr;
+ // Is the term within parentheses a class field or enum?
+ const auto innerLength = expr.size() - parenPos - 2;
+ if (innerLength > 0) { // Not some function call "defaultFunc()"
+ const auto inner = QStringView{expr}.mid(parenPos + 1, innerLength);
+ if (isQualifiedCppIdentifier(inner)
+ && !AbstractMetaBuilder::dontFixDefaultValue(inner)) {
+ const QString replacement = fixSimpleDefaultValue(inner, implementingClass);
+ if (!replacement.isEmpty() && replacement != inner)
+ expr.replace(parenPos + 1, innerLength, replacement);
+ }
+ }
+ // Is this a class constructor "Class(Field)"? Expand it.
+ const auto te = type.typeEntry();
+ if (!te->isComplex())
+ return expr;
+ const QString &qualifiedTypeName = te->qualifiedCppName();
+ if (!qualifiedTypeName.contains(u"::")) // Nothing to qualify here
+ return expr;
+ const auto className = QStringView{expr}.left(parenPos);
+ if (isUnderQualifiedSpec(qualifiedTypeName, className))
+ expr.replace(0, className.size(), qualifiedTypeName);
+ }
+
+ return expr;
+}
+
+QString AbstractMetaBuilder::fixDefaultValue(const QString &expr, const AbstractMetaType &type,
+ const AbstractMetaClassCPtr &c) const
+{
+ return d->fixDefaultValue(expr, type, c);
+}
+
+bool AbstractMetaBuilderPrivate::isEnum(const FileModelItem &dom, const QStringList& qualified_name)
+{
+ CodeModelItem item = dom->model()->findItem(qualified_name, dom);
+ return item && item->kind() == _EnumModelItem::__node_kind;
+}
+
+AbstractMetaClassPtr
+ AbstractMetaBuilderPrivate::findTemplateClass(const QString &name,
+ const AbstractMetaClassCPtr &context,
+ TypeInfo *info,
+ ComplexTypeEntryPtr *baseContainerType) const
+{
+ if (baseContainerType)
+ baseContainerType->reset();
+ auto *types = TypeDatabase::instance();
+
+ QStringList scope = context->typeEntry()->qualifiedCppName().split(u"::"_s);
+ QString errorMessage;
+ scope.removeLast();
+ for (auto i = scope.size(); i >= 0; --i) {
+ QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(u"::"_s) + u"::"_s : QString();
+ QString completeName = prefix + name;
+ const TypeInfo parsed = TypeParser::parse(completeName, &errorMessage);
+ QString qualifiedName = parsed.qualifiedName().join(u"::"_s);
+ if (qualifiedName.isEmpty()) {
+ qWarning().noquote().nospace() << "Unable to parse type \"" << completeName
+ << "\" while looking for template \"" << name << "\": " << errorMessage;
+ continue;
+ }
+ if (info)
+ *info = parsed;
+
+ AbstractMetaClassPtr templ;
+ for (const auto &c : std::as_const(m_templates)) {
+ if (c->typeEntry()->name() == qualifiedName) {
+ templ = c;
+ break;
+ }
+ }
+
+ if (!templ)
+ templ = AbstractMetaClass::findClass(m_metaClasses, qualifiedName);
+
+ if (templ)
+ return templ;
+
+ if (baseContainerType)
+ *baseContainerType = types->findContainerType(qualifiedName);
+ }
+
+ return nullptr;
+}
+
+AbstractMetaClassCList
+ AbstractMetaBuilderPrivate::getBaseClasses(const AbstractMetaClassCPtr &metaClass) const
+{
+ // Shortcut if inheritance has already been set up
+ if (metaClass->inheritanceDone() || !metaClass->needsInheritanceSetup())
+ return metaClass->baseClasses();
+ AbstractMetaClassCList baseClasses;
+ const QStringList &baseClassNames = metaClass->baseClassNames();
+ for (const QString& parent : baseClassNames) {
+ const auto cls = parent.contains(u'<')
+ ? findTemplateClass(parent, metaClass)
+ : AbstractMetaClass::findClass(m_metaClasses, parent);
+
+ if (cls)
+ baseClasses << cls;
+ }
+ return baseClasses;
+}
+
+std::optional<AbstractMetaType>
+ AbstractMetaBuilderPrivate::inheritTemplateType(const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaType &metaType)
+{
+ auto returned = metaType;
+
+ if (!metaType.typeEntry()->isTemplateArgument() && !metaType.hasInstantiations())
+ return returned;
+
+ returned.setOriginalTemplateType(metaType);
+
+ if (returned.typeEntry()->isTemplateArgument()) {
+ const auto tae = std::static_pointer_cast<const TemplateArgumentEntry>(returned.typeEntry());
+
+ // If the template is intantiated with void we special case this as rejecting the functions that use this
+ // parameter from the instantiation.
+ const AbstractMetaType &templateType = templateTypes.value(tae->ordinal());
+ if (templateType.typeEntry()->isVoid())
+ return {};
+
+ AbstractMetaType t = returned;
+ t.setTypeEntry(templateType.typeEntry());
+ t.setIndirections(templateType.indirections() + t.indirections() ? 1 : 0);
+ t.decideUsagePattern();
+
+ return inheritTemplateType(templateTypes, t);
+ }
+
+ if (returned.hasInstantiations()) {
+ AbstractMetaTypeList instantiations = returned.instantiations();
+ for (qsizetype i = 0; i < instantiations.size(); ++i) {
+ auto ins = inheritTemplateType(templateTypes, instantiations.at(i));
+ if (!ins.has_value())
+ return {};
+ instantiations[i] = ins.value();
+ }
+ returned.setInstantiations(instantiations);
+ }
+
+ return returned;
+}
+
+AbstractMetaClassPtr
+ AbstractMetaBuilder::inheritTemplateClass(const ComplexTypeEntryPtr &te,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaTypeList &templateTypes)
+{
+ auto result = std::make_shared<AbstractMetaClass>();
+ result->setTypeDef(true);
+
+ result->setTypeEntry(te);
+ if (!AbstractMetaBuilderPrivate::inheritTemplate(result, templateClass,
+ 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()) {
+ const auto typeO = inheritTemplateParameter(subclass, templateClass, i, &errorMessage);
+ if (typeO.has_value()) {
+ templateTypes.append(typeO.value());
+ } else {
+ 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)
+{
+ subclass->setTemplateBaseClass(templateClass);
+ subclass->setTemplateBaseClassInstantiations(templateTypes);
+ subclass->setBaseClass(templateClass->baseClass());
+ return true;
+}
+
+AbstractMetaFunctionPtr
+ AbstractMetaBuilderPrivate::inheritTemplateFunction(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes)
+{
+ AbstractMetaFunctionPtr f(function->copy());
+ f->setArguments(AbstractMetaArgumentList());
+ f->setFlags(f->flags() | AbstractMetaFunction::Flag::InheritedFromTemplate);
+
+ if (!function->isVoid()) {
+ auto returnType = inheritTemplateType(templateTypes, function->type());
+ if (!returnType.has_value())
+ return {};
+ f->setType(returnType.value());
+ }
+
+ const AbstractMetaArgumentList &arguments = function->arguments();
+ for (const AbstractMetaArgument &argument : arguments) {
+ auto argType = inheritTemplateType(templateTypes, argument.type());
+ if (!argType.has_value())
+ return {};
+ AbstractMetaArgument arg = argument;
+ arg.setType(argType.value());
+ f->addArgument(arg);
+ }
+
+ return f;
+}
+
+AbstractMetaFunctionPtr
+ AbstractMetaBuilder::inheritTemplateFunction(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes)
+{
+ return AbstractMetaBuilderPrivate::inheritTemplateFunction(function, templateTypes);
+}
+
+AbstractMetaFunctionPtr
+ AbstractMetaBuilderPrivate::inheritTemplateMember(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaClassPtr &subclass)
+{
+ AbstractMetaFunctionPtr f = inheritTemplateFunction(function, templateTypes);
+ if (!f)
+ return {};
+
+ // There is no base class in the target language to inherit from here, so
+ // the template instantiation is the class that implements the function.
+ f->setImplementingClass(subclass);
+
+ // We also set it as the declaring class, since the superclass is
+ // supposed to disappear. This allows us to make certain function modifications
+ // on the inherited functions.
+ f->setDeclaringClass(subclass);
+
+ if (f->isConstructor()) {
+ f->setName(subclass->name());
+ f->setOriginalName(subclass->name());
+ }
+
+ ComplexTypeEntryPtr te = subclass->typeEntry();
+ const FunctionModificationList mods = function->modifications(templateClass);
+
+ for (auto mod : mods) {
+ mod.setSignature(f->minimalSignature());
+
+// If we ever need it... Below is the code to do
+// substitution of the template instantation type inside
+// injected code..
+#if 0
+ if (mod.modifiers & Modification::CodeInjection) {
+ for (int j = 0; j < template_types.size(); ++j) {
+ CodeSnip &snip = mod.snips.last();
+ QString code = snip.code();
+ code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j),
+ template_types.at(j)->typeEntry()->qualifiedCppName());
+ snip.codeList.clear();
+ snip.addCode(code);
+ }
+ }
+#endif
+ te->addFunctionModification(mod);
+ }
+
+ QString errorMessage;
+ if (!applyArrayArgumentModifications(f->modifications(subclass), f.get(),
+ &errorMessage)) {
+ qCWarning(lcShiboken, "While specializing %s (%s): %s",
+ qPrintable(subclass->name()), qPrintable(templateClass->name()),
+ qPrintable(errorMessage));
+ }
+ return f;
+}
+
+AbstractMetaFunctionPtr
+ AbstractMetaBuilder::inheritTemplateMember(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaClassPtr &subclass)
+{
+ return AbstractMetaBuilderPrivate::inheritTemplateMember(function, templateTypes,
+ templateClass, subclass);
+}
+
+static bool doInheritTemplateFunction(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaFunctionCList &existingSubclassFuncs,
+ const AbstractMetaClassCPtr &templateBaseClass,
+ const AbstractMetaClassCPtr &subclass)
+{
+ // If the function is modified or the instantiation has an equally named
+ // function we are shadowing, so we need to skip it (unless the subclass
+ // declares it via "using").
+ if (function->isModifiedRemoved())
+ return false;
+ if (function->isConstructor() && !subclass->isTypeDef())
+ return false;
+ return AbstractMetaFunction::find(existingSubclassFuncs, function->name()) == nullptr
+ || subclass->isUsingMember(templateBaseClass, function->name(), Access::Protected);
+}
+
+void AbstractMetaBuilderPrivate::inheritTemplateFunctions(const AbstractMetaClassPtr &subclass)
+{
+ auto templateClass = subclass->templateBaseClass();
+
+ if (subclass->isTypeDef()) {
+ subclass->setHashFunction(templateClass->hashFunction());
+ subclass->setHasNonPrivateConstructor(templateClass->hasNonPrivateConstructor());
+ subclass->setHasPrivateDestructor(templateClass->hasPrivateDestructor());
+ subclass->setHasProtectedDestructor(templateClass->hasProtectedDestructor());
+ subclass->setHasVirtualDestructor(templateClass->hasVirtualDestructor());
+ }
+
+ const auto &templateTypes = subclass->templateBaseClassInstantiations();
+ const AbstractMetaFunctionCList existingSubclassFuncs =
+ subclass->functions(); // Take copy
+ const auto &templateClassFunctions = templateClass->functions();
+ for (const auto &function : templateClassFunctions) {
+ if (doInheritTemplateFunction(function, existingSubclassFuncs,
+ templateClass, subclass)) {
+ AbstractMetaFunctionCPtr f = inheritTemplateMember(function, templateTypes,
+ templateClass, subclass);
+ if (f)
+ AbstractMetaClass::addFunction(subclass, f);
+ }
+ }
+
+ // Take copy
+ const AbstractMetaFieldList existingSubclassFields = subclass->fields();
+ const AbstractMetaFieldList &templateClassFields = templateClass->fields();
+ for (const AbstractMetaField &field : templateClassFields) {
+ // If the field is modified or the instantiation has a field named
+ // the same as an existing field we have shadowing, so we need to skip it.
+ if (field.isModifiedRemoved() || field.isStatic()
+ || AbstractMetaField::find(existingSubclassFields, field.name()).has_value()) {
+ continue;
+ }
+
+ AbstractMetaField f = field;
+ f.setEnclosingClass(subclass);
+ auto fieldType = inheritTemplateType(templateTypes, field.type());
+ if (!fieldType.has_value())
+ continue;
+ f.setType(fieldType.value());
+ subclass->addField(f);
+ }
+}
+
+void AbstractMetaBuilderPrivate::parseQ_Properties(const AbstractMetaClassPtr &metaClass,
+ const QStringList &declarations)
+{
+ const QStringList scopes = currentScope()->qualifiedName();
+ QString errorMessage;
+ int i = 0;
+ for (; i < declarations.size(); ++i) {
+ auto spec = QPropertySpec::parseQ_Property(this, metaClass, declarations.at(i), scopes, &errorMessage);
+ if (spec.has_value()) {
+ spec->setIndex(i);
+ metaClass->addPropertySpec(spec.value());
+ } else if (!errorMessage.isEmpty()) {
+ QString message;
+ QTextStream str(&message);
+ str << metaClass->sourceLocation() << errorMessage;
+ qCWarning(lcShiboken, "%s", qPrintable(message));
+ }
+ }
+
+ // User-added properties
+ auto typeEntry = metaClass->typeEntry();
+ for (const TypeSystemProperty &tp : typeEntry->properties()) {
+ std::optional<QPropertySpec> spec;
+ if (metaClass->propertySpecByName(tp.name))
+ errorMessage = msgPropertyExists(metaClass->name(), tp.name);
+ else
+ spec = QPropertySpec::fromTypeSystemProperty(this, metaClass, tp, scopes, &errorMessage);
+
+ if (spec.has_value()) {
+ spec->setIndex(i++);
+ metaClass->addPropertySpec(spec.value());
+ } else {
+ QString message;
+ QTextStream str(&message);
+ str << typeEntry->sourceLocation() << errorMessage;
+ qCWarning(lcShiboken, "%s", qPrintable(message));
+ }
+ }
+}
+
+void AbstractMetaBuilderPrivate::setupExternalConversion(const AbstractMetaClassCPtr &cls)
+{
+ const auto &convOps = cls->operatorOverloads(OperatorQueryOption::ConversionOp);
+ for (const auto &func : convOps) {
+ if (func->isModifiedRemoved())
+ continue;
+ const auto metaClass =
+ AbstractMetaClass::findClass(m_metaClasses, func->type().typeEntry());
+ if (!metaClass)
+ continue;
+ metaClass->addExternalConversionOperator(func);
+ }
+ for (const auto &innerClass : cls->innerClasses())
+ setupExternalConversion(innerClass);
+}
+
+static void writeRejectLogFile(const QString &name,
+ const AbstractMetaBuilderPrivate::RejectSet &rejects)
+{
+ static const QHash<AbstractMetaBuilder::RejectReason, QByteArray> descriptions ={
+ {AbstractMetaBuilder::NotInTypeSystem, "Not in type system"_ba},
+ {AbstractMetaBuilder::GenerationDisabled, "Generation disabled by type system"_ba},
+ {AbstractMetaBuilder::RedefinedToNotClass, "Type redefined to not be a class"_ba},
+ {AbstractMetaBuilder::UnmatchedReturnType, "Unmatched return type"_ba},
+ {AbstractMetaBuilder::UnmatchedArgumentType, "Unmatched argument type"_ba},
+ {AbstractMetaBuilder::UnmatchedOperator, "Unmatched operator"_ba},
+ {AbstractMetaBuilder::Deprecated, "Deprecated"_ba}
+ };
+
+ QFile f(name);
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ qCWarning(lcShiboken, "%s", qPrintable(msgCannotOpenForWriting(f)));
+ return;
+ }
+
+ QTextStream s(&f);
+
+ int lastReason = -1;
+ for (const auto &e : rejects) {
+ if (e.reason != lastReason) {
+ const QByteArray description = descriptions.value(e.reason, "Unknown reason"_ba);
+ const QByteArray underline(description.size(), '*');
+ if (lastReason != -1)
+ s << '\n';
+ s << underline << '\n' << description << '\n' << underline << "\n\n";
+ lastReason = e.reason;
+ }
+
+ s << " - " << e << '\n';
+ }
+}
+
+void AbstractMetaBuilderPrivate::dumpLog() const
+{
+ writeRejectLogFile(m_logDirectory + u"mjb_rejected_classes.log"_s, m_rejectedClasses);
+ writeRejectLogFile(m_logDirectory + u"mjb_rejected_enums.log"_s, m_rejectedEnums);
+ writeRejectLogFile(m_logDirectory + u"mjb_rejected_functions.log"_s, m_rejectedFunctions);
+ writeRejectLogFile(m_logDirectory + u"mjb_rejected_fields.log"_s, m_rejectedFields);
+}
+
+// Topological sorting of classes. Templates for use with
+// AbstractMetaClassList/AbstractMetaClassCList.
+// Add a dependency of the class associated with typeEntry on clazz.
+template <class MetaClass>
+static bool addClassDependency(const QList<std::shared_ptr<MetaClass> > &classList,
+ const TypeEntryCPtr &typeEntry,
+ std::shared_ptr<MetaClass> clazz,
+ Graph<std::shared_ptr<MetaClass> > *graph)
+{
+ if (!typeEntry->isComplex() || typeEntry == clazz->typeEntry())
+ return false;
+ const auto c = AbstractMetaClass::findClass(classList, typeEntry);
+ if (c == nullptr || c->enclosingClass() == clazz)
+ return false;
+ return graph->addEdge(c, clazz);
+}
+
+template <class MetaClass>
+static QList<std::shared_ptr<MetaClass> >
+ topologicalSortHelper(const QList<std::shared_ptr<MetaClass> > &classList,
+ const Dependencies &additionalDependencies)
+{
+ Graph<std::shared_ptr<MetaClass> > graph(classList.cbegin(), classList.cend());
+
+ for (const auto &dep : additionalDependencies) {
+ if (!graph.addEdge(dep.parent, dep.child)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "AbstractMetaBuilder::classesTopologicalSorted(): Invalid additional dependency: "
+ << dep.child->name() << " -> " << dep.parent->name() << '.';
+ }
+ }
+
+ for (const auto &clazz : classList) {
+ if (auto enclosingC = clazz->enclosingClass()) {
+ const auto enclosing = std::const_pointer_cast<MetaClass>(enclosingC);
+ graph.addEdge(enclosing, clazz);
+ }
+
+ for (const auto &baseClass : clazz->baseClasses())
+ graph.addEdge(std::const_pointer_cast<MetaClass>(baseClass), clazz);
+
+ for (const auto &func : clazz->functions()) {
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument &arg : arguments) {
+ // Check methods with default args: If a class is instantiated by value,
+ // ("QString s = QString()"), add a dependency.
+ if (!arg.originalDefaultValueExpression().isEmpty()
+ && arg.type().isValue()) {
+ addClassDependency(classList, arg.type().typeEntry(),
+ clazz, &graph);
+ }
+ }
+ }
+ // Member fields need to be initialized
+ for (const AbstractMetaField &field : clazz->fields()) {
+ auto typeEntry = field.type().typeEntry();
+ if (typeEntry->isEnum()) // Enum defined in class?
+ typeEntry = typeEntry->parent();
+ if (typeEntry != nullptr)
+ addClassDependency(classList, typeEntry, clazz, &graph);
+ }
+ }
+
+ const auto result = graph.topologicalSort();
+ if (!result.isValid() && graph.nodeCount()) {
+ QTemporaryFile tempFile(QDir::tempPath() + u"/cyclic_depXXXXXX.dot"_s);
+ tempFile.setAutoRemove(false);
+ const bool ok = tempFile.open();
+ if (ok) {
+ graph.dumpDot(tempFile.fileName(),
+ [] (const AbstractMetaClassCPtr &c) { return c->name(); });
+ }
+
+ QString message;
+ QTextStream str(&message);
+ str << "Cyclic dependency of classes found:";
+ for (const auto &c : result.cyclic)
+ str << ' ' << c->name();
+ str << '.';
+ if (ok) {
+ str << " Graph can be found at \""
+ << QDir::toNativeSeparators(tempFile.fileName()) << '"';
+ }
+ qCWarning(lcShiboken, "%s", qPrintable(message));
+ }
+
+ return result.result;
+}
+
+AbstractMetaClassList
+ AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassList &classList,
+ const Dependencies &additionalDependencies)
+{
+ return topologicalSortHelper(classList, additionalDependencies);
+}
+
+AbstractMetaClassCList
+ AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassCList &classList,
+ const Dependencies &additionalDependencies)
+{
+ return topologicalSortHelper(classList, additionalDependencies);
+}
+
+void AbstractMetaBuilderPrivate::pushScope(const NamespaceModelItem &item)
+{
+ // For purposes of type lookup, join all namespaces of the same name
+ // within the parent item.
+ QList<NamespaceModelItem> candidates;
+ const QString name = item->name();
+ if (!m_scopes.isEmpty()) {
+ for (const auto &n : m_scopes.constLast()->namespaces()) {
+ if (n->name() == name)
+ candidates.append(n);
+ }
+ }
+ if (candidates.size() > 1) {
+ auto joined = std::make_shared<_NamespaceModelItem>(m_scopes.constLast()->model(),
+ name, _CodeModelItem::Kind_Namespace);
+ joined->setScope(item->scope());
+ for (const auto &n : candidates)
+ joined->appendNamespace(*n);
+ m_scopes << joined;
+ } else {
+ m_scopes << item;
+ }
+}
+
+void AbstractMetaBuilder::setGlobalHeaders(const QFileInfoList &globalHeaders)
+{
+ d->m_globalHeaders = globalHeaders;
+}
+
+void AbstractMetaBuilder::setHeaderPaths(const HeaderPaths &hp)
+{
+ for (const auto & h: hp) {
+ if (h.type != HeaderType::Framework && h.type != HeaderType::FrameworkSystem)
+ d->m_headerPaths.append(QFile::decodeName(h.path));
+ }
+}
+
+void AbstractMetaBuilder::setUseGlobalHeader(bool h)
+{
+ AbstractMetaBuilderPrivate::m_useGlobalHeader = h;
+}
+
+void AbstractMetaBuilder::setSkipDeprecated(bool value)
+{
+ d->m_skipDeprecated = value;
+}
+
+void AbstractMetaBuilder::setApiExtractorFlags(ApiExtractorFlags flags)
+{
+ d->m_apiExtractorFlags = flags;
+}
+
+// PYSIDE-975: When receiving an absolute path name from the code model, try
+// to resolve it against the include paths set on shiboken in order to recreate
+// relative paths like #include <foo/bar.h>.
+
+static inline bool isFileSystemSlash(QChar c)
+{
+ return c == u'/' || c == u'\\';
+}
+
+static bool matchHeader(const QString &headerPath, const QString &fileName)
+{
+#if defined(Q_OS_WIN) || defined(Q_OS_DARWIN)
+ static const Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive;
+#else
+ static const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive;
+#endif
+ const auto pathSize = headerPath.size();
+ return fileName.size() > pathSize
+ && isFileSystemSlash(fileName.at(pathSize))
+ && fileName.startsWith(headerPath, caseSensitivity);
+}
+
+void AbstractMetaBuilderPrivate::setInclude(const TypeEntryPtr &te, const QString &path) const
+{
+ auto it = m_resolveIncludeHash.find(path);
+ if (it == m_resolveIncludeHash.end()) {
+ QFileInfo info(path);
+ const QString fileName = info.fileName();
+ if (!m_useGlobalHeader
+ && std::any_of(m_globalHeaders.cbegin(), m_globalHeaders.cend(),
+ [fileName] (const QFileInfo &fi) {
+ return fi.fileName() == fileName; })) {
+ return;
+ }
+
+ int bestMatchLength = 0;
+ for (const auto &headerPath : m_headerPaths) {
+ if (headerPath.size() > bestMatchLength && matchHeader(headerPath, path))
+ bestMatchLength = headerPath.size();
+ }
+ const QString include = bestMatchLength > 0
+ ? path.right(path.size() - bestMatchLength - 1) : fileName;
+ it = m_resolveIncludeHash.insert(path, {Include::IncludePath, include});
+ }
+ te->setInclude(it.value());
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class Container>
+static void debugFormatSequence(QDebug &d, const char *key, const Container& c,
+ const char *separator = ", ")
+{
+ if (c.isEmpty())
+ return;
+ const auto begin = c.begin();
+ const auto end = c.end();
+ d << "\n " << key << '[' << c.size() << "]=(";
+ for (auto it = begin; it != end; ++it) {
+ if (it != begin)
+ d << separator;
+ d << *it;
+ }
+ d << ')';
+}
+
+void AbstractMetaBuilder::formatDebug(QDebug &debug) const
+{
+ debug << "m_globalHeader=" << d->m_globalHeaders;
+ debugFormatSequence(debug, "globalEnums", d->m_globalEnums, "\n");
+ debugFormatSequence(debug, "globalFunctions", d->m_globalFunctions, "\n");
+ if (const auto scopeCount = d->m_scopes.size()) {
+ debug << "\n scopes[" << scopeCount << "]=(";
+ for (qsizetype i = 0; i < scopeCount; ++i) {
+ if (i)
+ debug << ", ";
+ _CodeModelItem::formatKind(debug, d->m_scopes.at(i)->kind());
+ debug << " \"" << d->m_scopes.at(i)->name() << '"';
+ }
+ debug << ')';
+ }
+ debugFormatSequence(debug, "classes", d->m_metaClasses, "\n");
+ debugFormatSequence(debug, "templates", d->m_templates, "\n");
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaBuilder &ab)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaBuilder(";
+ ab.formatDebug(d);
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h
new file mode 100644
index 000000000..20261ed3c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h
@@ -0,0 +1,152 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETABUILDER_H
+#define ABSTRACTMETABUILDER_H
+
+#include "abstractmetalang_typedefs.h"
+#include "apiextractorflags.h"
+#include "header_paths.h"
+#include "typesystem_enums.h"
+#include "typesystem_typedefs.h"
+
+#include "clangparser/compilersupport.h"
+
+#include <QtCore/QFileInfoList>
+
+#include <optional>
+
+QT_FORWARD_DECLARE_CLASS(QIODevice)
+
+class AbstractMetaBuilderPrivate;
+class AbstractMetaClass;
+class AbstractMetaType;
+class AbstractMetaEnumValue;
+class ComplexTypeEntry;
+class TypeInfo;
+class TypeEntry;
+
+class AbstractMetaBuilder
+{
+public:
+ Q_DISABLE_COPY_MOVE(AbstractMetaBuilder)
+
+ enum RejectReason {
+ NotInTypeSystem,
+ GenerationDisabled,
+ RedefinedToNotClass,
+ UnmatchedArgumentType,
+ UnmatchedReturnType,
+ UnmatchedOperator,
+ Deprecated,
+ NoReason
+ };
+
+ AbstractMetaBuilder();
+ virtual ~AbstractMetaBuilder();
+
+ const AbstractMetaClassList &classes() const;
+ AbstractMetaClassList takeClasses();
+ const AbstractMetaClassList &templates() const;
+ AbstractMetaClassList takeTemplates();
+ const AbstractMetaClassList &smartPointers() const;
+ AbstractMetaClassList takeSmartPointers();
+ const AbstractMetaFunctionCList &globalFunctions() const;
+ const AbstractMetaEnumList &globalEnums() const;
+ const QHash<TypeEntryCPtr, AbstractMetaEnum> &typeEntryToEnumsHash() const;
+ const QMultiHash<QString, QString> &typedefTargetToName() const;
+
+ bool build(const QByteArrayList &arguments,
+ ApiExtractorFlags apiExtractorFlags = {},
+ bool addCompilerSupportArguments = true,
+ LanguageLevel level = LanguageLevel::Default,
+ unsigned clangFlags = 0);
+ void setLogDirectory(const QString& logDir);
+
+ /**
+ * AbstractMetaBuilder should know what's the global header being used,
+ * so any class declared under this header wont have the include file
+ * filled.
+ */
+ void setGlobalHeaders(const QFileInfoList& globalHeaders);
+ void setHeaderPaths(const HeaderPaths &h);
+
+ static void setUseGlobalHeader(bool h);
+
+ void setSkipDeprecated(bool value);
+
+ void setApiExtractorFlags(ApiExtractorFlags flags);
+
+ enum TranslateTypeFlag {
+ DontResolveType = 0x1,
+ TemplateArgument = 0x2,
+ NoClassScopeLookup = 0x4
+ };
+ Q_DECLARE_FLAGS(TranslateTypeFlags, TranslateTypeFlag);
+
+ static std::optional<AbstractMetaType>
+ translateType(const TypeInfo &_typei, const AbstractMetaClassPtr &currentClass = {},
+ TranslateTypeFlags flags = {}, QString *errorMessage = nullptr);
+ static std::optional<AbstractMetaType>
+ translateType(const QString &t, const AbstractMetaClassPtr &currentClass = {},
+ TranslateTypeFlags flags = {}, QString *errorMessage = nullptr);
+
+ /// Performs a template specialization of the function.
+ /// \param function Function
+ /// \param templateTypes Instantiation types
+ /// \return Specialized copy of the function
+ static AbstractMetaFunctionPtr
+ inheritTemplateFunction(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes);
+
+ static AbstractMetaClassPtr
+ inheritTemplateClass(const ComplexTypeEntryPtr &te,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaTypeList &templateTypes);
+
+ /// Performs a template specialization of the member function.
+ /// \param function Member function
+ /// \param templateTypes Instantiation types
+ /// \param templateClass Template class
+ /// \param subclass Specialized class
+ /// \return Specialized copy of the function
+ static AbstractMetaFunctionPtr
+ inheritTemplateMember(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaClassPtr &subclass);
+
+ static QString getSnakeCaseName(const QString &name);
+ // Names under which an item will be registered to Python depending on snakeCase
+ static QStringList definitionNames(const QString &name,
+ TypeSystem::SnakeCase snakeCase);
+
+ static QString resolveScopePrefix(const AbstractMetaClassCPtr &scope,
+ QStringView value);
+
+ static bool dontFixDefaultValue(QStringView expr);
+
+ // For testing purposes
+ QString fixDefaultValue(const QString &expr, const AbstractMetaType &type,
+ const AbstractMetaClassCPtr &) const;
+ QString fixEnumDefault(const AbstractMetaType &type, const QString &expr,
+ const AbstractMetaClassCPtr & = {}) const;
+
+ static void setCodeModelTestMode(bool b);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+private:
+ friend class AbstractMetaBuilderPrivate;
+ AbstractMetaBuilderPrivate *d;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaBuilder::TranslateTypeFlags);
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaBuilder &ab);
+#endif
+
+#endif // ABSTRACTMETBUILDER_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp
new file mode 100644
index 000000000..68eef737a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp
@@ -0,0 +1,202 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstractmetabuilder.h"
+#include "abstractmetabuilder_p.h"
+#include "abstractmetaenum.h"
+#include "abstractmetafield.h"
+#include "abstractmetalang.h"
+#include "enumtypeentry.h"
+#include "flagstypeentry.h"
+
+using namespace Qt::StringLiterals;
+
+using QStringViewList = QList<QStringView>;
+
+// Return a prefix to fully qualify value, eg:
+// resolveScopePrefix("Class::NestedClass::Enum::Value1", "Enum::Value1")
+// -> "Class::NestedClass::")
+static QString resolveScopePrefixHelper(const QStringViewList &scopeList,
+ QStringView value)
+{
+ QString name;
+ for (qsizetype i = scopeList.size() - 1 ; i >= 0; --i) {
+ const QString prefix = scopeList.at(i).toString() + u"::"_s;
+ if (value.startsWith(prefix))
+ name.clear();
+ else
+ name.prepend(prefix);
+ }
+ return name;
+}
+
+QString AbstractMetaBuilder::resolveScopePrefix(const AbstractMetaClassCPtr &scope,
+ QStringView value)
+{
+ if (!scope)
+ return {};
+ const QString &qualifiedCppName = scope->qualifiedCppName();
+ const QStringViewList scopeList =
+ QStringView{qualifiedCppName}.split(u"::"_s, Qt::SkipEmptyParts);
+ return resolveScopePrefixHelper(scopeList, value);
+}
+
+// Return the scope for fully qualifying the enumeration value
+static QString resolveEnumValueScopePrefix(const AbstractMetaEnum &metaEnum,
+ QStringView value)
+{
+ AbstractMetaClassCPtr scope = metaEnum.enclosingClass();
+ if (!scope)
+ return {}; // global enum, value should work as is
+ const QString &qualifiedCppName = scope->qualifiedCppName();
+ const QString &enumName = metaEnum.name();
+ QStringViewList parts =
+ QStringView{qualifiedCppName}.split(u"::"_s, Qt::SkipEmptyParts);
+ // Append the type (as required for enum classes) unless it is an anonymous enum.
+ if (!metaEnum.isAnonymous())
+ parts.append(QStringView{enumName});
+ return resolveScopePrefixHelper(parts, value);
+}
+
+bool AbstractMetaBuilderPrivate::isQualifiedCppIdentifier(QStringView e)
+{
+ return !e.isEmpty() && e.at(0).isLetter()
+ && std::all_of(e.cbegin() + 1, e.cend(),
+ [](QChar c) { return c.isLetterOrNumber() || c == u'_' || c == u':'; });
+}
+
+static bool isIntegerConstant(const QStringView expr)
+{
+ bool isNumber;
+ auto n = expr.toInt(&isNumber, /* guess base: 0x or decimal */ 0);
+ Q_UNUSED(n);
+ return isNumber;
+}
+
+static bool isFloatConstant(const QStringView expr)
+{
+ bool isNumber;
+ auto d = expr.toDouble(&isNumber);
+ Q_UNUSED(d);
+ return isNumber;
+}
+
+// Fix an enum default value: Add the enum/flag scope or fully qualified name
+// to the default value, making it usable from Python wrapper code outside the
+// owner class hierarchy. See TestEnum::testEnumDefaultValues().
+QString AbstractMetaBuilderPrivate::fixEnumDefault(const AbstractMetaType &type,
+ const QString &expr,
+ const AbstractMetaClassCPtr &klass) const
+{
+ // QFlags construct from integers, do not fix that
+ if (isIntegerConstant(expr))
+ return expr;
+
+ const QString field = qualifyStaticField(klass, expr);
+ if (!field.isEmpty())
+ return field;
+
+ const auto typeEntry = type.typeEntry();
+ EnumTypeEntryCPtr enumTypeEntry;
+ FlagsTypeEntryCPtr flagsTypeEntry;
+ if (typeEntry->isFlags()) {
+ flagsTypeEntry = std::static_pointer_cast<const FlagsTypeEntry>(typeEntry);
+ enumTypeEntry = flagsTypeEntry->originator();
+ } else {
+ Q_ASSERT(typeEntry->isEnum());
+ enumTypeEntry = std::static_pointer_cast<const EnumTypeEntry>(typeEntry);
+ }
+ // Use the enum's qualified name (would otherwise be "QFlags<Enum>")
+ if (!enumTypeEntry->qualifiedCppName().contains(u"::"))
+ return expr; // Global enum, nothing to fix here
+
+ // This is a somehow scoped enum
+ AbstractMetaEnum metaEnum = m_enums.value(enumTypeEntry);
+
+ if (isQualifiedCppIdentifier(expr)) // A single enum value
+ return resolveEnumValueScopePrefix(metaEnum, expr) + expr;
+
+ QString result;
+ // Is this a cast from integer or other type ("Enum(-1)" or "Options(0x10|0x20)"?
+ // Prepend the scope (assuming enum and flags are in the same scope).
+ auto parenPos = expr.indexOf(u'(');
+ const bool typeCast = parenPos != -1 && expr.endsWith(u')')
+ && isQualifiedCppIdentifier(QStringView{expr}.left(parenPos));
+ if (typeCast) {
+ const QString prefix =
+ AbstractMetaBuilder::resolveScopePrefix(metaEnum.enclosingClass(), expr);
+ result += prefix;
+ parenPos += prefix.size();
+ }
+ result += expr;
+
+ // Extract "Option1 | Option2" from "Options(Option1 | Option2)"
+ QStringView innerExpression = typeCast
+ ? QStringView{result}.mid(parenPos + 1, result.size() - parenPos - 2)
+ : QStringView{result};
+
+ // Quick check for number "Options(0x4)"
+ if (isIntegerConstant(innerExpression))
+ return result;
+
+ // Quick check for single enum value "Options(Option1)"
+ if (isQualifiedCppIdentifier(innerExpression)) {
+ const QString prefix = resolveEnumValueScopePrefix(metaEnum, innerExpression);
+ result.insert(parenPos + 1, prefix);
+ return result;
+ }
+
+ // Tokenize simple "A | B" expressions and qualify the enum values therein.
+ // Anything more complicated is left as is ATM.
+ if (!innerExpression.contains(u'|') || innerExpression.contains(u'&')
+ || innerExpression.contains(u'^') || innerExpression.contains(u'(')
+ || innerExpression.contains(u'~')) {
+ return result;
+ }
+
+ const QList<QStringView> tokens = innerExpression.split(u'|', Qt::SkipEmptyParts);
+ QStringList qualifiedTokens;
+ qualifiedTokens.reserve(tokens.size());
+ for (const auto &tokenIn : tokens) {
+ const auto token = tokenIn.trimmed();
+ QString qualified = token.toString();
+ if (!isIntegerConstant(token) && isQualifiedCppIdentifier(token))
+ qualified.prepend(resolveEnumValueScopePrefix(metaEnum, token));
+ qualifiedTokens.append(qualified);
+ }
+ const QString qualifiedExpression = qualifiedTokens.join(u" | "_s);
+ if (!typeCast)
+ return qualifiedExpression;
+
+ result.replace(parenPos + 1, innerExpression.size(), qualifiedExpression);
+ return result;
+}
+
+bool AbstractMetaBuilder::dontFixDefaultValue(QStringView expr)
+{
+ return expr.isEmpty() || expr == u"{}" || expr == u"nullptr"
+ || expr == u"NULL" || expr == u"true" || expr == u"false"
+ || (expr.startsWith(u'{') && expr.startsWith(u'}')) // initializer list
+ || (expr.startsWith(u'[') && expr.startsWith(u']')) // array
+ || expr.startsWith(u"Qt::") // Qt namespace constant
+ || isIntegerConstant(expr) || isFloatConstant(expr);
+}
+
+QString AbstractMetaBuilderPrivate::qualifyStaticField(const AbstractMetaClassCPtr &c,
+ QStringView field)
+{
+ if (!c || c->fields().isEmpty())
+ return {};
+ // If there is a scope, ensure it matches the class
+ const auto lastQualifier = field.lastIndexOf(u"::");
+ if (lastQualifier != -1
+ && !c->qualifiedCppName().endsWith(field.left(lastQualifier))) {
+ return {};
+ }
+ const auto fieldName = lastQualifier != -1
+ ? field.mid(lastQualifier + 2) : field;
+ const auto fieldOpt = c->findField(fieldName);
+ if (!fieldOpt.has_value() || !fieldOpt.value().isStatic())
+ return {};
+ return AbstractMetaBuilder::resolveScopePrefix(c, field) + field.toString();
+}
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
new file mode 100644
index 000000000..e65a4f176
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
@@ -0,0 +1,254 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETABUILDER_P_H
+#define ABSTRACTMETABUILDER_P_H
+
+#include "abstractmetabuilder.h"
+#include "dependency.h"
+#include "parser/codemodel_fwd.h"
+#include "abstractmetalang.h"
+#include "abstractmetatype.h"
+#include "include.h"
+#include "typeparser.h"
+#include "modifications_typedefs.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QMultiHash>
+#include <QtCore/QSet>
+
+#include <optional>
+#include <set>
+
+class TypeDatabase;
+
+struct RejectEntry
+{
+ AbstractMetaBuilder::RejectReason reason;
+ QString signature;
+ QString sortkey;
+ QString message;
+};
+
+bool operator<(const RejectEntry &re1, const RejectEntry &re2);
+
+class AbstractMetaBuilderPrivate
+{
+public:
+ struct TypeClassEntry
+ {
+ AbstractMetaType type;
+ AbstractMetaClassCPtr klass;
+ };
+
+ using TranslateTypeFlags = AbstractMetaBuilder::TranslateTypeFlags;
+
+ Q_DISABLE_COPY(AbstractMetaBuilderPrivate)
+
+ AbstractMetaBuilderPrivate();
+
+ static FileModelItem buildDom(QByteArrayList arguments,
+ bool addCompilerSupportArguments,
+ LanguageLevel level,
+ unsigned clangFlags);
+ void traverseDom(const FileModelItem &dom, ApiExtractorFlags flags);
+
+ void dumpLog() const;
+
+ static AbstractMetaClassList
+ classesTopologicalSorted(const AbstractMetaClassList &classList,
+ const Dependencies &additionalDependencies = {});
+ static AbstractMetaClassCList
+ classesTopologicalSorted(const AbstractMetaClassCList &classList,
+ const Dependencies &additionalDependencies = {});
+
+ NamespaceModelItem popScope() { return m_scopes.takeLast(); }
+
+ void pushScope(const NamespaceModelItem &item);
+
+ NamespaceModelItem currentScope() const { return m_scopes.constLast(); }
+
+ AbstractMetaClassPtr argumentToClass(const ArgumentModelItem &,
+ const AbstractMetaClassCPtr &currentClass);
+
+ void addAbstractMetaClass(const AbstractMetaClassPtr &cls, const _CodeModelItem *item);
+ AbstractMetaClassPtr traverseTypeDef(const FileModelItem &dom,
+ const TypeDefModelItem &typeDef,
+ const AbstractMetaClassPtr &currentClass);
+ AbstractMetaClassPtr traverseTypeDefHelper(const FileModelItem &dom,
+ const TypeDefModelItem &typeDef,
+ const AbstractMetaClassPtr &currentClass);
+ void traverseTypesystemTypedefs();
+ AbstractMetaClassPtr traverseClass(const FileModelItem &dom,
+ const ClassModelItem &item,
+ const AbstractMetaClassPtr &currentClass);
+ void traverseScopeMembers(const ScopeModelItem &item,
+ const AbstractMetaClassPtr &metaClass);
+ void traverseClassMembers(const ClassModelItem &scopeItem);
+ void traverseUsingMembers(const AbstractMetaClassPtr &metaClass) const;
+ void traverseNamespaceMembers(const NamespaceModelItem &scopeItem);
+ bool setupInheritance(const AbstractMetaClassPtr &metaClass);
+ AbstractMetaClassPtr traverseNamespace(const FileModelItem &dom,
+ const NamespaceModelItem &item);
+ std::optional<AbstractMetaEnum> traverseEnum(const EnumModelItem &item,
+ const AbstractMetaClassPtr &enclosing,
+ 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);
+ void traverseFunctions(const ScopeModelItem& item,
+ const AbstractMetaClassPtr &parent);
+ static void applyFunctionModifications(AbstractMetaFunction *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);
+ bool traverseAddedGlobalFunction(const AddedFunctionPtr &addedFunc,
+ QString *errorMessage);
+ bool traverseAddedMemberFunction(const AddedFunctionPtr &addedFunc,
+ const AbstractMetaClassPtr &metaClass,
+ QString *errorMessage);
+ void rejectFunction(const FunctionModelItem &functionItem,
+ const AbstractMetaClassPtr &currentClass,
+ AbstractMetaBuilder::RejectReason reason,
+ const QString &rejectReason);
+ AbstractMetaFunction *traverseFunction(const FunctionModelItem &function,
+ const AbstractMetaClassPtr &currentClass);
+ std::optional<AbstractMetaField> traverseField(const VariableModelItem &field,
+ const AbstractMetaClassCPtr &cls);
+ void checkFunctionModifications() const;
+ void registerHashFunction(const FunctionModelItem &functionItem,
+ const AbstractMetaClassPtr &currentClass);
+ void registerToStringCapabilityIn(const NamespaceModelItem &namespaceItem);
+ void registerToStringCapability(const FunctionModelItem &functionItem,
+ const AbstractMetaClassPtr &currentClass);
+
+ /**
+ * A conversion operator function should not have its owner class as
+ * its return type, but unfortunately it does. This function fixes the
+ * return type of operator functions of this kind making the return type
+ * be the same as it is supposed to generate when used in C++.
+ * If the returned type is a wrapped C++ class, this method also adds the
+ * conversion operator to the collection of external conversions of the
+ * said class.
+ * \param metaFunction conversion operator function to be fixed.
+ */
+ static void fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction);
+
+ void parseQ_Properties(const AbstractMetaClassPtr &metaClass,
+ const QStringList &declarations);
+ void setupEquals(const AbstractMetaClassPtr &metaClass);
+ void setupComparable(const AbstractMetaClassPtr &metaClass);
+ void setupExternalConversion(const AbstractMetaClassCPtr &cls);
+
+ static bool isQualifiedCppIdentifier(QStringView e);
+ QString fixDefaultValue(QString expr, const AbstractMetaType &type,
+ const AbstractMetaClassCPtr &) const;
+ QString fixSimpleDefaultValue(QStringView expr,
+ const AbstractMetaClassCPtr &klass) const;
+
+ QString fixEnumDefault(const AbstractMetaType &type, const QString &expr,
+ const AbstractMetaClassCPtr &) const;
+ /// Qualify a static field name for default value expressions
+ static QString qualifyStaticField(const AbstractMetaClassCPtr &c, QStringView field);
+
+ std::optional<AbstractMetaType>
+ translateType(const TypeInfo &type, const AbstractMetaClassCPtr &currentClass,
+ TranslateTypeFlags flags = {}, QString *errorMessage = nullptr);
+ static std::optional<AbstractMetaType>
+ translateTypeStatic(const TypeInfo &type, const AbstractMetaClassCPtr &current,
+ AbstractMetaBuilderPrivate *d = nullptr, TranslateTypeFlags flags = {},
+ QString *errorMessageIn = nullptr);
+ static TypeEntryCList findTypeEntriesHelper(const QString &qualifiedName, const QString &name,
+ TranslateTypeFlags flags = {},
+ const AbstractMetaClassCPtr &currentClass = {},
+ AbstractMetaBuilderPrivate *d = nullptr);
+ static TypeEntryCList findTypeEntries(const QString &qualifiedName, const QString &name,
+ TranslateTypeFlags flags = {},
+ const AbstractMetaClassCPtr &currentClass = {},
+ AbstractMetaBuilderPrivate *d = nullptr,
+ QString *errorMessage = nullptr);
+
+ qint64 findOutValueFromString(const QString &stringValue, bool &ok);
+
+ AbstractMetaClassPtr findTemplateClass(const QString& name, const AbstractMetaClassCPtr &context,
+ TypeInfo *info = nullptr,
+ ComplexTypeEntryPtr *baseContainerType = nullptr) const;
+ AbstractMetaClassCList getBaseClasses(const AbstractMetaClassCPtr &metaClass) const;
+
+ static bool inheritTemplate(const AbstractMetaClassPtr &subclass,
+ const AbstractMetaClassCPtr &templateClass,
+ const TypeInfo &info);
+ static bool inheritTemplate(const AbstractMetaClassPtr &subclass,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaTypeList &templateTypes);
+
+ static AbstractMetaFunctionPtr
+ inheritTemplateFunction(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes);
+
+ static AbstractMetaFunctionPtr
+ inheritTemplateMember(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaClassPtr &subclass);
+
+ static void inheritTemplateFunctions(const AbstractMetaClassPtr &subclass);
+ static std::optional<AbstractMetaType>
+ inheritTemplateType(const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaType &metaType);
+
+ static bool isQObject(const FileModelItem &dom, const QString &qualifiedName);
+ static bool isEnum(const FileModelItem &dom, const QStringList &qualifiedName);
+
+ void sortLists();
+ void setInclude(const TypeEntryPtr &te, const QString &path) const;
+ static void fixArgumentNames(AbstractMetaFunction *func, const FunctionModificationList &mods);
+
+ void fillAddedFunctions(const AbstractMetaClassPtr &metaClass);
+ AbstractMetaClassCPtr resolveTypeSystemTypeDef(const AbstractMetaType &t) const;
+
+ void fixSmartPointers();
+
+ AbstractMetaBuilder *q = nullptr;
+ AbstractMetaClassList m_metaClasses;
+ AbstractMetaClassList m_templates;
+ AbstractMetaClassList m_smartPointers;
+ QHash<const _CodeModelItem *, AbstractMetaClassPtr > m_itemToClass;
+ QHash<AbstractMetaClassCPtr, const _CodeModelItem *> m_classToItem;
+ AbstractMetaFunctionCList m_globalFunctions;
+ AbstractMetaEnumList m_globalEnums;
+
+ using RejectSet = std::set<RejectEntry>;
+
+ RejectSet m_rejectedClasses;
+ RejectSet m_rejectedEnums;
+ RejectSet m_rejectedFunctions;
+ RejectSet m_rejectedFields;
+
+ QHash<TypeEntryCPtr, AbstractMetaEnum> m_enums;
+
+ QList<NamespaceModelItem> m_scopes;
+
+ QString m_logDirectory;
+ QFileInfoList m_globalHeaders;
+ QStringList m_headerPaths;
+ mutable QHash<QString, Include> m_resolveIncludeHash;
+ QMultiHash<QString, QString> m_typedefTargetToName;
+ QList<TypeClassEntry> m_typeSystemTypeDefs; // look up metatype->class for type system typedefs
+ ApiExtractorFlags m_apiExtractorFlags;
+ bool m_skipDeprecated = false;
+ static bool m_useGlobalHeader;
+ static bool m_codeModelTestMode;
+};
+
+#endif // ABSTRACTMETBUILDER_P_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp b/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp
new file mode 100644
index 000000000..780170c22
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp
@@ -0,0 +1,423 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstractmetaenum.h"
+#include "abstractmetalang.h"
+#include "documentation.h"
+#include "enumtypeentry.h"
+#include "parser/enumvalue.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+class AbstractMetaEnumValueData : public QSharedData
+{
+public:
+ QString m_name;
+ QString m_stringValue;
+ EnumValue m_value;
+ Documentation m_doc;
+ bool m_deprecated = false;
+};
+
+AbstractMetaEnumValue::AbstractMetaEnumValue() :
+ d(new AbstractMetaEnumValueData)
+{
+}
+
+AbstractMetaEnumValue::AbstractMetaEnumValue(const AbstractMetaEnumValue &) = default;
+AbstractMetaEnumValue &AbstractMetaEnumValue::operator=(const AbstractMetaEnumValue &) = default;
+AbstractMetaEnumValue::AbstractMetaEnumValue(AbstractMetaEnumValue &&) noexcept = default;
+AbstractMetaEnumValue &AbstractMetaEnumValue::operator=(AbstractMetaEnumValue &&) noexcept = default;
+AbstractMetaEnumValue::~AbstractMetaEnumValue() = default;
+
+EnumValue AbstractMetaEnumValue::value() const
+{
+ return d->m_value;
+}
+
+void AbstractMetaEnumValue::setValue(EnumValue value)
+{
+ if (d->m_value != value)
+ d->m_value = value;
+}
+
+QString AbstractMetaEnumValue::stringValue() const
+{
+ return d->m_stringValue;
+}
+
+void AbstractMetaEnumValue::setStringValue(const QString &v)
+{
+ if (d->m_stringValue != v)
+ d->m_stringValue = v;
+}
+
+QString AbstractMetaEnumValue::name() const
+{
+ return d->m_name;
+}
+
+void AbstractMetaEnumValue::setName(const QString &name)
+{
+ if (d->m_name != name)
+ d->m_name = name;
+}
+
+bool AbstractMetaEnumValue::isDeprecated() const
+{
+ return d->m_deprecated;
+}
+
+void AbstractMetaEnumValue::setDeprecated(bool deprecated)
+{
+ if (d->m_deprecated != deprecated)
+ d->m_deprecated = deprecated;
+}
+
+Documentation AbstractMetaEnumValue::documentation() const
+{
+ return d->m_doc;
+}
+
+void AbstractMetaEnumValue::setDocumentation(const Documentation &doc)
+{
+ if (d->m_doc != doc)
+ d->m_doc = doc;
+}
+
+// --------------------- AbstractMetaEnum
+
+class AbstractMetaEnumData : public QSharedData
+{
+public:
+ AbstractMetaEnumData() : m_deprecated(false),
+ m_hasQenumsDeclaration(false), m_signed(true)
+ {
+ }
+
+ int unsignedUsedBits() const;
+ int signedUsedBits() const;
+
+ AbstractMetaEnumValueList m_enumValues;
+
+ EnumTypeEntryCPtr m_typeEntry;
+ Documentation m_doc;
+ QString m_underlyingType;
+
+ EnumKind m_enumKind = CEnum;
+ Access m_access = Access::Public;
+ uint m_deprecated : 1;
+ uint m_hasQenumsDeclaration : 1;
+ uint m_signed : 1;
+};
+
+static int _usedBits(uint64_t v)
+{
+ return (v >> 32) ? 64 : (v >> 16) ? 32 : (v >> 8) ? 16 : 8;
+}
+
+static int _usedBits(int64_t v)
+{
+ return (v >> 31) ? 64 : (v >> 15) ? 32 : (v >> 7) ? 16 : 8;
+}
+
+int AbstractMetaEnumData::unsignedUsedBits() const
+{
+ uint64_t maxValue = 0;
+ for (const auto &v : m_enumValues) {
+ if (const auto uv = v.value().unsignedValue(); uv > maxValue)
+ maxValue = uv;
+ }
+ return _usedBits(maxValue);
+}
+
+int AbstractMetaEnumData::signedUsedBits() const
+{
+ int64_t maxValue = 0;
+ for (const auto &v : m_enumValues) {
+ const auto sv = v.value().value();
+ const auto absV = sv < 0 ? ~sv : sv;
+ if (absV > maxValue)
+ maxValue = absV;
+ }
+ return _usedBits(maxValue);
+}
+
+AbstractMetaEnum::AbstractMetaEnum() : d(new AbstractMetaEnumData)
+{
+}
+
+AbstractMetaEnum::AbstractMetaEnum(const AbstractMetaEnum &) = default;
+AbstractMetaEnum &AbstractMetaEnum::operator=(const AbstractMetaEnum&) = default;
+AbstractMetaEnum::AbstractMetaEnum(AbstractMetaEnum &&) noexcept = default;
+AbstractMetaEnum &AbstractMetaEnum::operator=(AbstractMetaEnum &&) noexcept = default;
+AbstractMetaEnum::~AbstractMetaEnum() = default;
+
+const AbstractMetaEnumValueList &AbstractMetaEnum::values() const
+{
+ return d->m_enumValues;
+}
+
+AbstractMetaEnumValueList AbstractMetaEnum::nonRejectedValues() const
+{
+ auto te = d->m_typeEntry;
+ AbstractMetaEnumValueList result = d->m_enumValues;
+ auto pred = [te](const AbstractMetaEnumValue &v) {
+ return te->isEnumValueRejected(v.name()); };
+ result.erase(std::remove_if(result.begin(), result.end(), pred), result.end());
+ return result;
+}
+
+void AbstractMetaEnum::addEnumValue(const AbstractMetaEnumValue &enumValue)
+{
+ d->m_enumValues << enumValue;
+}
+
+std::optional<AbstractMetaEnumValue>
+ findMatchingEnumValue(const AbstractMetaEnumValueList &list, QStringView value)
+{
+ for (const AbstractMetaEnumValue &enumValue : list) {
+ if (enumValue.name() == value)
+ return enumValue;
+ }
+ return {};
+}
+
+// Find enum values for "enum Enum { e1 }" either for "e1" or "Enum::e1"
+std::optional<AbstractMetaEnumValue>
+ AbstractMetaEnum::findEnumValue(QStringView value) const
+{
+ if (isAnonymous())
+ return findMatchingEnumValue(d->m_enumValues, value);
+ const int sepPos = value.indexOf(u"::");
+ if (sepPos == -1)
+ return findMatchingEnumValue(d->m_enumValues, value);
+ if (name() == value.left(sepPos))
+ return findMatchingEnumValue(d->m_enumValues, value.right(value.size() - sepPos - 2));
+ return {};
+}
+
+QString AbstractMetaEnum::name() const
+{
+ return d->m_typeEntry->targetLangEntryName();
+}
+
+QString AbstractMetaEnum::qualifiedCppName() const
+{
+ return enclosingClass()
+ ? enclosingClass()->qualifiedCppName() + u"::"_s + name()
+ : name();
+}
+
+Access AbstractMetaEnum::access() const
+{
+ return d->m_access;
+}
+
+void AbstractMetaEnum::setAccess(Access a)
+{
+ if (a != d->m_access)
+ d->m_access = a;
+}
+
+bool AbstractMetaEnum::isDeprecated() const
+{
+ return d->m_deprecated;
+}
+
+void AbstractMetaEnum::setDeprecated(bool deprecated)
+{
+ if (d->m_deprecated != deprecated)
+ d->m_deprecated = deprecated;
+}
+
+static bool isDeprecatedValue(const AbstractMetaEnumValue &v)
+{
+ return v.isDeprecated();
+};
+
+bool AbstractMetaEnum::hasDeprecatedValues() const
+{
+ return std::any_of(d->m_enumValues.cbegin(), d->m_enumValues.cend(),
+ isDeprecatedValue);
+}
+
+AbstractMetaEnumValueList AbstractMetaEnum::deprecatedValues() const
+{
+ AbstractMetaEnumValueList result;
+ std::copy_if(d->m_enumValues.cbegin(), d->m_enumValues.cend(),
+ std::back_inserter(result), isDeprecatedValue);
+ return result;
+}
+
+const Documentation &AbstractMetaEnum::documentation() const
+{
+ return d->m_doc;
+}
+
+void AbstractMetaEnum::setDocumentation(const Documentation &doc)
+{
+ if (d->m_doc != doc)
+ d->m_doc = doc;
+}
+
+QString AbstractMetaEnum::qualifier() const
+{
+ return d->m_typeEntry->targetLangQualifier();
+}
+
+QString AbstractMetaEnum::package() const
+{
+ return d->m_typeEntry->targetLangPackage();
+}
+
+QString AbstractMetaEnum::fullName() const
+{
+ return package() + u'.' + qualifier() + u'.' + name();
+}
+
+EnumKind AbstractMetaEnum::enumKind() const
+{
+ return d->m_enumKind;
+}
+
+void AbstractMetaEnum::setEnumKind(EnumKind kind)
+{
+ if (d->m_enumKind != kind)
+ d->m_enumKind = kind;
+}
+
+bool AbstractMetaEnum::isAnonymous() const
+{
+ return d->m_enumKind == AnonymousEnum;
+}
+
+bool AbstractMetaEnum::hasQEnumsDeclaration() const
+{
+ return d->m_hasQenumsDeclaration;
+}
+
+void AbstractMetaEnum::setHasQEnumsDeclaration(bool on)
+{
+ if (d->m_hasQenumsDeclaration != on)
+ d->m_hasQenumsDeclaration = on;
+}
+
+EnumTypeEntryCPtr AbstractMetaEnum::typeEntry() const
+{
+ return d->m_typeEntry;
+}
+
+void AbstractMetaEnum::setTypeEntry(const EnumTypeEntryCPtr &entry)
+{
+ if (d->m_typeEntry != entry)
+ d->m_typeEntry = entry;
+}
+
+bool AbstractMetaEnum::isSigned() const
+{
+ return d->m_signed;
+}
+
+void AbstractMetaEnum::setSigned(bool s)
+{
+ if (d->m_signed != s)
+ d->m_signed = s;
+}
+
+QString AbstractMetaEnum::underlyingType() const
+{
+ return d->m_underlyingType;
+}
+
+void AbstractMetaEnum::setUnderlyingType(const QString &underlyingType)
+{
+ if (d->m_underlyingType != underlyingType)
+ d->m_underlyingType = underlyingType;
+}
+
+int AbstractMetaEnum::usedBits() const
+{
+ return isSigned() ? d->signedUsedBits() : d->unsignedUsedBits();
+}
+
+QString AbstractMetaEnum::intTypeForSize(int usedBits, bool isSigned)
+{
+ QString result = u"int"_s + QString::number(usedBits) + u"_t"_s;
+ return isSigned ? result : u'u' + result;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+static void formatMetaEnumValue(QDebug &d, const AbstractMetaEnumValue &v, bool forceHex = false)
+{
+ d << v.name() << '=';
+ if (forceHex)
+ v.value().formatDebugHex(d);
+ else
+ v.value().formatDebug(d);
+ if (v.isDeprecated())
+ d << " (deprecated)";
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaEnumValue &v)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaEnumValue(";
+ formatMetaEnumValue(d, v);
+ d << ')';
+ return d;
+}
+
+static void formatMetaEnum(QDebug &d, const AbstractMetaEnum &e)
+{
+ d << '"' << e.fullName() << '"';
+ if (e.isDeprecated())
+ d << " (deprecated)";
+ d << " \"" << e.underlyingType() << '"';
+ if (!e.isSigned())
+ d << " (unsigned)";
+ d << " [";
+ const AbstractMetaEnumValueList &values = e.values();
+ const bool hasFlags = e.typeEntry()->flags() != nullptr;
+ for (qsizetype i = 0, count = values.size(); i < count; ++i) {
+ if (i)
+ d << ", ";
+ formatMetaEnumValue(d, values.at(i), hasFlags);
+ }
+ d << ']';
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaEnum *ae)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaEnum(";
+ if (ae)
+ formatMetaEnum(d, *ae);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaEnum &ae)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaEnum(";
+ formatMetaEnum(d, ae);
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/abstractmetaenum.h b/sources/shiboken6/ApiExtractor/abstractmetaenum.h
new file mode 100644
index 000000000..03d7a3082
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetaenum.h
@@ -0,0 +1,125 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETAENUM_H
+#define ABSTRACTMETAENUM_H
+
+#include "abstractmetalang_typedefs.h"
+#include "enclosingclassmixin.h"
+#include "parser/codemodel_enums.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QString>
+
+#include <optional>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class AbstractMetaEnumData;
+class AbstractMetaEnumValueData;
+class Documentation;
+class EnumValue;
+class EnumTypeEntry;
+
+class AbstractMetaEnumValue
+{
+public:
+ AbstractMetaEnumValue();
+ AbstractMetaEnumValue(const AbstractMetaEnumValue &);
+ AbstractMetaEnumValue &operator=(const AbstractMetaEnumValue &);
+ AbstractMetaEnumValue(AbstractMetaEnumValue &&) noexcept;
+ AbstractMetaEnumValue &operator=(AbstractMetaEnumValue &&) noexcept;
+ ~AbstractMetaEnumValue();
+
+ EnumValue value() const;
+ void setValue(EnumValue value);
+
+ QString stringValue() const;
+ void setStringValue(const QString &v);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ bool isDeprecated() const;
+ void setDeprecated(bool deprecated);
+
+ Documentation documentation() const;
+ void setDocumentation(const Documentation& doc);
+
+ int usedBits() const;
+
+private:
+ QSharedDataPointer<AbstractMetaEnumValueData> d;
+};
+
+class AbstractMetaEnum : public EnclosingClassMixin
+{
+public:
+ AbstractMetaEnum();
+ AbstractMetaEnum(const AbstractMetaEnum &);
+ AbstractMetaEnum &operator=(const AbstractMetaEnum &);
+ AbstractMetaEnum(AbstractMetaEnum &&) noexcept;
+ AbstractMetaEnum &operator=(AbstractMetaEnum &&) noexcept;
+ ~AbstractMetaEnum();
+
+ const AbstractMetaEnumValueList &values() const;
+ AbstractMetaEnumValueList nonRejectedValues() const;
+ void addEnumValue(const AbstractMetaEnumValue &enumValue);
+
+ std::optional<AbstractMetaEnumValue> findEnumValue(QStringView value) const;
+
+ QString name() const;
+ QString qualifiedCppName() const;
+
+ Access access() const;
+ void setAccess(Access a);
+ bool isPrivate() const { return access() == Access::Private; }
+ bool isProtected() const { return access() == Access::Protected; }
+
+ bool isDeprecated() const;
+ void setDeprecated(bool deprecated);
+ bool hasDeprecatedValues() const;
+ AbstractMetaEnumValueList deprecatedValues() const;
+
+ const Documentation &documentation() const;
+ void setDocumentation(const Documentation& doc);
+
+ QString qualifier() const;
+
+ QString package() const;
+
+ QString fullName() const;
+
+ EnumKind enumKind() const;
+ void setEnumKind(EnumKind kind);
+
+ bool isAnonymous() const;
+
+ // Has the enum been declared inside a Q_ENUMS() macro in its enclosing class?
+ bool hasQEnumsDeclaration() const;
+ void setHasQEnumsDeclaration(bool on);
+
+ EnumTypeEntryCPtr typeEntry() const;
+ void setTypeEntry(const EnumTypeEntryCPtr &entry);
+
+ bool isSigned() const;
+ void setSigned(bool s);
+
+ QString underlyingType() const;
+ void setUnderlyingType(const QString &underlyingType);
+
+ static QString intTypeForSize(int usedBits, bool isSigned);
+ int usedBits() const;
+
+private:
+ QSharedDataPointer<AbstractMetaEnumData> d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaEnumValue &ae);
+QDebug operator<<(QDebug d, const AbstractMetaEnum *ae);
+QDebug operator<<(QDebug d, const AbstractMetaEnum &ae);
+#endif
+
+#endif // ABSTRACTMETAENUM_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetafield.cpp b/sources/shiboken6/ApiExtractor/abstractmetafield.cpp
new file mode 100644
index 000000000..27a76d04d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetafield.cpp
@@ -0,0 +1,254 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstractmetafield.h"
+#include "abstractmetabuilder.h"
+#include "abstractmetalang.h"
+#include "abstractmetatype.h"
+#include "documentation.h"
+#include "modifications.h"
+#include "complextypeentry.h"
+#include "typesystemtypeentry.h"
+#include "parser/codemodel.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+class AbstractMetaFieldData : public QSharedData
+{
+public:
+ QString m_originalName;
+ QString m_name;
+ AbstractMetaType m_type;
+ Documentation m_doc;
+ bool m_setterEnabled = true; // Modifications
+ bool m_getterEnabled = true; // Modifications
+ bool m_static = false;
+ Access m_access = Access::Public;
+};
+
+AbstractMetaField::AbstractMetaField() : d(new AbstractMetaFieldData)
+{
+}
+
+AbstractMetaField::AbstractMetaField(const AbstractMetaField &) = default;
+AbstractMetaField &AbstractMetaField::operator=(const AbstractMetaField &) = default;
+AbstractMetaField::AbstractMetaField(AbstractMetaField &&) noexcept = default;
+AbstractMetaField &AbstractMetaField::operator=(AbstractMetaField &&) noexcept = default;
+AbstractMetaField::~AbstractMetaField() = default;
+
+// returned->setEnclosingClass(nullptr);
+
+std::optional<AbstractMetaField>
+ AbstractMetaField::find(const AbstractMetaFieldList &haystack,
+ QStringView needle)
+{
+ for (const auto &f : haystack) {
+ if (f.name() == needle)
+ return f;
+ }
+ return {};
+}
+
+/*******************************************************************************
+ * Indicates that this field has a modification that removes it
+ */
+bool AbstractMetaField::isModifiedRemoved() const
+{
+ const FieldModificationList &mods = modifications();
+ for (const FieldModification &mod : mods) {
+ if (mod.isRemoved())
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaField::generateOpaqueContainer() const
+{
+ const FieldModificationList &mods = modifications();
+ for (const FieldModification &mod : mods) {
+ if (mod.isOpaqueContainer())
+ return true;
+ }
+ return false;
+}
+
+const AbstractMetaType &AbstractMetaField::type() const
+{
+ return d->m_type;
+}
+
+void AbstractMetaField::setType(const AbstractMetaType &type)
+{
+ if (d->m_type != type)
+ d->m_type = type;
+}
+
+QString AbstractMetaField::name() const
+{
+ return d->m_name;
+}
+
+void AbstractMetaField::setName(const QString &name)
+{
+ if (d->m_name != name)
+ d->m_name = name;
+}
+
+Access AbstractMetaField::access() const
+{
+ return d->m_access;
+}
+
+void AbstractMetaField::setAccess(Access a)
+{
+ if (a != d->m_access)
+ d->m_access = a;
+}
+
+bool AbstractMetaField::isStatic() const
+{
+ return d->m_static;
+}
+
+void AbstractMetaField::setStatic(bool s)
+{
+ if (s != d->m_static)
+ d->m_static = s;
+}
+
+QString AbstractMetaField::qualifiedCppName() const
+{
+ return enclosingClass()->qualifiedCppName() + u"::"_s
+ + originalName();
+}
+
+QStringList AbstractMetaField::definitionNames() const
+{
+ return AbstractMetaBuilder::definitionNames(d->m_name, snakeCase());
+}
+
+QString AbstractMetaField::originalName() const
+{
+ return d->m_originalName.isEmpty() ? d->m_name : d->m_originalName;
+}
+
+void AbstractMetaField::setOriginalName(const QString &name)
+{
+ if (d->m_originalName != name)
+ d->m_originalName = name;
+}
+
+const Documentation &AbstractMetaField::documentation() const
+{
+ return d->m_doc;
+}
+
+void AbstractMetaField::setDocumentation(const Documentation &doc)
+{
+ if (d->m_doc != doc)
+ d->m_doc = doc;
+}
+
+bool AbstractMetaField::isGetterEnabled() const
+{
+ return d->m_getterEnabled;
+}
+
+void AbstractMetaField::setGetterEnabled(bool e)
+{
+ if (d->m_getterEnabled != e)
+ d->m_getterEnabled = e;
+}
+
+bool AbstractMetaField::isSetterEnabled() const
+{
+ return d->m_setterEnabled;
+}
+
+void AbstractMetaField::setSetterEnabled(bool e)
+{
+ if (e != d->m_setterEnabled)
+ d->m_setterEnabled = e;
+}
+
+bool AbstractMetaField::canGenerateGetter() const
+{
+ return d->m_getterEnabled && !isStatic() && !d->m_type.isArray();
+}
+
+bool AbstractMetaField::canGenerateSetter() const
+{
+ return d->m_setterEnabled && !isStatic()
+ && !d->m_type.isArray()
+ && (!d->m_type.isConstant() || d->m_type.isPointerToConst());
+}
+
+TypeSystem::SnakeCase AbstractMetaField::snakeCase() const
+{
+ // Renamed?
+ if (!d->m_originalName.isEmpty() && d->m_originalName != d->m_name)
+ return TypeSystem::SnakeCase::Disabled;
+
+ for (const auto &mod : modifications()) {
+ if (mod.snakeCase() != TypeSystem::SnakeCase::Unspecified)
+ return mod.snakeCase();
+ }
+
+ auto typeEntry = enclosingClass()->typeEntry();
+ const auto snakeCase = typeEntry->snakeCase();
+ return snakeCase != TypeSystem::SnakeCase::Unspecified
+ ? snakeCase : typeSystemTypeEntry(typeEntry)->snakeCase();
+}
+
+FieldModificationList AbstractMetaField::modifications() const
+{
+ const FieldModificationList &mods = enclosingClass()->typeEntry()->fieldModifications();
+ FieldModificationList returned;
+
+ for (const FieldModification &mod : mods) {
+ if (mod.name() == name())
+ returned += mod;
+ }
+
+ return returned;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void AbstractMetaField::formatDebug(QDebug &d) const
+{
+ if (isStatic())
+ d << "static ";
+ d << access() << ' ' << type().name() << " \"" << name() << '"';
+
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaField *af)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaField(";
+ if (af)
+ af->formatDebug(d);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaField &af)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaField(";
+ af.formatDebug(d);
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/abstractmetafield.h b/sources/shiboken6/ApiExtractor/abstractmetafield.h
new file mode 100644
index 000000000..0fa858791
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetafield.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETAFIELD_H
+#define ABSTRACTMETAFIELD_H
+
+#include "abstractmetalang_typedefs.h"
+#include "parser/codemodel_enums.h"
+#include "typesystem_enums.h"
+#include "modifications_typedefs.h"
+#include "typesystem_typedefs.h"
+#include "enclosingclassmixin.h"
+
+#include <QtCore/QSharedDataPointer>
+
+#include <optional>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class Documentation;
+class AbstractMetaFieldData;
+
+class AbstractMetaField : public EnclosingClassMixin
+{
+public:
+ AbstractMetaField();
+ AbstractMetaField(const AbstractMetaField &);
+ AbstractMetaField &operator=(const AbstractMetaField &);
+ AbstractMetaField(AbstractMetaField &&) noexcept;
+ AbstractMetaField &operator=(AbstractMetaField &&) noexcept;
+ ~AbstractMetaField();
+
+ FieldModificationList modifications() const;
+
+ bool isModifiedRemoved() const;
+ bool generateOpaqueContainer() const;
+
+ const AbstractMetaType &type() const;
+ void setType(const AbstractMetaType &type);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ Access access() const;
+ void setAccess(Access a);
+ bool isPrivate() const { return access() == Access::Private; }
+ bool isProtected() const { return access() == Access::Protected; }
+
+ bool isStatic() const;
+ void setStatic(bool s);
+
+ QString qualifiedCppName() const;
+
+ // Names under which the field will be registered to Python.
+ QStringList definitionNames() const;
+
+ QString originalName() const;
+ void setOriginalName(const QString& name);
+
+ const Documentation &documentation() const;
+ void setDocumentation(const Documentation& doc);
+
+ bool isGetterEnabled() const; // Modifications
+ void setGetterEnabled(bool e);
+ bool isSetterEnabled() const; // Modifications
+ void setSetterEnabled(bool e);
+
+ bool canGenerateGetter() const;
+ bool canGenerateSetter() const;
+
+ TypeSystem::SnakeCase snakeCase() const;
+
+ static std::optional<AbstractMetaField>
+ find(const AbstractMetaFieldList &haystack, QStringView needle);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+private:
+ QSharedDataPointer<AbstractMetaFieldData> d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaField *af);
+QDebug operator<<(QDebug d, const AbstractMetaField &af);
+#endif
+
+#endif // ABSTRACTMETAFIELD_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
new file mode 100644
index 000000000..11a02f154
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
@@ -0,0 +1,1707 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstractmetafunction.h"
+#include "abstractmetaargument.h"
+#include "abstractmetabuilder.h"
+#include "abstractmetalang.h"
+#include "abstractmetalang_helpers.h"
+#include "abstractmetatype.h"
+#include "addedfunction.h"
+#include <codemodel.h>
+#include "documentation.h"
+#include "exception.h"
+#include "messages.h"
+#include "codesnip.h"
+#include "modifications.h"
+#include "reporthandler.h"
+#include "sourcelocation.h"
+#include "typedatabase.h"
+#include "complextypeentry.h"
+#include "containertypeentry.h"
+#include "functiontypeentry.h"
+#include "primitivetypeentry.h"
+#include "typesystemtypeentry.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QRegularExpression>
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+// Cache FunctionModificationList in a flat list per class (0 for global
+// functions, or typically owner/implementing/declaring class.
+struct ModificationCacheEntry
+{
+ AbstractMetaClassCPtr klass;
+ FunctionModificationList modifications;
+};
+
+using ModificationCache = QList<ModificationCacheEntry>;
+
+class AbstractMetaFunctionPrivate
+{
+public:
+ AbstractMetaFunctionPrivate()
+ : m_constant(false),
+ m_reverse(false),
+ m_pointerOperator(false),
+ m_isCallOperator(false)
+ {
+ }
+
+ QString signature() const;
+ QString formatMinimalSignature(const AbstractMetaFunction *q,
+ bool comment) const;
+ QString modifiedName(const AbstractMetaFunction *q) const;
+ int overloadNumber(const AbstractMetaFunction *q) const;
+
+ const FunctionModificationList &modifications(const AbstractMetaFunction *q,
+ const AbstractMetaClassCPtr &implementor) const;
+
+ bool applyTypeModification(const AbstractMetaFunction *q,
+ const QString &type, int number, QString *errorMessage);
+
+ QString m_name;
+ QString m_originalName;
+ Documentation m_doc;
+ mutable QString m_cachedMinimalSignature;
+ mutable QString m_cachedSignature;
+ mutable QString m_cachedModifiedName;
+ QString m_unresolvedSignature;
+
+ FunctionTypeEntryPtr m_typeEntry;
+ AbstractMetaFunction::FunctionType m_functionType = AbstractMetaFunction::NormalFunction;
+ AbstractMetaType m_type;
+ QString m_modifiedTypeName;
+ AbstractMetaClassCPtr m_class;
+ AbstractMetaClassCPtr m_implementingClass;
+ AbstractMetaClassCPtr m_declaringClass;
+ mutable ModificationCache m_modificationCache;
+ int m_propertySpecIndex = -1;
+ AbstractMetaArgumentList m_arguments;
+ AddedFunctionPtr m_addedFunction;
+ SourceLocation m_sourceLocation;
+ AbstractMetaFunction::Attributes m_attributes;
+ FunctionAttributes m_cppAttributes;
+ AbstractMetaFunction::Flags m_flags;
+ uint m_constant : 1;
+ uint m_reverse : 1;
+ uint m_pointerOperator : 1;
+ uint m_isCallOperator : 1;
+ mutable int m_cachedOverloadNumber = TypeSystem::OverloadNumberUnset;
+ Access m_access = Access::Public;
+ Access m_originalAccess = Access::Public;
+ ExceptionSpecification m_exceptionSpecification = ExceptionSpecification::Unknown;
+ TypeSystem::AllowThread m_allowThreadModification = TypeSystem::AllowThread::Unspecified;
+ TypeSystem::ExceptionHandling m_exceptionHandlingModification = TypeSystem::ExceptionHandling::Unspecified;
+};
+
+AbstractMetaFunction::AbstractMetaFunction(const QString &name) :
+ AbstractMetaFunction()
+{
+ d->m_originalName = d->m_name = name;
+}
+
+AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) :
+ AbstractMetaFunction(addedFunc->name())
+{
+ d->m_addedFunction = addedFunc;
+ setConstant(addedFunc->isConstant());
+ switch (addedFunc->access()) {
+ case AddedFunction::Protected:
+ setAccess(Access::Protected);
+ break;
+ case AddedFunction::Public:
+ setAccess(Access::Public);
+ break;
+ }
+ AbstractMetaFunction::Attributes atts;
+ if (addedFunc->isStatic())
+ setCppAttribute(FunctionAttribute::Static);
+ if (addedFunc->isClassMethod())
+ atts |= AbstractMetaFunction::ClassMethod;
+ setAttributes(atts);
+}
+
+QString AbstractMetaFunction::name() const
+{
+ return d->m_name;
+}
+
+void AbstractMetaFunction::setName(const QString &name)
+{
+ d->m_name = name;
+}
+
+QString AbstractMetaFunction::originalName() const
+{
+ return d->m_originalName.isEmpty() ? name() : d->m_originalName;
+}
+
+void AbstractMetaFunction::setOriginalName(const QString &name)
+{
+ d->m_originalName = name;
+}
+
+Access AbstractMetaFunction::access() const
+{
+ return d->m_access;
+}
+
+void AbstractMetaFunction::setAccess(Access a)
+{
+ d->m_originalAccess = d->m_access = a;
+}
+
+void AbstractMetaFunction::modifyAccess(Access a)
+{
+ d->m_access = a;
+}
+
+bool AbstractMetaFunction::wasPrivate() const
+{
+ return d->m_originalAccess == Access::Private;
+}
+
+bool AbstractMetaFunction::wasProtected() const
+{
+ return d->m_originalAccess == Access::Protected;
+}
+
+bool AbstractMetaFunction::wasPublic() const
+{
+ return d->m_originalAccess == Access::Public;
+}
+
+QStringList AbstractMetaFunction::definitionNames() const
+{
+ return AbstractMetaBuilder::definitionNames(d->m_name, snakeCase());
+}
+
+const Documentation &AbstractMetaFunction::documentation() const
+{
+ return d->m_doc;
+}
+
+void AbstractMetaFunction::setDocumentation(const Documentation &doc)
+{
+ d->m_doc = doc;
+}
+
+bool AbstractMetaFunction::isReverseOperator() const
+{
+ return d->m_reverse;
+}
+
+void AbstractMetaFunction::setReverseOperator(bool reverse)
+{
+ d->m_reverse = reverse;
+}
+
+bool AbstractMetaFunction::isPointerOperator() const
+{
+ return d->m_pointerOperator;
+}
+
+void AbstractMetaFunction::setPointerOperator(bool value)
+{
+ d->m_pointerOperator = value;
+}
+
+bool AbstractMetaFunction::isExplicit() const
+{
+ return d->m_cppAttributes.testFlag(FunctionAttribute::Explicit);
+}
+
+void AbstractMetaFunction::setExplicit(bool isExplicit)
+{
+ d->m_cppAttributes.setFlag(FunctionAttribute::Explicit, isExplicit);
+}
+
+bool AbstractMetaFunction::returnsBool() const
+{
+ if (d->m_type.typeUsagePattern() != AbstractMetaType::PrimitivePattern)
+ return false;
+ return basicReferencedTypeEntry(d->m_type.typeEntry())->name() == u"bool";
+}
+
+bool AbstractMetaFunction::isOperatorBool() const
+{
+ return d->m_functionType == AbstractMetaFunction::ConversionOperator
+ && d->m_constant && returnsBool();
+}
+
+AbstractMetaFunction::AbstractMetaFunction() : d(new AbstractMetaFunctionPrivate)
+{
+}
+
+AbstractMetaFunction::~AbstractMetaFunction() = default;
+
+AbstractMetaFunction::Attributes AbstractMetaFunction::attributes() const
+{
+ return d->m_attributes;
+}
+
+void AbstractMetaFunction::setAttributes(Attributes attributes)
+{
+ d->m_attributes = attributes;
+}
+
+void AbstractMetaFunction::operator+=(AbstractMetaFunction::Attribute attribute)
+{
+ d->m_attributes.setFlag(attribute);
+}
+
+void AbstractMetaFunction::operator-=(AbstractMetaFunction::Attribute attribute)
+{
+ d->m_attributes.setFlag(attribute, false);
+}
+
+FunctionAttributes AbstractMetaFunction::cppAttributes() const
+{
+ return d->m_cppAttributes;
+}
+
+void AbstractMetaFunction::setCppAttributes(FunctionAttributes a)
+{
+ d->m_cppAttributes = a;
+}
+
+void AbstractMetaFunction::setCppAttribute(FunctionAttribute a, bool on)
+{
+ d->m_cppAttributes.setFlag(a, on);
+}
+
+AbstractMetaFunction::Flags AbstractMetaFunction::flags() const
+{
+ return d->m_flags;
+}
+
+void AbstractMetaFunction::setFlags(Flags f)
+{
+ d->m_flags = f;
+}
+
+/*******************************************************************************
+ * Indicates that this function has a modification that removes it
+ */
+bool AbstractMetaFunction::isModifiedRemoved(AbstractMetaClassCPtr cls) const
+{
+ if (!isInGlobalScope() && !cls)
+ cls = d->m_implementingClass;
+ for (const auto &mod : modifications(cls)) {
+ if (mod.isRemoved())
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::isModifiedFinal(AbstractMetaClassCPtr cls) const
+{
+ if (!isInGlobalScope() && cls == nullptr)
+ cls = d->m_implementingClass;
+ for (const auto &mod : modifications(cls)) {
+ if (mod.modifiers().testFlag(FunctionModification::Final))
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::isVoid() const
+{
+ return d->m_type.isVoid();
+}
+
+const AbstractMetaType &AbstractMetaFunction::type() const
+{
+ return d->m_type;
+}
+
+void AbstractMetaFunction::setType(const AbstractMetaType &type)
+{
+ d->m_type = type;
+}
+
+AbstractMetaClassCPtr AbstractMetaFunction::ownerClass() const
+{
+ return d->m_class;
+}
+
+void AbstractMetaFunction::setOwnerClass(const AbstractMetaClassCPtr &cls)
+{
+ d->m_class = cls;
+}
+
+bool AbstractMetaFunction::operator<(const AbstractMetaFunction &other) const
+{
+ return compareTo(&other) & NameLessThan;
+}
+
+
+/*!
+ Returns a mask of CompareResult describing how this function is
+ compares to another function
+*/
+AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const AbstractMetaFunction *other) const
+{
+ CompareResult result;
+
+ // Enclosing class...
+ if (ownerClass() == other->ownerClass())
+ result |= EqualImplementor;
+
+ // Attributes
+ if (attributes() == other->attributes() && cppAttributes() == other->cppAttributes())
+ result |= EqualAttributes;
+
+ // Compare types
+ if (type().name() == other->type().name())
+ result |= EqualReturnType;
+
+ // Compare names
+ int cmp = originalName().compare(other->originalName());
+
+ if (cmp < 0)
+ result |= NameLessThan;
+ else if (!cmp)
+ result |= EqualName;
+
+ // compare name after modification...
+ cmp = modifiedName().compare(other->modifiedName());
+ if (!cmp)
+ result |= EqualModifiedName;
+
+ // Compare arguments...
+ AbstractMetaArgumentList minArguments;
+ AbstractMetaArgumentList maxArguments;
+ if (arguments().size() < other->arguments().size()) {
+ minArguments = arguments();
+ maxArguments = other->arguments();
+ } else {
+ minArguments = other->arguments();
+ maxArguments = arguments();
+ }
+
+ const auto minCount = minArguments.size();
+ const auto maxCount = maxArguments.size();
+ bool same = true;
+ for (qsizetype i = 0; i < maxCount; ++i) {
+ if (i < minCount) {
+ const AbstractMetaArgument &min_arg = minArguments.at(i);
+ const AbstractMetaArgument &max_arg = maxArguments.at(i);
+ if (min_arg.type().name() != max_arg.type().name()
+ && (min_arg.defaultValueExpression().isEmpty() || max_arg.defaultValueExpression().isEmpty())) {
+ same = false;
+ break;
+ }
+ } else {
+ if (maxArguments.at(i).defaultValueExpression().isEmpty()) {
+ same = false;
+ break;
+ }
+ }
+ }
+
+ if (same)
+ result |= minCount == maxCount ? EqualArguments : EqualDefaultValueOverload;
+
+ return result;
+}
+
+// Is this the const overload of another function of equivalent return type?
+bool AbstractMetaFunction::isConstOverloadOf(const AbstractMetaFunction *other) const
+{
+ const auto argumentCount = d->m_arguments.size();
+ if (!isConstant() || other->isConstant() || name() != other->name()
+ || argumentCount != other->arguments().size()) {
+ return false;
+ }
+
+ // Match "const Foo &getFoo() const" / "Foo &getFoo()" / "Foo getFoo() const"
+ const auto otherType = other->type();
+ if (d->m_type.name() != otherType.name()
+ || d->m_type.indirectionsV() != otherType.indirectionsV()) {
+ return false;
+ }
+
+ const auto &otherArguments = other->arguments();
+ for (qsizetype a = 0; a < argumentCount; ++a) {
+ if (d->m_arguments.at(a).type() != otherArguments.at(a).type())
+ return false;
+ }
+ return true;
+}
+
+AbstractMetaFunction *AbstractMetaFunction::copy() const
+{
+ auto *cpy = new AbstractMetaFunction;
+ cpy->setAttributes(attributes());
+ auto ca = cppAttributes();
+ // Historical bug: explicit was not copied! (causing nontypetemplate_test.py fail)
+ ca.setFlag(FunctionAttribute::Explicit, false);
+ cpy->setCppAttributes(ca);
+ cpy->setFlags(flags());
+ cpy->setAccess(access());
+ cpy->setName(name());
+ cpy->setOriginalName(originalName());
+ cpy->setOwnerClass(ownerClass());
+ cpy->setImplementingClass(implementingClass());
+ cpy->setFunctionType(functionType());
+ cpy->setDeclaringClass(declaringClass());
+ cpy->setType(type());
+ cpy->setConstant(isConstant());
+ cpy->setExceptionSpecification(d->m_exceptionSpecification);
+ cpy->setAllowThreadModification(d->m_allowThreadModification);
+ cpy->setExceptionHandlingModification(d->m_exceptionHandlingModification);
+ cpy->d->m_modifiedTypeName = d->m_modifiedTypeName;
+ cpy->d->m_addedFunction = d->m_addedFunction;
+ cpy->d->m_arguments = d->m_arguments;
+
+ return cpy;
+}
+
+bool AbstractMetaFunction::usesRValueReferences() const
+{
+ if (d->m_functionType == MoveConstructorFunction || d->m_functionType == MoveAssignmentOperatorFunction)
+ return true;
+ if (d->m_type.referenceType() == RValueReference)
+ return true;
+ for (const AbstractMetaArgument &a : d->m_arguments) {
+ if (a.type().referenceType() == RValueReference)
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::generateBinding() const
+{
+ switch (d->m_functionType) {
+ case ConversionOperator:
+ if (d->m_name != u"operator int" && d->m_name != u"operator double")
+ return false;
+ break;
+ case AssignmentOperatorFunction:
+ case MoveAssignmentOperatorFunction:
+ case AbstractMetaFunction::MoveConstructorFunction:
+ return false;
+ default:
+ if (!isWhiteListed())
+ return false;
+ break;
+ }
+ // Can we access the wrapper in case of a protected method? If not,
+ // disable for consistency regardless of avoidProtectedHack.
+ if (isProtected()) {
+ const auto typeFlags = ownerClass()->typeEntry()->typeFlags();
+ if (typeFlags.testFlag(ComplexTypeEntry::DisableWrapper))
+ return false;
+ }
+ if (isPrivate() && d->m_functionType != EmptyFunction)
+ return false;
+ // RValue references only for user-specified
+ // functions (<add-function>/<declare-function>/<function>)
+ return d->m_name != u"qt_metacall" &&
+ (!usesRValueReferences() || d->m_addedFunction || d->m_typeEntry)
+ && !isModifiedRemoved();
+}
+
+bool AbstractMetaFunction::isWhiteListed() const
+{
+ switch (d->m_functionType) {
+ case NormalFunction:
+ case SignalFunction:
+ case SlotFunction:
+ if (auto dc = declaringClass()) {
+ const QSet<QString> &whiteList = dc->typeEntry()->generateFunctions();
+ return whiteList.isEmpty() || whiteList.contains(d->m_name)
+ || whiteList.contains(minimalSignature());
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+QString AbstractMetaFunctionPrivate::signature() const
+{
+ if (m_cachedSignature.isEmpty()) {
+ m_cachedSignature = m_originalName;
+
+ m_cachedSignature += u'(';
+
+ for (qsizetype i = 0; i < m_arguments.size(); ++i) {
+ const AbstractMetaArgument &a = m_arguments.at(i);
+ const AbstractMetaType &t = a.type();
+ if (i > 0)
+ m_cachedSignature += u", "_s;
+ m_cachedSignature += t.cppSignature();
+ // We need to have the argument names in the qdoc files
+ m_cachedSignature += u' ';
+ m_cachedSignature += a.name();
+ }
+ m_cachedSignature += u')';
+
+ if (m_constant)
+ m_cachedSignature += u" const"_s;
+ }
+ return m_cachedSignature;
+}
+
+QString AbstractMetaFunction::signature() const
+{
+ return d->signature();
+}
+
+QString AbstractMetaFunction::classQualifiedSignature() const
+{
+ QString result;
+ if (d->m_implementingClass)
+ result += d->m_implementingClass->qualifiedCppName() + u"::"_s;
+ result += signature();
+ return result;
+}
+
+QString AbstractMetaFunction::unresolvedSignature() const
+{
+ return d->m_unresolvedSignature;
+}
+
+void AbstractMetaFunction::setUnresolvedSignature(const QString &s)
+{
+ d->m_unresolvedSignature = s;
+}
+
+bool AbstractMetaFunction::isConstant() const
+{
+ return d->m_constant;
+}
+
+void AbstractMetaFunction::setConstant(bool constant)
+{
+ d->m_constant = constant;
+}
+
+bool AbstractMetaFunction::isUserAdded() const
+{
+ return d->m_addedFunction && !d->m_addedFunction->isDeclaration();
+}
+
+bool AbstractMetaFunction::isUserAddedPythonOverride() const
+{
+ return d->m_addedFunction && d->m_addedFunction->isPythonOverride();
+}
+
+bool AbstractMetaFunction::isUserDeclared() const
+{
+ return d->m_addedFunction && d->m_addedFunction->isDeclaration();
+}
+
+int AbstractMetaFunction::actualMinimumArgumentCount() const
+{
+ int count = 0;
+ for (qsizetype i = 0, size = d->m_arguments.size(); i < size; ++i && ++count) {
+ const auto &arg = d->m_arguments.at(i);
+ if (arg.isModifiedRemoved())
+ --count;
+ else if (!arg.defaultValueExpression().isEmpty())
+ break;
+ }
+
+ return count;
+}
+
+int AbstractMetaFunction::actualArgumentIndex(int index) const
+{
+ if (index < 0 || index >= int(d->m_arguments.size()))
+ throw Exception(msgArgumentIndexOutOfRange(this, index));
+ int result = 0;
+ for (int i = 0; i < index; ++i) {
+ if (!d->m_arguments.at(i).isModifiedRemoved())
+ ++result;
+ }
+ return result;
+}
+
+// Returns reference counts for argument at idx, or all arguments if idx == -2
+QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClassCPtr &cls, int idx) const
+{
+ QList<ReferenceCount> returned;
+
+ for (const auto &mod : modifications(cls)) {
+ for (const ArgumentModification &argumentMod : mod.argument_mods()) {
+ if (argumentMod.index() != idx && idx != -2)
+ continue;
+ returned += argumentMod.referenceCounts();
+ }
+ }
+
+ return returned;
+}
+
+ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClassCPtr &cls, int idx) const
+{
+ for (const auto &mod : modifications(cls)) {
+ for (const ArgumentModification &argumentMod : mod.argument_mods()) {
+ if (argumentMod.index() != idx)
+ continue;
+ return argumentMod.owner();
+ }
+ }
+ return ArgumentOwner();
+}
+
+QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int key) const
+{
+ for (const auto &modification : modifications(declaringClass())) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods()) {
+ if (argumentModification.index() != key)
+ continue;
+
+ for (const CodeSnip &snip : argumentModification.conversionRules()) {
+ if (snip.language == language && !snip.code().isEmpty())
+ return snip.code();
+ }
+ }
+ }
+
+ return QString();
+}
+
+bool AbstractMetaFunction::hasConversionRule(TypeSystem::Language language, int idx) const
+{
+ return !conversionRule(language, idx).isEmpty();
+}
+
+// FIXME If we remove a arg. in the method at the base class, it will not reflect here.
+bool AbstractMetaFunction::argumentRemoved(int key) const
+{
+ for (const auto &modification : modifications(declaringClass())) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods()) {
+ if (argumentModification.index() == key) {
+ if (argumentModification.isRemoved())
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+AbstractMetaClassCPtr AbstractMetaFunction::targetLangOwner() const
+{
+ return d->m_class && d->m_class->isInvisibleNamespace()
+ ? d->m_class->targetLangEnclosingClass() : d->m_class;
+}
+
+AbstractMetaClassCPtr AbstractMetaFunction::declaringClass() const
+{
+ return d->m_declaringClass;
+}
+
+void AbstractMetaFunction::setDeclaringClass(const AbstractMetaClassCPtr &cls)
+{
+ d->m_declaringClass = cls;
+}
+
+AbstractMetaClassCPtr AbstractMetaFunction::implementingClass() const
+{
+ return d->m_implementingClass;
+}
+
+void AbstractMetaFunction::setImplementingClass(const AbstractMetaClassCPtr &cls)
+{
+ d->m_implementingClass = cls;
+}
+
+const AbstractMetaArgumentList &AbstractMetaFunction::arguments() const
+{
+ return d->m_arguments;
+}
+
+AbstractMetaArgumentList &AbstractMetaFunction::arguments()
+{
+ return d->m_arguments;
+}
+
+void AbstractMetaFunction::setArguments(const AbstractMetaArgumentList &arguments)
+{
+ d->m_arguments = arguments;
+}
+
+void AbstractMetaFunction::addArgument(const AbstractMetaArgument &argument)
+{
+ d->m_arguments << argument;
+}
+
+static bool modifiedDeprecated(const FunctionModification &mod)
+{
+ return mod.modifiers().testFlag(FunctionModification::Deprecated);
+}
+
+static bool modifiedUndeprecated(const FunctionModification &mod)
+{
+ return mod.modifiers().testFlag(FunctionModification::Undeprecated);
+}
+
+bool AbstractMetaFunction::isDeprecated() const
+{
+ const auto &mods = modifications(declaringClass());
+
+ return d->m_cppAttributes.testFlag(FunctionAttribute::Deprecated)
+ ? std::none_of(mods.cbegin(), mods.cend(), modifiedUndeprecated)
+ : std::any_of(mods.cbegin(), mods.cend(), modifiedDeprecated);
+}
+
+bool AbstractMetaFunction::isConstructor() const
+{
+ return d->m_functionType == ConstructorFunction || d->m_functionType == CopyConstructorFunction
+ || d->m_functionType == MoveConstructorFunction;
+}
+
+bool AbstractMetaFunction::isDefaultConstructor() const
+{
+ return d->m_functionType == ConstructorFunction
+ && (d->m_arguments.isEmpty()
+ || d->m_arguments.constFirst().hasDefaultValueExpression());
+}
+
+bool AbstractMetaFunction::needsReturnType() const
+{
+ switch (d->m_functionType) {
+ case AbstractMetaFunction::ConstructorFunction:
+ case AbstractMetaFunction::CopyConstructorFunction:
+ case AbstractMetaFunction::MoveConstructorFunction:
+ case AbstractMetaFunction::DestructorFunction:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool AbstractMetaFunction::isInGlobalScope() const
+{
+ return d->m_class == nullptr;
+}
+
+AbstractMetaFunction::FunctionType AbstractMetaFunction::functionType() const
+{
+ return d->m_functionType;
+}
+
+void AbstractMetaFunction::setFunctionType(AbstractMetaFunction::FunctionType type)
+{
+ d->m_functionType = type;
+}
+
+std::optional<AbstractMetaFunction::ComparisonOperatorType>
+AbstractMetaFunction::comparisonOperatorType() const
+{
+ if (d->m_functionType != ComparisonOperator)
+ return {};
+ static const QHash<QString, ComparisonOperatorType> mapping = {
+ {u"operator=="_s, OperatorEqual},
+ {u"operator!="_s, OperatorNotEqual},
+ {u"operator<"_s, OperatorLess},
+ {u"operator<="_s, OperatorLessEqual},
+ {u"operator>"_s, OperatorGreater},
+ {u"operator>="_s, OperatorGreaterEqual}
+ };
+ const auto it = mapping.constFind(originalName());
+ Q_ASSERT(it != mapping.constEnd());
+ return it.value();
+}
+
+// Auto-detect whether a function should be wrapped into
+// Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS, that is, temporarily release
+// the GIL (global interpreter lock). Doing so is required for any thread-wait
+// functions, anything that might call a virtual function (potentially
+// reimplemented in Python), and recommended for lengthy I/O or similar.
+// It has performance costs, though.
+bool AbstractMetaFunction::autoDetectAllowThread() const
+{
+ // Disallow for simple getter functions.
+ return !maybeAccessor();
+}
+
+bool AbstractMetaFunction::maybeAccessor() const
+{
+ return d->m_functionType == NormalFunction && d->m_class != nullptr
+ && d->m_constant != 0 && !isVoid() && d->m_arguments.isEmpty();
+}
+
+SourceLocation AbstractMetaFunction::sourceLocation() const
+{
+ return d->m_sourceLocation;
+}
+
+void AbstractMetaFunction::setSourceLocation(const SourceLocation &sourceLocation)
+{
+ d->m_sourceLocation = sourceLocation;
+}
+
+static inline TypeSystem::AllowThread allowThreadMod(const AbstractMetaClassCPtr &klass)
+{
+ return klass->typeEntry()->allowThread();
+}
+
+static inline bool hasAllowThreadMod(const AbstractMetaClassCPtr &klass)
+{
+ return allowThreadMod(klass) != TypeSystem::AllowThread::Unspecified;
+}
+
+bool AbstractMetaFunction::allowThread() const
+{
+ auto allowThreadModification = d->m_allowThreadModification;
+ // If there is no modification on the function, check for a base class.
+ if (d->m_class && allowThreadModification == TypeSystem::AllowThread::Unspecified) {
+ if (auto base = recurseClassHierarchy(d->m_class, hasAllowThreadMod))
+ allowThreadModification = allowThreadMod(base);
+ }
+
+ bool result = true;
+ switch (allowThreadModification) {
+ case TypeSystem::AllowThread::Disallow:
+ result = false;
+ break;
+ case TypeSystem::AllowThread::Allow:
+ break;
+ case TypeSystem::AllowThread::Auto:
+ result = autoDetectAllowThread();
+ break;
+ case TypeSystem::AllowThread::Unspecified:
+ result = false;
+ break;
+ }
+ if (!result && ReportHandler::isDebug(ReportHandler::MediumDebug))
+ qCInfo(lcShiboken).noquote() << msgDisallowThread(this);
+ return result;
+}
+
+TypeSystem::Ownership AbstractMetaFunction::argumentTargetOwnership(const AbstractMetaClassCPtr &cls, int idx) const
+{
+ for (const auto &modification : modifications(cls)) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods()) {
+ if (argumentModification.index() == idx)
+ return argumentModification.targetOwnerShip();
+ }
+ }
+
+ return TypeSystem::UnspecifiedOwnership;
+}
+
+const QString &AbstractMetaFunction::modifiedTypeName() const
+{
+ return d->m_modifiedTypeName;
+}
+
+bool AbstractMetaFunction::generateOpaqueContainerReturn() const
+{
+ if (!isTypeModified() || d->m_type.typeUsagePattern() != AbstractMetaType::ContainerPattern)
+ return false;
+ // Needs to be a reference to a container, allow by value only for spans
+ if (d->m_type.referenceType() != LValueReference) {
+ auto cte = std::static_pointer_cast<const ContainerTypeEntry>(d->m_type.typeEntry());
+ if (cte->containerKind() != ContainerTypeEntry::SpanContainer)
+ return false;
+ }
+ return d->m_type.generateOpaqueContainerForGetter(d->m_modifiedTypeName);
+}
+
+bool AbstractMetaFunction::isModifiedToArray(int argumentIndex) const
+{
+ for (const auto &modification : modifications(declaringClass())) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods()) {
+ if (argumentModification.index() == argumentIndex && argumentModification.isArray())
+ return true;
+ }
+ }
+ return false;
+}
+
+// Note: The declaring class must be correctly set for this to work.
+bool AbstractMetaFunctionPrivate::applyTypeModification(const AbstractMetaFunction *q,
+ const QString &type,
+ int number, QString *errorMessage)
+{
+ if (number < 0 || number > m_arguments.size()) {
+ *errorMessage =
+ msgTypeModificationFailed(type, number, q,
+ msgArgumentOutOfRange(number, 0, m_arguments.size()));
+ return false;
+ }
+
+ // Modified return types may have unparseable types like Python tuples
+ if (number == 0) {
+ m_modifiedTypeName = type;
+ return true;
+ }
+
+ auto typeOpt = AbstractMetaType::fromString(type, errorMessage);
+ if (!typeOpt.has_value()) {
+ *errorMessage = msgTypeModificationFailed(type, number, q, *errorMessage);
+ return false;
+ }
+ m_arguments[number - 1].setModifiedType(typeOpt.value());
+ return true;
+}
+
+void AbstractMetaFunction::applyTypeModifications()
+{
+ QString errorMessage;
+ for (const auto &modification : modifications(declaringClass())) {
+ for (const ArgumentModification &am : modification.argument_mods()) {
+ const int n = am.index();
+ if (am.isTypeModified()
+ && !d->applyTypeModification(this, am.modifiedType(),
+ n, &errorMessage)) {
+ throw Exception(errorMessage);
+ } else if (am.isRemoved() && n != 0) {
+ if (n < 1 || n > d->m_arguments.size()) {
+ errorMessage =
+ msgArgumentRemovalFailed(this, n,
+ msgArgumentOutOfRange(n, 1, d->m_arguments.size()));
+ throw Exception(errorMessage);
+ }
+ d->m_arguments[n - 1].setModifiedRemoved(true);
+ }
+ }
+ }
+}
+
+QString AbstractMetaFunction::pyiTypeReplaced(int argumentIndex) const
+{
+ for (const auto &modification : modifications(declaringClass())) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods()) {
+ if (argumentModification.index() == argumentIndex) {
+ QString type = argumentModification.pyiType();
+ if (!type.isEmpty())
+ return type;
+ type = argumentModification.modifiedType();
+ if (!type.isEmpty())
+ return type;
+ }
+ }
+ }
+
+ return {};
+}
+
+// Parameter 'comment' indicates usage as a code comment of the overload decisor
+QString AbstractMetaFunctionPrivate::formatMinimalSignature(const AbstractMetaFunction *q,
+ bool comment) const
+{
+ QString result = m_originalName + u'(';
+ for (qsizetype i = 0; i < m_arguments.size(); ++i) {
+ const auto &argument = m_arguments.at(i);
+ if (i > 0)
+ result += u',';
+
+ const auto &type = comment ? argument.modifiedType() : argument.type();
+ result += type.minimalSignature();
+ if (comment && argument.hasDefaultValueExpression())
+ result += u'=';
+ }
+ result += u')';
+ if (m_constant)
+ result += u"const"_s;
+ result = TypeDatabase::normalizedSignature(result);
+
+ if (comment && !q->isVoid()) {
+ result += u"->"_s;
+ result += q->isTypeModified()
+ ? q->modifiedTypeName() : q->type().minimalSignature();
+ }
+ return result;
+}
+
+QString AbstractMetaFunction::minimalSignature() const
+{
+ if (d->m_cachedMinimalSignature.isEmpty())
+ d->m_cachedMinimalSignature = d->formatMinimalSignature(this, false);
+ return d->m_cachedMinimalSignature;
+}
+
+QStringList AbstractMetaFunction::modificationSignatures() const
+{
+ QStringList result{minimalSignature()};
+ if (d->m_unresolvedSignature != result.constFirst())
+ result.append(d->m_unresolvedSignature);
+ return result;
+}
+
+QString AbstractMetaFunction::signatureComment() const
+{
+ return d->formatMinimalSignature(this, true);
+}
+
+QString AbstractMetaFunction::debugSignature() const
+{
+ QString result;
+ const auto attributes = cppAttributes();
+ const bool isOverride = attributes.testFlag(FunctionAttribute::Override);
+ const bool isFinal = attributes.testFlag(FunctionAttribute::Final);
+ if (!isOverride && !isFinal && (attributes.testFlag(FunctionAttribute::Virtual)))
+ result += u"virtual "_s;
+ if (d->m_implementingClass)
+ result += d->m_implementingClass->qualifiedCppName() + u"::"_s;
+ result += minimalSignature();
+ if (isOverride)
+ result += u" override"_s;
+ if (isFinal)
+ result += u" final"_s;
+ return result;
+}
+
+FunctionModificationList AbstractMetaFunction::findClassModifications(const AbstractMetaFunction *f,
+ AbstractMetaClassCPtr implementor)
+{
+ const auto signatures = f->modificationSignatures();
+ FunctionModificationList mods;
+ while (implementor) {
+ mods += implementor->typeEntry()->functionModifications(signatures);
+ if ((implementor == implementor->baseClass()) ||
+ (implementor == f->implementingClass() && !mods.isEmpty())) {
+ break;
+ }
+ implementor = implementor->baseClass();
+ }
+ return mods;
+}
+
+FunctionModificationList AbstractMetaFunction::findGlobalModifications(const AbstractMetaFunction *f)
+{
+ auto *td = TypeDatabase::instance();
+ return td->globalFunctionModifications(f->modificationSignatures());
+}
+
+const FunctionModificationList &
+ AbstractMetaFunctionPrivate::modifications(const AbstractMetaFunction *q,
+ const AbstractMetaClassCPtr &implementor) const
+{
+ if (m_addedFunction)
+ return m_addedFunction->modifications();
+ for (const auto &ce : m_modificationCache) {
+ if (ce.klass == implementor)
+ return ce.modifications;
+ }
+ auto modifications = m_class == nullptr
+ ? AbstractMetaFunction::findGlobalModifications(q)
+ : AbstractMetaFunction::findClassModifications(q, implementor);
+
+ m_modificationCache.append({implementor, modifications});
+ return m_modificationCache.constLast().modifications;
+}
+
+const FunctionModificationList &
+ AbstractMetaFunction::modifications(AbstractMetaClassCPtr implementor) const
+{
+ if (!implementor)
+ implementor = d->m_class;
+ return d->modifications(this, implementor);
+}
+
+void AbstractMetaFunction::clearModificationsCache()
+{
+ d->m_modificationCache.clear();
+}
+
+const DocModificationList AbstractMetaFunction::addedFunctionDocModifications() const
+{
+ return d->m_addedFunction
+ ? d->m_addedFunction->docModifications() : DocModificationList{};
+}
+
+QString AbstractMetaFunction::argumentName(int index,
+ bool /* create */,
+ AbstractMetaClassCPtr /* implementor */) const
+{
+ return d->m_arguments[--index].name();
+}
+
+int AbstractMetaFunction::propertySpecIndex() const
+{
+ return d->m_propertySpecIndex;
+}
+
+void AbstractMetaFunction::setPropertySpecIndex(int i)
+{
+ d->m_propertySpecIndex = i;
+}
+
+FunctionTypeEntryPtr AbstractMetaFunction::typeEntry() const
+{
+ return d->m_typeEntry;
+}
+
+void AbstractMetaFunction::setTypeEntry(const FunctionTypeEntryPtr &typeEntry)
+{
+ d->m_typeEntry = typeEntry;
+}
+
+QString AbstractMetaFunction::targetLangPackage() const
+{
+ if (d->m_addedFunction != nullptr)
+ return d->m_addedFunction->targetLangPackage();
+ if (d->m_class != nullptr)
+ return d->m_class->typeEntry()->targetLangPackage();
+ if (d->m_typeEntry != nullptr)
+ return d->m_typeEntry->targetLangPackage();
+ return {};
+}
+
+bool AbstractMetaFunction::isCallOperator() const
+{
+ return d->m_name == u"operator()";
+}
+
+bool AbstractMetaFunction::hasInjectedCode() const
+{
+ const FunctionModificationList &mods = modifications(ownerClass());
+ for (const FunctionModification &mod : mods) {
+ if (mod.isCodeInjection())
+ return true;
+ }
+ return false;
+}
+
+// Traverse the code snippets, return true if predicate returns true
+template <class Predicate>
+bool AbstractMetaFunction::traverseCodeSnips(Predicate predicate,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const
+{
+ for (const FunctionModification &mod : modifications(ownerClass())) {
+ if (mod.isCodeInjection()) {
+ for (const CodeSnip &snip : mod.snips()) {
+ if ((snip.language & language) != 0
+ && (snip.position == position || position == TypeSystem::CodeSnipPositionAny)
+ && predicate(snip)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+CodeSnipList AbstractMetaFunction::injectedCodeSnips(TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const
+{
+ CodeSnipList result;
+ traverseCodeSnips([&result] (const CodeSnip &s) {
+ result.append(s);
+ return false;
+ }, position, language);
+ return result;
+}
+
+bool AbstractMetaFunction::injectedCodeContains(const QRegularExpression &pattern,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const
+{
+ return traverseCodeSnips([pattern] (const CodeSnip &s) {
+ return s.code().contains(pattern);
+ }, position, language);
+}
+
+bool AbstractMetaFunction::injectedCodeContains(QStringView pattern,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const
+{
+ return traverseCodeSnips([pattern] (const CodeSnip &s) {
+ return s.code().contains(pattern);
+ }, position, language);
+}
+
+bool AbstractMetaFunction::hasSignatureModifications() const
+{
+ const FunctionModificationList &mods = modifications();
+ for (const FunctionModification &mod : mods) {
+ if (mod.isRenameModifier())
+ return true;
+ for (const ArgumentModification &argmod : mod.argument_mods()) {
+ // since zero represents the return type and we're
+ // interested only in checking the function arguments,
+ // it will be ignored.
+ if (argmod.index() > 0)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::isConversionOperator(const QString &funcName)
+{
+ return funcName.startsWith(u"operator ");
+}
+
+ExceptionSpecification AbstractMetaFunction::exceptionSpecification() const
+{
+ return d->m_exceptionSpecification;
+}
+
+void AbstractMetaFunction::setExceptionSpecification(ExceptionSpecification e)
+{
+ d->m_exceptionSpecification = e;
+}
+
+static inline TypeSystem::ExceptionHandling exceptionMod(const AbstractMetaClassCPtr &klass)
+{
+ return klass->typeEntry()->exceptionHandling();
+}
+
+static inline bool hasExceptionMod(const AbstractMetaClassCPtr &klass)
+{
+ return exceptionMod(klass) != TypeSystem::ExceptionHandling::Unspecified;
+}
+
+bool AbstractMetaFunction::generateExceptionHandling() const
+{
+ switch (d->m_functionType) {
+ case AbstractMetaFunction::CopyConstructorFunction:
+ case AbstractMetaFunction::MoveConstructorFunction:
+ case AbstractMetaFunction::AssignmentOperatorFunction:
+ case AbstractMetaFunction::MoveAssignmentOperatorFunction:
+ case AbstractMetaFunction::DestructorFunction:
+ return false;
+ default:
+ break;
+ }
+
+ auto exceptionHandlingModification = d->m_exceptionHandlingModification;
+ // If there is no modification on the function, check for a base class.
+ if (d->m_class && exceptionHandlingModification == TypeSystem::ExceptionHandling::Unspecified) {
+ if (auto base = recurseClassHierarchy(d->m_class, hasExceptionMod))
+ exceptionHandlingModification = exceptionMod(base);
+ }
+
+ bool result = false;
+ switch (exceptionHandlingModification) {
+ case TypeSystem::ExceptionHandling::On:
+ result = true;
+ break;
+ case TypeSystem::ExceptionHandling::AutoDefaultToOn:
+ result = d->m_exceptionSpecification != ExceptionSpecification::NoExcept;
+ break;
+ case TypeSystem::ExceptionHandling::AutoDefaultToOff:
+ result = d->m_exceptionSpecification == ExceptionSpecification::Throws;
+ break;
+ case TypeSystem::ExceptionHandling::Unspecified:
+ case TypeSystem::ExceptionHandling::Off:
+ break;
+ }
+ return result;
+}
+
+bool AbstractMetaFunction::isConversionOperator() const
+{
+ return d->m_functionType == ConversionOperator;
+}
+
+bool AbstractMetaFunction::isOperatorOverload(const QString &funcName)
+{
+ if (isConversionOperator(funcName))
+ return true;
+
+ static const QRegularExpression opRegEx(u"^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?"
+ "|\\+\\+|\\-\\-|&&|\\|\\||<<[=]?|>>[=]?|~"
+ "|\\[\\]|\\s+delete\\[?\\]?"
+ "|\\(\\)"
+ "|\\s+new\\[?\\]?)$"_s);
+ Q_ASSERT(opRegEx.isValid());
+ return opRegEx.match(funcName).hasMatch();
+}
+
+bool AbstractMetaFunction::isOperatorOverload() const
+{
+ return d->m_functionType == AssignmentOperatorFunction
+ || (d->m_functionType >= FirstOperator && d->m_functionType <= LastOperator);
+}
+
+bool AbstractMetaFunction::isArithmeticOperator() const
+{
+ return d->m_functionType == ArithmeticOperator;
+}
+
+bool AbstractMetaFunction::isBitwiseOperator() const
+{
+ return d->m_functionType == BitwiseOperator
+ || d->m_functionType == ShiftOperator;
+}
+
+bool AbstractMetaFunction::isComparisonOperator() const
+{
+ return d->m_functionType == ComparisonOperator;
+}
+
+bool AbstractMetaFunction::isSymmetricalComparisonOperator() const
+{
+ if (d->m_functionType != ComparisonOperator || d->m_class == nullptr)
+ return false;
+ AbstractMetaType classType(d->m_class->typeEntry());
+ classType.decideUsagePattern();
+ return std::all_of(d->m_arguments.constBegin(), d->m_arguments.constEnd(),
+ [classType](const AbstractMetaArgument &a) {
+ return a.type().isEquivalent(classType);});
+}
+
+bool AbstractMetaFunction::isIncDecrementOperator() const
+{
+ return d->m_functionType == IncrementOperator
+ || d->m_functionType == DecrementOperator;
+}
+bool AbstractMetaFunction::isLogicalOperator() const
+{
+ return d->m_functionType == LogicalOperator;
+}
+
+bool AbstractMetaFunction::isAssignmentOperator() const
+{
+ return d->m_functionType == AssignmentOperatorFunction
+ || d->m_functionType == MoveAssignmentOperatorFunction;
+}
+
+bool AbstractMetaFunction::isGetter() const
+{
+ return d->m_functionType == NormalFunction && !isVoid()
+ && d->m_constant && d->m_access == Access::Public
+ && d->m_arguments.isEmpty();
+}
+
+bool AbstractMetaFunction::isQtIsNullMethod() const
+{
+ return isGetter() && d->m_name == u"isNull" && returnsBool();
+}
+
+int AbstractMetaFunction::arityOfOperator() const
+{
+ if (!isOperatorOverload() || isCallOperator())
+ return -1;
+
+ int arity = d->m_arguments.size();
+
+ // Operator overloads that are class members
+ // implicitly includes the instance and have
+ // one parameter less than their arity,
+ // so we increment it.
+ if (ownerClass() && arity < 2)
+ arity++;
+
+ return arity;
+}
+
+bool AbstractMetaFunction::isInplaceOperator() const
+{
+ static const QSet<QStringView> inplaceOperators =
+ {
+ u"operator+=", u"operator&=", u"operator-=", u"operator|=",
+ u"operator*=", u"operator^=", u"operator/=", u"operator<<=",
+ u"operator%=", u"operator>>="
+ };
+
+ return isOperatorOverload() && inplaceOperators.contains(originalName());
+}
+
+bool AbstractMetaFunction::isVirtual() const
+{
+ return d->m_cppAttributes.testFlag(FunctionAttribute::Virtual);
+}
+
+QString AbstractMetaFunctionPrivate::modifiedName(const AbstractMetaFunction *q) const
+{
+ if (m_cachedModifiedName.isEmpty()) {
+ for (const auto &mod : q->modifications(q->implementingClass())) {
+ if (mod.isRenameModifier()) {
+ m_cachedModifiedName = mod.renamedToName();
+ break;
+ }
+ }
+ if (m_cachedModifiedName.isEmpty())
+ m_cachedModifiedName = m_name;
+ }
+ return m_cachedModifiedName;
+}
+
+QString AbstractMetaFunction::modifiedName() const
+{
+ return d->modifiedName(this);
+}
+
+AbstractMetaFunctionCPtr
+AbstractMetaFunction::find(const AbstractMetaFunctionCList &haystack,
+ QAnyStringView needle)
+{
+ for (const auto &f : haystack) {
+ if (f->name() == needle)
+ return f;
+ }
+ return {};
+}
+
+bool AbstractMetaFunction::matches(OperatorQueryOptions query) const
+{
+ bool result = false;
+ switch (d->m_functionType) {
+ case AbstractMetaFunction::AssignmentOperatorFunction:
+ result = query.testFlag(OperatorQueryOption::AssignmentOp);
+ break;
+ case AbstractMetaFunction::ConversionOperator:
+ result = query.testFlag(OperatorQueryOption::ConversionOp);
+ break;
+ case AbstractMetaFunction::ArithmeticOperator:
+ result = query.testFlag(OperatorQueryOption::ArithmeticOp);
+ break;
+ case AbstractMetaFunction::IncrementOperator:
+ case AbstractMetaFunction::DecrementOperator:
+ result = query.testFlag(OperatorQueryOption::IncDecrementOp);
+ break;
+ case AbstractMetaFunction::BitwiseOperator:
+ case AbstractMetaFunction::ShiftOperator:
+ result = query.testFlag(OperatorQueryOption::BitwiseOp);
+ break;
+ case AbstractMetaFunction::LogicalOperator:
+ result = query.testFlag(OperatorQueryOption::LogicalOp);
+ break;
+ case AbstractMetaFunction::SubscriptOperator:
+ result = query.testFlag(OperatorQueryOption::SubscriptionOp);
+ break;
+ case AbstractMetaFunction::ComparisonOperator:
+ result = query.testFlag(OperatorQueryOption::ComparisonOp);
+ if (!result && query.testFlag(OperatorQueryOption::SymmetricalComparisonOp))
+ result = isSymmetricalComparisonOperator();
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+void AbstractMetaFunction::setAllowThreadModification(TypeSystem::AllowThread am)
+{
+ d->m_allowThreadModification = am;
+}
+
+void AbstractMetaFunction::setExceptionHandlingModification(TypeSystem::ExceptionHandling em)
+{
+ d->m_exceptionHandlingModification = em;
+}
+
+int AbstractMetaFunctionPrivate::overloadNumber(const AbstractMetaFunction *q) const
+{
+ if (m_cachedOverloadNumber == TypeSystem::OverloadNumberUnset) {
+ m_cachedOverloadNumber = TypeSystem::OverloadNumberDefault;
+ for (const auto &mod : q->modifications(q->implementingClass())) {
+ if (mod.overloadNumber() != TypeSystem::OverloadNumberUnset) {
+ m_cachedOverloadNumber = mod.overloadNumber();
+ break;
+ }
+ }
+ }
+ return m_cachedOverloadNumber;
+}
+
+int AbstractMetaFunction::overloadNumber() const
+{
+ return d->overloadNumber(this);
+}
+
+TypeSystem::SnakeCase AbstractMetaFunction::snakeCase() const
+{
+ if (isUserAdded())
+ return TypeSystem::SnakeCase::Disabled;
+ // Renamed?
+ if (!d->m_originalName.isEmpty() && d->m_originalName != d->m_name)
+ return TypeSystem::SnakeCase::Disabled;
+ switch (d->m_functionType) {
+ case AbstractMetaFunction::NormalFunction:
+ case AbstractMetaFunction::SignalFunction:
+ case AbstractMetaFunction::EmptyFunction:
+ case AbstractMetaFunction::SlotFunction:
+ break;
+ default:
+ return TypeSystem::SnakeCase::Disabled;
+ }
+
+ for (const auto &mod : modifications()) {
+ if (mod.snakeCase() != TypeSystem::SnakeCase::Unspecified)
+ return mod.snakeCase();
+ }
+
+ if (d->m_typeEntry) // Global function
+ return typeSystemTypeEntry(d->m_typeEntry)->snakeCase();
+
+ if (d->m_class) {
+ auto typeEntry = d->m_class->typeEntry();
+ const auto snakeCase = typeEntry->snakeCase();
+ return snakeCase != TypeSystem::SnakeCase::Unspecified
+ ? snakeCase : typeSystemTypeEntry(typeEntry)->snakeCase();
+ }
+ return TypeSystem::SnakeCase::Disabled;
+}
+
+// Query functions for generators
+bool AbstractMetaFunction::injectedCodeUsesPySelf() const
+{
+ return injectedCodeContains(u"%PYSELF", TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode);
+}
+
+bool AbstractMetaFunction::injectedCodeCallsPythonOverride() const
+{
+ static const QRegularExpression
+ overrideCallRegexCheck(R"(PyObject_Call\s*\(\s*%PYTHON_METHOD_OVERRIDE\s*,)"_L1);
+ Q_ASSERT(overrideCallRegexCheck.isValid());
+ return injectedCodeContains(overrideCallRegexCheck, TypeSystem::CodeSnipPositionAny,
+ TypeSystem::NativeCode);
+}
+
+bool AbstractMetaFunction::injectedCodeHasReturnValueAttribution(TypeSystem::Language language) const
+{
+ if (language == TypeSystem::TargetLangCode) {
+ static const QRegularExpression
+ retValAttributionRegexCheck_target(R"(%PYARG_0\s*=[^=]\s*.+)"_L1);
+ Q_ASSERT(retValAttributionRegexCheck_target.isValid());
+ return injectedCodeContains(retValAttributionRegexCheck_target, TypeSystem::CodeSnipPositionAny, language);
+ }
+
+ static const QRegularExpression
+ retValAttributionRegexCheck_native(R"(%0\s*=[^=]\s*.+)"_L1);
+ Q_ASSERT(retValAttributionRegexCheck_native.isValid());
+ return injectedCodeContains(retValAttributionRegexCheck_native, TypeSystem::CodeSnipPositionAny, language);
+}
+
+bool AbstractMetaFunction::injectedCodeUsesArgument(int argumentIndex) const
+{
+ const QRegularExpression argRegEx = CodeSnipAbstract::placeHolderRegex(argumentIndex + 1);
+
+ return traverseCodeSnips([argRegEx](const CodeSnip &s) {
+ const QString code = s.code();
+ return code.contains(u"%ARGUMENT_NAMES") || code.contains(argRegEx);
+ }, TypeSystem::CodeSnipPositionAny);
+}
+
+bool AbstractMetaFunction::isVisibilityModifiedToPrivate() const
+{
+ for (const auto &mod : modifications()) {
+ if (mod.modifiers().testFlag(FunctionModification::Private))
+ return true;
+ }
+ return false;
+}
+
+struct ComparisonOperator
+{
+ const char *cppOperator;
+ const char *pythonOpCode;
+};
+
+using ComparisonOperatorMapping =
+ QHash<AbstractMetaFunction::ComparisonOperatorType, ComparisonOperator>;
+
+static const ComparisonOperatorMapping &comparisonOperatorMapping()
+{
+ static const ComparisonOperatorMapping result = {
+ {AbstractMetaFunction::OperatorEqual, {"==", "Py_EQ"}},
+ {AbstractMetaFunction::OperatorNotEqual, {"!=", "Py_NE"}},
+ {AbstractMetaFunction::OperatorLess, {"<", "Py_LT"}},
+ {AbstractMetaFunction::OperatorLessEqual, {"<=", "Py_LE"}},
+ {AbstractMetaFunction::OperatorGreater, {">", "Py_GT"}},
+ {AbstractMetaFunction::OperatorGreaterEqual, {">=", "Py_GE"}}
+ };
+ return result;
+}
+
+const char * AbstractMetaFunction::pythonRichCompareOpCode(ComparisonOperatorType ct)
+{
+ return comparisonOperatorMapping().value(ct).pythonOpCode;
+}
+
+const char * AbstractMetaFunction::cppComparisonOperator(ComparisonOperatorType ct)
+{
+ return comparisonOperatorMapping().value(ct).cppOperator;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void AbstractMetaFunction::formatDebugBrief(QDebug &debug) const
+{
+ debug << '"' << debugSignature() << '"';
+}
+
+void AbstractMetaFunction::formatDebugVerbose(QDebug &debug) const
+{
+ debug << d->m_functionType << ' ';
+ if (d->m_class)
+ debug << d->m_access << ' ';
+ debug << d->m_type << ' ' << d->m_name;
+ switch (d->m_exceptionSpecification) {
+ case ExceptionSpecification::Unknown:
+ break;
+ case ExceptionSpecification::NoExcept:
+ debug << " noexcept";
+ break;
+ case ExceptionSpecification::Throws:
+ debug << " throw(...)";
+ break;
+ }
+ if (d->m_exceptionHandlingModification != TypeSystem::ExceptionHandling::Unspecified)
+ debug << " exeption-mod " << int(d->m_exceptionHandlingModification);
+ debug << '(';
+ for (qsizetype i = 0, count = d->m_arguments.size(); i < count; ++i) {
+ if (i)
+ debug << ", ";
+ debug << d->m_arguments.at(i);
+ }
+ const QString signature = minimalSignature();
+ debug << "), signature=\"" << signature << '"';
+ if (signature != d->m_unresolvedSignature)
+ debug << ", unresolvedSignature=\"" << d->m_unresolvedSignature << '"';
+ if (d->m_constant)
+ debug << " [const]";
+ if (d->m_reverse)
+ debug << " [reverse]";
+ if (isUserAdded())
+ debug << " [userAdded]";
+ if (isUserDeclared())
+ debug << " [userDeclared]";
+ if (d->m_cppAttributes.testFlag(FunctionAttribute::Explicit))
+ debug << " [explicit]";
+ if (d->m_cppAttributes.testFlag(FunctionAttribute::Deprecated))
+ debug << " [deprecated]";
+ if (d->m_pointerOperator)
+ debug << " [operator->]";
+ if (d->m_isCallOperator)
+ debug << " [operator()]";
+ if (d->m_class)
+ debug << " class: " << d->m_class->name();
+ if (d->m_implementingClass)
+ debug << " implementing class: " << d->m_implementingClass->name();
+ if (d->m_declaringClass)
+ debug << " declaring class: " << d->m_declaringClass->name();
+}
+
+QDebug operator<<(QDebug debug, const AbstractMetaFunction *af)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "AbstractMetaFunction(";
+ if (af) {
+ if (debug.verbosity() > 2) {
+ af->formatDebugVerbose(debug);
+ } else {
+ debug << "signature=";
+ af->formatDebugBrief(debug);
+ }
+ } else {
+ debug << '0';
+ }
+ debug << ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/abstractmetafunction.h b/sources/shiboken6/ApiExtractor/abstractmetafunction.h
new file mode 100644
index 000000000..e252e439d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetafunction.h
@@ -0,0 +1,487 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETAFUNCTION_H
+#define ABSTRACTMETAFUNCTION_H
+
+#include "abstractmetalang_enums.h"
+#include "abstractmetalang_typedefs.h"
+#include "typesystem_enums.h"
+#include "modifications_typedefs.h"
+#include "typesystem_typedefs.h"
+#include "parser/codemodel_enums.h"
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QScopedPointer>
+
+#include <optional>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+QT_FORWARD_DECLARE_CLASS(QRegularExpression)
+
+class AbstractMetaFunctionPrivate;
+class AbstractMetaType;
+class FunctionTypeEntry;
+class Documentation;
+class SourceLocation;
+
+struct ArgumentOwner;
+struct ReferenceCount;
+
+class AbstractMetaFunction
+{
+ Q_GADGET
+public:
+ Q_DISABLE_COPY_MOVE(AbstractMetaFunction)
+
+ enum FunctionType {
+ ConstructorFunction,
+ CopyConstructorFunction,
+ MoveConstructorFunction,
+ AssignmentOperatorFunction,
+ MoveAssignmentOperatorFunction,
+ DestructorFunction,
+ NormalFunction,
+ SignalFunction,
+ EmptyFunction,
+ SlotFunction,
+ GetAttroFunction,
+ SetAttroFunction,
+ CallOperator,
+ FirstOperator = CallOperator,
+ ConversionOperator,
+ DereferenceOperator, // Iterator's operator *
+ ReferenceOperator, // operator &
+ ArrowOperator,
+ ArithmeticOperator,
+ IncrementOperator,
+ DecrementOperator,
+ BitwiseOperator,
+ LogicalOperator,
+ ShiftOperator,
+ SubscriptOperator,
+ ComparisonOperator,
+ LastOperator = ComparisonOperator
+ };
+ Q_ENUM(FunctionType)
+
+ enum ComparisonOperatorType {
+ OperatorEqual, OperatorNotEqual, OperatorLess, OperatorLessEqual,
+ OperatorGreater, OperatorGreaterEqual
+ };
+ Q_ENUM(ComparisonOperatorType)
+
+ enum CompareResultFlag {
+ EqualName = 0x00000001,
+ EqualArguments = 0x00000002,
+ EqualAttributes = 0x00000004,
+ EqualImplementor = 0x00000008,
+ EqualReturnType = 0x00000010,
+ EqualDefaultValueOverload = 0x00000020,
+ EqualModifiedName = 0x00000040,
+
+ NameLessThan = 0x00001000,
+
+ PrettySimilar = EqualName | EqualArguments,
+ Equal = 0x0000001f,
+ NotEqual = 0x00001000
+ };
+ Q_DECLARE_FLAGS(CompareResult, CompareResultFlag)
+ Q_FLAG(CompareResultFlag)
+
+ enum Attribute {
+ None = 0x00000000,
+
+ ClassMethod = 0x00000008,
+
+ GetterFunction = 0x00000020,
+ SetterFunction = 0x00000040,
+
+ PropertyReader = 0x00000100,
+ PropertyWriter = 0x00000200,
+ PropertyResetter = 0x00000400,
+ PropertyNotify = 0x00000800,
+
+ // Add by meta builder (implicit constructors, inherited methods, etc)
+ AddedMethod = 0x001000000,
+ };
+ Q_DECLARE_FLAGS(Attributes, Attribute)
+ Q_FLAG(Attribute)
+
+ Attributes attributes() const;
+ void setAttributes(Attributes attributes);
+
+ void operator+=(Attribute attribute);
+ void operator-=(Attribute attribute);
+
+ FunctionAttributes cppAttributes() const;
+ void setCppAttributes(FunctionAttributes a);
+ void setCppAttribute(FunctionAttribute a, bool on = true);
+
+ enum class Flag { // Internal flags not relevant for comparing functions
+ // Binary operator whose leading/trailing argument was removed by metabuilder
+ OperatorLeadingClassArgumentRemoved = 0x1,
+ OperatorTrailingClassArgumentRemoved = 0x2,
+ OperatorClassArgumentByValue = 0x4, // The removed class argument was passed by value
+ InheritedFromTemplate = 0x8, // Inherited from a template in metabuilder
+ HiddenFriend = 0x10,
+ PrivateSignal = 0x20 // Private Qt signal (cannot emit from client code)
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ Flags flags() const;
+ void setFlags(Flags f);
+
+ bool isAbstract() const;
+ bool isClassMethod() const;
+ bool isStatic() const;
+ bool isPropertyReader() const;
+ bool isPropertyWriter() const;
+ bool isPropertyResetter() const;
+
+ AbstractMetaFunction();
+ explicit AbstractMetaFunction(const QString &name);
+ explicit AbstractMetaFunction(const AddedFunctionPtr &addedFunc);
+ ~AbstractMetaFunction();
+
+ QString name() const;
+ void setName(const QString &name);
+
+ // Names under which the function will be registered to Python.
+ QStringList definitionNames() const;
+
+ QString originalName() const;
+
+ void setOriginalName(const QString &name);
+
+ Access access() const;
+ void setAccess(Access a);
+ void modifyAccess(Access a);
+
+ bool isPrivate() const { return access() == Access::Private; }
+ bool isProtected() const { return access() == Access::Protected; }
+ bool isPublic() const { return access() == Access::Public; }
+ bool wasPrivate() const;
+ bool wasProtected() const;
+ bool wasPublic() const;
+
+ const Documentation &documentation() const;
+ void setDocumentation(const Documentation& doc);
+
+ bool isReverseOperator() const;
+ void setReverseOperator(bool reverse);
+
+ /// Returns true if this is a binary operator and the "self" operand is a
+ /// pointer, e.g. class Foo {}; operator+(SomeEnum, Foo*);
+ /// (not to be mixed up with DereferenceOperator).
+ bool isPointerOperator() const;
+ void setPointerOperator(bool value);
+
+
+ /**
+ * Says if the function (a constructor) was declared as explicit in C++.
+ * \return true if the function was declared as explicit in C++
+ */
+ bool isExplicit() const;
+ void setExplicit(bool isExplicit);
+
+ bool returnsBool() const;
+ bool isOperatorBool() const;
+ static bool isConversionOperator(const QString& funcName);
+
+ ExceptionSpecification exceptionSpecification() const;
+ void setExceptionSpecification(ExceptionSpecification e);
+
+ bool generateExceptionHandling() const;
+
+ bool isConversionOperator() const;
+
+ static bool isOperatorOverload(const QString& funcName);
+ bool isOperatorOverload() const;
+
+ bool isArithmeticOperator() const;
+ bool isBitwiseOperator() const; // Includes shift operator
+ bool isComparisonOperator() const;
+ /// Returns whether this is a comparison accepting owner class
+ /// (bool operator==(QByteArray,QByteArray) but not bool operator==(QByteArray,const char *)
+ bool isSymmetricalComparisonOperator() const;
+ bool isIncDecrementOperator() const;
+ bool isLogicalOperator() const;
+ bool isAssignmentOperator() const; // Assignment or move assignment
+ bool isGetter() const;
+ /// Returns whether it is a Qt-style isNull() method suitable for nb_bool
+ bool isQtIsNullMethod() const;
+
+ /**
+ * Informs the arity of the operator or -1 if the function is not
+ * an operator overload.
+ * /return the arity of the operator or -1
+ */
+ int arityOfOperator() const;
+ bool isUnaryOperator() const { return arityOfOperator() == 1; }
+ bool isBinaryOperator() const { return arityOfOperator() == 2; }
+ bool isInplaceOperator() const;
+
+ bool isVirtual() const;
+ bool allowThread() const;
+ QString modifiedName() const;
+
+ QString minimalSignature() const;
+ /// List of signatures matched for modifications
+ QStringList modificationSignatures() const;
+ // Signature with replaced argument types and return type for overload
+ // decisor comment.
+ QString signatureComment() const;
+ QString debugSignature() const; // including virtual/override/final, etc., for debugging only.
+
+ bool isModifiedRemoved(AbstractMetaClassCPtr cls = {}) const;
+ bool isModifiedFinal(AbstractMetaClassCPtr cls = {}) const;
+
+ bool isVoid() const;
+
+ const AbstractMetaType &type() const;
+ void setType(const AbstractMetaType &type);
+
+ // The class that has this function as a member.
+ AbstractMetaClassCPtr ownerClass() const;
+ void setOwnerClass(const AbstractMetaClassCPtr &cls);
+
+ // Owner excluding invisible namespaces
+ AbstractMetaClassCPtr targetLangOwner() const;
+
+ // The first class in a hierarchy that declares the function
+ AbstractMetaClassCPtr declaringClass() const;
+ void setDeclaringClass(const AbstractMetaClassCPtr &cls);
+
+ // The class that actually implements this function
+ AbstractMetaClassCPtr implementingClass() const;
+ void setImplementingClass(const AbstractMetaClassCPtr &cls);
+
+ const AbstractMetaArgumentList &arguments() const;
+ AbstractMetaArgumentList &arguments();
+ void setArguments(const AbstractMetaArgumentList &arguments);
+ void addArgument(const AbstractMetaArgument &argument);
+ int actualMinimumArgumentCount() const;
+ // Return the argument index accounting for the isModifiedRemoved arguments [0..n-1]
+ int actualArgumentIndex(int index) const;
+
+ bool isDeprecated() const;
+ bool isDestructor() const { return functionType() == DestructorFunction; }
+ bool isConstructor() const;
+ bool isCopyConstructor() const { return functionType() == CopyConstructorFunction; }
+ bool isDefaultConstructor() const;
+ bool needsReturnType() const;
+ bool isInGlobalScope() const;
+ bool isSignal() const { return functionType() == SignalFunction; }
+ bool isSlot() const { return functionType() == SlotFunction; }
+ bool isEmptyFunction() const { return functionType() == EmptyFunction; }
+ bool maybeAccessor() const;
+ FunctionType functionType() const;
+ void setFunctionType(FunctionType type);
+
+ std::optional<ComparisonOperatorType> comparisonOperatorType() const;
+
+ bool usesRValueReferences() const;
+ bool generateBinding() const;
+ // Returns whether the function is contained in the positive list of the
+ // type entry if one is specified.
+ bool isWhiteListed() const;
+
+ QString signature() const;
+ /// Return a signature qualified by class name, for error reporting.
+ QString classQualifiedSignature() const;
+
+ /// Signature with unresolved typedefs as seen by the code parser
+ QString unresolvedSignature() const;
+ void setUnresolvedSignature(const QString &);
+
+ bool isConstant() const;
+ void setConstant(bool constant);
+
+ /// Returns true if the AbstractMetaFunction was added by the user via the type system description.
+ bool isUserAdded() const;
+ bool isUserAddedPythonOverride() const;
+ /// Returns true if the AbstractMetaFunction was declared by the user via
+ /// the type system description.
+ bool isUserDeclared() const;
+
+ CompareResult compareTo(const AbstractMetaFunction *other) const;
+ bool isConstOverloadOf(const AbstractMetaFunction *other) const;
+
+ bool operator <(const AbstractMetaFunction &a) const;
+
+ AbstractMetaFunction *copy() const;
+
+ QString conversionRule(TypeSystem::Language language, int idx) const;
+ bool hasConversionRule(TypeSystem::Language language, int idx) const;
+ QList<ReferenceCount>
+ referenceCounts(const AbstractMetaClassCPtr &cls, int idx = -2) const;
+ ArgumentOwner argumentOwner(const AbstractMetaClassCPtr &cls, int idx) const;
+
+ // Returns the ownership rules for the given argument (target lang).
+ TypeSystem::Ownership
+ argumentTargetOwnership(const AbstractMetaClassCPtr &cls, int idx) const;
+
+ const QString &modifiedTypeName() const;
+ bool isTypeModified() const { return !modifiedTypeName().isEmpty(); }
+ bool generateOpaqueContainerReturn() const;
+
+ bool isModifiedToArray(int argumentIndex) const;
+
+ void applyTypeModifications();
+
+ /// Return the (modified) type for the signature; modified-pyi-type, modified-type
+ QString pyiTypeReplaced(int argumentIndex) const;
+
+ bool argumentRemoved(int) const;
+ /**
+ * Verifies if any modification to the function is an inject code.
+ * \return true if there is inject code modifications to the function.
+ */
+ bool hasInjectedCode() const;
+ /**
+ * Returns a list of code snips for this function.
+ * The code snips can be filtered by position and language.
+ * \return list of code snips
+ */
+ CodeSnipList injectedCodeSnips(TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny,
+ TypeSystem::Language language = TypeSystem::All) const;
+ bool injectedCodeContains(const QRegularExpression &pattern,
+ TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny,
+ TypeSystem::Language language = TypeSystem::All) const;
+ bool injectedCodeContains(QStringView pattern,
+ TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny,
+ TypeSystem::Language language = TypeSystem::All) const;
+
+ /**
+ * Verifies if any modification to the function alters/removes its
+ * arguments types or default values.
+ * \return true if there is some modification to function signature
+ */
+ bool hasSignatureModifications() const;
+
+ const FunctionModificationList &modifications(AbstractMetaClassCPtr implementor = {}) const;
+ void clearModificationsCache();
+
+ const DocModificationList addedFunctionDocModifications() const;
+
+ static FunctionModificationList findClassModifications(const AbstractMetaFunction *f,
+ AbstractMetaClassCPtr implementor);
+ static FunctionModificationList findGlobalModifications(const AbstractMetaFunction *f);
+
+ /**
+ * Return the argument name if there is a modification the renamed value will be returned
+ */
+ QString argumentName(int index, bool create = true, AbstractMetaClassCPtr cl = {}) const;
+
+ int propertySpecIndex() const;
+ void setPropertySpecIndex(int i);
+
+ FunctionTypeEntryPtr typeEntry() const;
+ void setTypeEntry(const FunctionTypeEntryPtr &typeEntry);
+
+ QString targetLangPackage() const;
+
+ bool isCallOperator() const;
+
+ static AbstractMetaFunctionCPtr
+ find(const AbstractMetaFunctionCList &haystack, QAnyStringView needle);
+
+ bool matches(OperatorQueryOptions) const;
+
+ // for the meta builder only
+ void setAllowThreadModification(TypeSystem::AllowThread am);
+ void setExceptionHandlingModification(TypeSystem::ExceptionHandling em);
+
+ int overloadNumber() const;
+
+ TypeSystem::SnakeCase snakeCase() const;
+
+ // Query functions for generators
+ /// Verifies if any of the function's code injections of the "native"
+ /// type needs the type system variable "%PYSELF".
+ /// \return true if the function's native code snippets use "%PYSELF"
+ bool injectedCodeUsesPySelf() const;
+
+ /// Verifies if any of the function's code injections of the "native" class makes a
+ /// call to the C++ method. This is used by the generator to avoid writing calls to
+ /// Python overrides of C++ virtual methods when the user custom code already does this.
+ /// \param func the function to check
+ /// \return true if the function's code snippets call the Python override for a C++ virtual method
+ bool injectedCodeCallsPythonOverride() const;
+
+ /// Verifies if any of the function's code injections attributes values to
+ /// the return variable (%0 or %PYARG_0).
+ /// \param language the kind of code snip
+ /// \return true if the function's code attributes values to "%0" or "%PYARG_0"
+ bool injectedCodeHasReturnValueAttribution(TypeSystem::Language language =
+ TypeSystem::TargetLangCode) const;
+
+ /// Verifies if any of the function's code injections uses the type system variable
+ /// for function arguments of a given index.
+ bool injectedCodeUsesArgument(int argumentIndex) const;
+
+ bool isVisibilityModifiedToPrivate() const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebugBrief(QDebug &debug) const;
+ void formatDebugVerbose(QDebug &debug) const;
+#endif
+
+ SourceLocation sourceLocation() const;
+ void setSourceLocation(const SourceLocation &sourceLocation);
+
+ static const char *pythonRichCompareOpCode(ComparisonOperatorType ct);
+ static const char *cppComparisonOperator(ComparisonOperatorType ct);
+
+private:
+ template <class Predicate>
+ bool traverseCodeSnips(Predicate predicate,
+ TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny,
+ TypeSystem::Language language = TypeSystem::All) const;
+ bool autoDetectAllowThread() const;
+
+ QScopedPointer<AbstractMetaFunctionPrivate> d;
+};
+
+inline bool AbstractMetaFunction::isAbstract() const
+{
+ return cppAttributes().testFlag(FunctionAttribute::Abstract);
+}
+
+inline bool AbstractMetaFunction::isStatic() const
+{
+ return cppAttributes().testFlag(FunctionAttribute::Static);
+}
+
+inline bool AbstractMetaFunction::isClassMethod() const
+{
+ return attributes().testFlag(ClassMethod);
+}
+
+inline bool AbstractMetaFunction::isPropertyReader() const
+{
+ return attributes().testFlag(PropertyReader);
+}
+
+inline bool AbstractMetaFunction::isPropertyWriter() const
+{
+ return attributes().testFlag(PropertyWriter);
+}
+
+inline bool AbstractMetaFunction::isPropertyResetter() const
+{
+ return attributes().testFlag(PropertyResetter);
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::CompareResult)
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::Attributes);
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::Flags);
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const AbstractMetaFunction *af);
+#endif
+
+#endif // ABSTRACTMETAFUNCTION_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.cpp b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
new file mode 100644
index 000000000..fb49cc9d0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
@@ -0,0 +1,1983 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstractmetalang.h"
+#include "anystringview_helpers.h"
+#include "abstractmetalang_helpers.h"
+#include "abstractmetaargument.h"
+#include "abstractmetaenum.h"
+#include "abstractmetafunction.h"
+#include "abstractmetatype.h"
+#include "abstractmetafield.h"
+#include "parser/codemodel.h"
+#include "documentation.h"
+#include "messages.h"
+#include "modifications.h"
+#include "propertyspec.h"
+#include "reporthandler.h"
+#include "sourcelocation.h"
+#include "typedatabase.h"
+#include "enumtypeentry.h"
+#include "namespacetypeentry.h"
+#include "usingmember.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+bool function_sorter(const AbstractMetaFunctionCPtr &a, const AbstractMetaFunctionCPtr &b)
+{
+ return a->signature() < b->signature();
+}
+
+class AbstractMetaClassPrivate
+{
+public:
+ AbstractMetaClassPrivate()
+ : m_hasVirtuals(false),
+ m_isPolymorphic(false),
+ m_hasNonpublic(false),
+ m_hasNonPrivateConstructor(false),
+ m_hasPrivateConstructor(false),
+ m_hasDeletedDefaultConstructor(false),
+ m_hasDeletedCopyConstructor(false),
+ m_functionsFixed(false),
+ m_inheritanceDone(false),
+ m_hasPrivateDestructor(false),
+ m_hasProtectedDestructor(false),
+ m_hasVirtualDestructor(false),
+ m_isTypeDef(false),
+ m_hasToStringCapability(false),
+ m_valueTypeWithCopyConstructorOnly(false),
+ m_hasCachedWrapper(false)
+ {
+ }
+
+ void addFunction(const AbstractMetaFunctionCPtr &function);
+ static AbstractMetaFunction *
+ createFunction(const QString &name, AbstractMetaFunction::FunctionType t,
+ Access access, const AbstractMetaArgumentList &arguments,
+ const AbstractMetaType &returnType, const AbstractMetaClassPtr &q);
+ void addConstructor(AbstractMetaFunction::FunctionType t,
+ Access access,
+ const AbstractMetaArgumentList &arguments,
+ const AbstractMetaClassPtr &q);
+ void addUsingConstructors(const AbstractMetaClassPtr &q);
+ void sortFunctions();
+ void setFunctions(const AbstractMetaFunctionCList &functions,
+ const AbstractMetaClassCPtr &q);
+ bool isUsingMember(const AbstractMetaClassCPtr &c, const QString &memberName,
+ Access minimumAccess) const;
+ bool hasConstructors() const;
+ qsizetype indexOfProperty(const QString &name) const;
+
+ uint m_hasVirtuals : 1;
+ uint m_isPolymorphic : 1;
+ uint m_hasNonpublic : 1;
+ uint m_hasNonPrivateConstructor : 1;
+ uint m_hasPrivateConstructor : 1;
+ uint m_hasDeletedDefaultConstructor : 1;
+ uint m_hasDeletedCopyConstructor : 1;
+ uint m_functionsFixed : 1;
+ uint m_inheritanceDone : 1; // m_baseClasses has been populated from m_baseClassNames
+ uint m_hasPrivateDestructor : 1;
+ uint m_hasProtectedDestructor : 1;
+ uint m_hasVirtualDestructor : 1;
+ uint m_isTypeDef : 1;
+ uint m_hasToStringCapability : 1;
+ uint m_valueTypeWithCopyConstructorOnly : 1;
+ mutable uint m_hasCachedWrapper : 1;
+
+ Documentation m_doc;
+
+ AbstractMetaClassCPtr m_enclosingClass;
+ AbstractMetaClassCPtr m_defaultSuperclass;
+ AbstractMetaClassCList m_baseClasses; // Real base classes after setting up inheritance
+ AbstractMetaTypeList m_baseTemplateInstantiations;
+ AbstractMetaClassCPtr m_extendedNamespace;
+
+ AbstractMetaClassCPtr m_templateBaseClass;
+ AbstractMetaFunctionCList m_functions;
+ AbstractMetaFunctionCList m_userAddedPythonOverrides;
+ AbstractMetaFieldList m_fields;
+ AbstractMetaEnumList m_enums;
+ QList<QPropertySpec> m_propertySpecs;
+ AbstractMetaClassCList m_innerClasses;
+ QString m_hashFunction;
+
+ AbstractMetaFunctionCList m_externalConversionOperators;
+
+ QStringList m_baseClassNames; // Base class names from C++, including rejected
+ TypeEntryCList m_templateArgs;
+ ComplexTypeEntryPtr m_typeEntry;
+ SourceLocation m_sourceLocation;
+ UsingMembers m_usingMembers;
+
+ mutable AbstractMetaClass::CppWrapper m_cachedWrapper;
+ AbstractMetaClass::Attributes m_attributes;
+
+ bool m_stream = false;
+ uint m_toStringCapabilityIndirections = 0;
+};
+
+AbstractMetaClass::AbstractMetaClass() : d(new AbstractMetaClassPrivate)
+{
+}
+
+AbstractMetaClass::~AbstractMetaClass() = default;
+
+AbstractMetaClass::Attributes AbstractMetaClass::attributes() const
+{
+ return d->m_attributes;
+}
+
+void AbstractMetaClass::setAttributes(Attributes attributes)
+{
+ d->m_attributes = attributes;
+}
+
+void AbstractMetaClass::operator+=(AbstractMetaClass::Attribute attribute)
+{
+ d->m_attributes.setFlag(attribute);
+}
+
+void AbstractMetaClass::operator-=(AbstractMetaClass::Attribute attribute)
+{
+ d->m_attributes.setFlag(attribute, false);
+}
+
+bool AbstractMetaClass::isPolymorphic() const
+{
+ return d->m_isPolymorphic;
+}
+
+/*******************************************************************************
+ * Returns a list of all the functions with a given name
+ */
+AbstractMetaFunctionCList AbstractMetaClass::queryFunctionsByName(const QString &name) const
+{
+ AbstractMetaFunctionCList returned;
+ for (const auto &function : d->m_functions) {
+ if (function->name() == name)
+ returned.append(function);
+ }
+
+ return returned;
+}
+
+/*******************************************************************************
+ * Returns a list of all the functions retrieved during parsing which should
+ * be added to the API.
+ */
+AbstractMetaFunctionCList AbstractMetaClass::functionsInTargetLang() const
+{
+ FunctionQueryOptions default_flags = FunctionQueryOption::NormalFunctions
+ | FunctionQueryOption::Visible | FunctionQueryOption::NotRemoved;
+
+ // Constructors
+ AbstractMetaFunctionCList returned = queryFunctions(FunctionQueryOption::AnyConstructor
+ | default_flags);
+
+ returned += queryFunctions(FunctionQueryOption::NonStaticFunctions
+ | default_flags);
+
+ // Static functions
+ returned += queryFunctions(FunctionQueryOption::StaticFunctions
+ | default_flags);
+
+ // Empty, private functions, since they aren't caught by the other ones
+ returned += queryFunctions(FunctionQueryOption::Empty | FunctionQueryOption::Invisible);
+
+ return returned;
+}
+
+AbstractMetaFunctionCList AbstractMetaClass::implicitConversions() const
+{
+ if (!isCopyConstructible() && !hasExternalConversionOperators())
+ return {};
+
+ AbstractMetaFunctionCList returned;
+ const auto list = queryFunctions(FunctionQueryOption::Constructors) + externalConversionOperators();
+
+ // Exclude anything that uses rvalue references, be it a move
+ // constructor "QPolygon(QPolygon &&)" or something else like
+ // "QPolygon(QVector<QPoint> &&)".
+ for (const auto &f : list) {
+ if ((f->actualMinimumArgumentCount() == 1 || f->arguments().size() == 1 || f->isConversionOperator())
+ && !f->isExplicit()
+ && !f->usesRValueReferences()
+ && !f->isModifiedRemoved()
+ && f->wasPublic()) {
+ returned += f;
+ }
+ }
+ return returned;
+}
+
+AbstractMetaFunctionCList AbstractMetaClass::operatorOverloads(OperatorQueryOptions query) const
+{
+ const auto &list = queryFunctions(FunctionQueryOption::OperatorOverloads
+ | FunctionQueryOption::Visible);
+ AbstractMetaFunctionCList returned;
+ for (const auto &f : list) {
+ if (f->matches(query))
+ returned += f;
+ }
+
+ return returned;
+}
+
+bool AbstractMetaClass::hasArithmeticOperatorOverload() const
+{
+ for (const auto & f: d->m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isArithmeticOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasIncDecrementOperatorOverload() const
+{
+ for (const auto & f: d->m_functions) {
+ if (f->ownerClass() == f->implementingClass()
+ && f->isIncDecrementOperator() && !f->isPrivate()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasBitwiseOperatorOverload() const
+{
+ for (const auto & f: d->m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isBitwiseOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasComparisonOperatorOverload() const
+{
+ for (const auto &f : d->m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isComparisonOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasLogicalOperatorOverload() const
+{
+ for (const auto &f : d->m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isLogicalOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+const AbstractMetaFieldList &AbstractMetaClass::fields() const
+{
+ return d->m_fields;
+}
+
+AbstractMetaFieldList &AbstractMetaClass::fields()
+{
+ return d->m_fields;
+}
+
+void AbstractMetaClass::setFields(const AbstractMetaFieldList &fields)
+{
+ d->m_fields = fields;
+}
+
+void AbstractMetaClass::addField(const AbstractMetaField &field)
+{
+ d->m_fields << field;
+}
+
+bool AbstractMetaClass::hasStaticFields() const
+{
+ return std::any_of(d->m_fields.cbegin(), d->m_fields.cend(),
+ [](const AbstractMetaField &f) { return f.isStatic(); });
+}
+
+void AbstractMetaClass::sortFunctions()
+{
+ d->sortFunctions();
+}
+
+AbstractMetaClassCPtr AbstractMetaClass::templateBaseClass() const
+{
+ return d->m_templateBaseClass;
+}
+
+void AbstractMetaClass::setTemplateBaseClass(const AbstractMetaClassCPtr &cls)
+{
+ d->m_templateBaseClass = cls;
+}
+
+const AbstractMetaFunctionCList &AbstractMetaClass::functions() const
+{
+ return d->m_functions;
+}
+
+const AbstractMetaFunctionCList &AbstractMetaClass::userAddedPythonOverrides() const
+{
+ return d->m_userAddedPythonOverrides;
+}
+
+void AbstractMetaClassPrivate::sortFunctions()
+{
+ std::sort(m_functions.begin(), m_functions.end(), function_sorter);
+}
+
+void AbstractMetaClassPrivate::setFunctions(const AbstractMetaFunctionCList &functions,
+ const AbstractMetaClassCPtr &q)
+{
+ m_functions = functions;
+
+ // Functions must be sorted by name before next loop
+ sortFunctions();
+
+ for (const auto &f : std::as_const(m_functions)) {
+ std::const_pointer_cast<AbstractMetaFunction>(f)->setOwnerClass(q);
+ if (!f->isPublic())
+ m_hasNonpublic = true;
+ }
+}
+
+const QList<QPropertySpec> &AbstractMetaClass::propertySpecs() const
+{
+ return d->m_propertySpecs;
+}
+
+void AbstractMetaClass::addPropertySpec(const QPropertySpec &spec)
+{
+ d->m_propertySpecs << spec;
+}
+
+void AbstractMetaClass::setPropertyDocumentation(const QString &name, const Documentation &doc)
+{
+ const auto index = d->indexOfProperty(name);
+ if (index >= 0)
+ d->m_propertySpecs[index].setDocumentation(doc);
+}
+
+void AbstractMetaClassPrivate::addFunction(const AbstractMetaFunctionCPtr &function)
+{
+ Q_ASSERT(!function->signature().startsWith(u'('));
+
+ if (!function->isDestructor())
+ m_functions << function;
+ else
+ Q_ASSERT(false); //memory leak
+
+ m_hasVirtuals |= function->isVirtual();
+ m_isPolymorphic |= m_hasVirtuals;
+ m_hasNonpublic |= !function->isPublic();
+ m_hasNonPrivateConstructor |= !function->isPrivate()
+ && function->functionType() == AbstractMetaFunction::ConstructorFunction;
+}
+
+void AbstractMetaClass::addFunction(const AbstractMetaClassPtr &klass,
+ const AbstractMetaFunctionCPtr &function)
+{
+ auto nonConstF = std::const_pointer_cast<AbstractMetaFunction>(function);
+ nonConstF->setOwnerClass(klass);
+
+ // Set the default value of the declaring class. This may be changed
+ // in fixFunctions later on
+ nonConstF->setDeclaringClass(klass);
+
+ // Some of the queries below depend on the implementing class being set
+ // to function properly. Such as function modifications
+ nonConstF->setImplementingClass(klass);
+
+ if (function->isUserAddedPythonOverride()) {
+ nonConstF->setConstant(false);
+ nonConstF->setCppAttribute(FunctionAttribute::Static);
+ klass->d->m_userAddedPythonOverrides.append(function);
+ } else {
+ klass->d->addFunction(function);
+ }
+}
+
+bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const
+{
+ if (!other->isSignal())
+ return false;
+
+ for (const auto &f : d->m_functions) {
+ if (f->isSignal() && f->compareTo(other) & AbstractMetaFunction::EqualName)
+ return other->modifiedName() == f->modifiedName();
+ }
+
+ return false;
+}
+
+
+QString AbstractMetaClass::name() const
+{
+ return d->m_typeEntry->targetLangEntryName();
+}
+
+const Documentation &AbstractMetaClass::documentation() const
+{
+ return d->m_doc;
+}
+
+void AbstractMetaClass::setDocumentation(const Documentation &doc)
+{
+ d->m_doc = doc;
+}
+
+QString AbstractMetaClass::baseClassName() const
+{
+ return d->m_baseClasses.isEmpty() ? QString() : d->m_baseClasses.constFirst()->name();
+}
+
+// Attribute "default-superclass"
+AbstractMetaClassCPtr AbstractMetaClass::defaultSuperclass() const
+{
+ return d->m_defaultSuperclass;
+}
+
+void AbstractMetaClass::setDefaultSuperclass(const AbstractMetaClassPtr &s)
+{
+ d->m_defaultSuperclass = s;
+}
+
+AbstractMetaClassCPtr AbstractMetaClass::baseClass() const
+{
+ return d->m_baseClasses.value(0, nullptr);
+}
+
+const AbstractMetaClassCList &AbstractMetaClass::baseClasses() const
+{
+ Q_ASSERT(inheritanceDone() || !needsInheritanceSetup());
+ return d->m_baseClasses;
+}
+
+// base classes including "defaultSuperclass".
+AbstractMetaClassCList AbstractMetaClass::typeSystemBaseClasses() const
+{
+ AbstractMetaClassCList result = d->m_baseClasses;
+ if (d->m_defaultSuperclass) {
+ result.removeAll(d->m_defaultSuperclass);
+ result.prepend(d->m_defaultSuperclass);
+ }
+ return result;
+}
+
+// Recursive list of all base classes including defaultSuperclass
+AbstractMetaClassCList AbstractMetaClass::allTypeSystemAncestors() const
+{
+ AbstractMetaClassCList result;
+ const auto baseClasses = typeSystemBaseClasses();
+ for (const auto &base : baseClasses) {
+ result.append(base);
+ result.append(base->allTypeSystemAncestors());
+ }
+ return result;
+}
+
+void AbstractMetaClass::addBaseClass(const AbstractMetaClassCPtr &baseClass)
+{
+ Q_ASSERT(baseClass);
+ d->m_baseClasses.append(baseClass);
+ d->m_isPolymorphic |= baseClass->isPolymorphic();
+}
+
+void AbstractMetaClass::setBaseClass(const AbstractMetaClassCPtr &baseClass)
+{
+ if (baseClass) {
+ d->m_baseClasses.prepend(baseClass);
+ d->m_isPolymorphic |= baseClass->isPolymorphic();
+ }
+}
+
+AbstractMetaClassCPtr AbstractMetaClass::extendedNamespace() const
+{
+ return d->m_extendedNamespace;
+}
+
+void AbstractMetaClass::setExtendedNamespace(const AbstractMetaClassCPtr &e)
+{
+ d->m_extendedNamespace = e;
+}
+
+const AbstractMetaClassCList &AbstractMetaClass::innerClasses() const
+{
+ return d->m_innerClasses;
+}
+
+void AbstractMetaClass::addInnerClass(const AbstractMetaClassPtr &cl)
+{
+ d->m_innerClasses << cl;
+}
+
+void AbstractMetaClass::setInnerClasses(const AbstractMetaClassCList &innerClasses)
+{
+ d->m_innerClasses = innerClasses;
+}
+
+QString AbstractMetaClass::package() const
+{
+ return d->m_typeEntry->targetLangPackage();
+}
+
+bool AbstractMetaClass::isNamespace() const
+{
+ return d->m_typeEntry->isNamespace();
+}
+
+// Is an invisible namespaces whose functions/enums
+// should be mapped to the global space.
+bool AbstractMetaClass::isInvisibleNamespace() const
+{
+ return d->m_typeEntry->isNamespace() && d->m_typeEntry->generateCode()
+ && !NamespaceTypeEntry::isVisibleScope(d->m_typeEntry);
+}
+
+bool AbstractMetaClass::isInlineNamespace() const
+{
+ bool result = false;
+ if (d->m_typeEntry->isNamespace()) {
+ const auto nte = std::static_pointer_cast<const NamespaceTypeEntry>(d->m_typeEntry);
+ result = nte->isInlineNamespace();
+ }
+ return result;
+}
+
+bool AbstractMetaClass::isQtNamespace() const
+{
+ return isNamespace() && name() == u"Qt";
+}
+
+QString AbstractMetaClass::qualifiedCppName() const
+{
+ return d->m_typeEntry->qualifiedCppName();
+}
+
+bool AbstractMetaClass::hasFunction(const QString &str) const
+{
+ return bool(findFunction(str));
+}
+
+AbstractMetaFunctionCPtr AbstractMetaClass::findFunction(QAnyStringView functionName) const
+{
+ return AbstractMetaFunction::find(d->m_functions, functionName);
+}
+
+AbstractMetaFunctionCList AbstractMetaClass::findFunctions(QAnyStringView functionName) const
+{
+ AbstractMetaFunctionCList result;
+ std::copy_if(d->m_functions.cbegin(), d->m_functions.cend(),
+ std::back_inserter(result),
+ [&functionName](const AbstractMetaFunctionCPtr &f) {
+ return f->name() == functionName;
+ });
+ return result;
+}
+
+AbstractMetaFunctionCPtr AbstractMetaClass::findOperatorBool() const
+{
+ auto it = std::find_if(d->m_functions.cbegin(), d->m_functions.cend(),
+ [](const AbstractMetaFunctionCPtr &f) {
+ return f->isOperatorBool();
+ });
+ if (it == d->m_functions.cend())
+ return {};
+ return *it;
+}
+
+AbstractMetaFunctionCPtr AbstractMetaClass::findQtIsNullMethod() const
+{
+ auto it = std::find_if(d->m_functions.cbegin(), d->m_functions.cend(),
+ [](const AbstractMetaFunctionCPtr &f) {
+ return f->isQtIsNullMethod();
+ });
+ if (it == d->m_functions.cend())
+ return {};
+ return *it;
+}
+
+bool AbstractMetaClass::hasProtectedFields() const
+{
+ for (const AbstractMetaField &field : d->m_fields) {
+ if (field.isProtected())
+ return true;
+ }
+ return false;
+}
+
+const TypeEntryCList &AbstractMetaClass::templateArguments() const
+{
+ return d->m_templateArgs;
+}
+
+void AbstractMetaClass::setTemplateArguments(const TypeEntryCList &args)
+{
+ d->m_templateArgs = args;
+}
+
+const QStringList &AbstractMetaClass::baseClassNames() const
+{
+ return d->m_baseClassNames;
+}
+
+void AbstractMetaClass::setBaseClassNames(const QStringList &names)
+{
+ d->m_baseClassNames = names;
+}
+
+ComplexTypeEntryCPtr AbstractMetaClass::typeEntry() const
+{
+ return d->m_typeEntry;
+}
+
+ComplexTypeEntryPtr AbstractMetaClass::typeEntry()
+{
+ return d->m_typeEntry;
+}
+
+void AbstractMetaClass::setTypeEntry(const ComplexTypeEntryPtr &type)
+{
+ d->m_typeEntry = type;
+}
+
+QString AbstractMetaClass::hashFunction() const
+{
+ return d->m_hashFunction;
+}
+
+void AbstractMetaClass::setHashFunction(const QString &f)
+{
+ d->m_hashFunction = f;
+}
+
+bool AbstractMetaClass::hasHashFunction() const
+{
+ return !d->m_hashFunction.isEmpty();
+}
+
+// Search whether a functions is a property setter/getter/reset
+AbstractMetaClass::PropertyFunctionSearchResult
+ AbstractMetaClass::searchPropertyFunction(const QString &name) const
+{
+ for (qsizetype i = 0, size = d->m_propertySpecs.size(); i < size; ++i) {
+ const auto &propertySpec = d->m_propertySpecs.at(i);
+ if (name == propertySpec.read())
+ return PropertyFunctionSearchResult{i, PropertyFunction::Read};
+ if (name == propertySpec.write())
+ return PropertyFunctionSearchResult{i, PropertyFunction::Write};
+ if (name == propertySpec.reset())
+ return PropertyFunctionSearchResult{i, PropertyFunction::Reset};
+ if (name == propertySpec.notify())
+ return PropertyFunctionSearchResult{i, PropertyFunction::Notify};
+ }
+ return PropertyFunctionSearchResult{-1, PropertyFunction::Read};
+}
+
+std::optional<QPropertySpec>
+ AbstractMetaClass::propertySpecByName(const QString &name) const
+{
+ const auto index = d->indexOfProperty(name);
+ if (index >= 0)
+ return d->m_propertySpecs.at(index);
+ return {};
+}
+
+const AbstractMetaFunctionCList &AbstractMetaClass::externalConversionOperators() const
+{
+ return d->m_externalConversionOperators;
+}
+
+void AbstractMetaClass::addExternalConversionOperator(const AbstractMetaFunctionCPtr &conversionOp)
+{
+ if (!d->m_externalConversionOperators.contains(conversionOp))
+ d->m_externalConversionOperators.append(conversionOp);
+}
+
+bool AbstractMetaClass::hasExternalConversionOperators() const
+{
+ return !d->m_externalConversionOperators.isEmpty();
+}
+
+bool AbstractMetaClass::hasTemplateBaseClassInstantiations() const
+{
+ return d->m_templateBaseClass != nullptr && !d->m_baseTemplateInstantiations.isEmpty();
+}
+
+const AbstractMetaTypeList &AbstractMetaClass::templateBaseClassInstantiations() const
+{
+ return d->m_baseTemplateInstantiations;
+}
+
+void AbstractMetaClass::setTemplateBaseClassInstantiations(const AbstractMetaTypeList &instantiations)
+{
+ Q_ASSERT(d->m_templateBaseClass != nullptr);
+ d->m_baseTemplateInstantiations = instantiations;
+}
+
+void AbstractMetaClass::setTypeDef(bool typeDef)
+{
+ d->m_isTypeDef = typeDef;
+}
+
+bool AbstractMetaClass::isTypeDef() const
+{
+ return d->m_isTypeDef;
+}
+
+bool AbstractMetaClass::isStream() const
+{
+ return d->m_stream;
+}
+
+void AbstractMetaClass::setStream(bool stream)
+{
+ d->m_stream = stream;
+}
+
+bool AbstractMetaClass::hasToStringCapability() const
+{
+ return d->m_hasToStringCapability;
+}
+
+void AbstractMetaClass::setToStringCapability(bool value, uint indirections)
+{
+ d->m_hasToStringCapability = value;
+ d->m_toStringCapabilityIndirections = indirections;
+}
+
+uint AbstractMetaClass::toStringCapabilityIndirections() const
+{
+ return d->m_toStringCapabilityIndirections;
+}
+
+// Does any of the base classes require deletion in the main thread?
+bool AbstractMetaClass::deleteInMainThread() const
+{
+ return typeEntry()->deleteInMainThread()
+ || (!d->m_baseClasses.isEmpty() && d->m_baseClasses.constFirst()->deleteInMainThread());
+}
+
+bool AbstractMetaClassPrivate::hasConstructors() const
+{
+ return AbstractMetaClass::queryFirstFunction(m_functions,
+ FunctionQueryOption::AnyConstructor) != nullptr;
+}
+
+qsizetype AbstractMetaClassPrivate::indexOfProperty(const QString &name) const
+{
+ for (qsizetype i = 0; i < m_propertySpecs.size(); ++i) {
+ if (m_propertySpecs.at(i).name() == name)
+ return i;
+ }
+ return -1;
+}
+
+bool AbstractMetaClass::hasConstructors() const
+{
+ return d->hasConstructors();
+}
+
+AbstractMetaFunctionCPtr AbstractMetaClass::copyConstructor() const
+{
+ for (const auto &f : d->m_functions) {
+ if (f->functionType() == AbstractMetaFunction::CopyConstructorFunction)
+ return f;
+ }
+ return {};
+}
+
+bool AbstractMetaClass::hasCopyConstructor() const
+{
+ return copyConstructor() != nullptr;
+}
+
+bool AbstractMetaClass::hasPrivateCopyConstructor() const
+{
+ const auto copyCt = copyConstructor();
+ return copyCt && copyCt->isPrivate();
+}
+
+void AbstractMetaClassPrivate::addConstructor(AbstractMetaFunction::FunctionType t,
+ Access access,
+ const AbstractMetaArgumentList &arguments,
+ const AbstractMetaClassPtr &q)
+{
+ auto *f = createFunction(q->name(), t, access, arguments, AbstractMetaType::createVoid(), q);
+ if (access != Access::Private)
+ m_hasNonPrivateConstructor = true;
+ f->setAttributes(AbstractMetaFunction::AddedMethod);
+ addFunction(AbstractMetaFunctionCPtr(f));
+}
+
+void AbstractMetaClass::addDefaultConstructor(const AbstractMetaClassPtr &klass)
+{
+ klass->d->addConstructor(AbstractMetaFunction::ConstructorFunction,
+ Access::Public, {}, klass);
+}
+
+void AbstractMetaClass::addDefaultCopyConstructor(const AbstractMetaClassPtr &klass)
+{
+ AbstractMetaType argType(klass->typeEntry());
+ argType.setReferenceType(LValueReference);
+ argType.setConstant(true);
+ argType.setTypeUsagePattern(AbstractMetaType::ValuePattern);
+
+ AbstractMetaArgument arg;
+ arg.setType(argType);
+ arg.setName(klass->name());
+
+ klass->d->addConstructor(AbstractMetaFunction::CopyConstructorFunction,
+ Access::Public, {arg}, klass);
+}
+
+AbstractMetaFunction *
+ AbstractMetaClassPrivate::createFunction(const QString &name,
+ AbstractMetaFunction::FunctionType t,
+ Access access,
+ const AbstractMetaArgumentList &arguments,
+ const AbstractMetaType &returnType,
+ const AbstractMetaClassPtr &q)
+{
+ auto *f = new AbstractMetaFunction(name);
+ f->setType(returnType);
+ f->setOwnerClass(q);
+ f->setFunctionType(t);
+ f->setArguments(arguments);
+ f->setDeclaringClass(q);
+ f->setAccess(access);
+ f->setImplementingClass(q);
+ return f;
+}
+
+static AbstractMetaType boolType()
+{
+ auto boolType = TypeDatabase::instance()->findType(u"bool"_s);
+ Q_ASSERT(boolType);
+ AbstractMetaType result(boolType);
+ result.decideUsagePattern();
+ return result;
+}
+
+// Helper to synthesize comparison operators from a spaceship operator. Since
+// shiboken also generates code for comparing to different types, this fits
+// better than of handling it in the generator code.
+void AbstractMetaClass::addSynthesizedComparisonOperators(const AbstractMetaClassPtr &c)
+{
+ static const auto returnType = boolType();
+
+ AbstractMetaType selfType(c->typeEntry());
+ selfType.setConstant(true);
+ selfType.setReferenceType(LValueReference);
+ selfType.decideUsagePattern();
+ AbstractMetaArgument selfArgument;
+ selfArgument.setType(selfType);
+ selfArgument.setName(u"rhs"_s);
+ AbstractMetaArgumentList arguments(1, selfArgument);
+
+ static const char *operators[]
+ = {"operator==", "operator!=", "operator<", "operator<=", "operator>", "operator>="};
+ for (auto *op : operators) {
+ auto *f = AbstractMetaClassPrivate::createFunction(QLatin1StringView(op),
+ AbstractMetaFunction::ComparisonOperator,
+ Access::Public, arguments,
+ returnType, c);
+ c->d->addFunction(AbstractMetaFunctionCPtr(f));
+ }
+}
+
+bool AbstractMetaClass::hasNonPrivateConstructor() const
+{
+ return d->m_hasNonPrivateConstructor;
+}
+
+void AbstractMetaClass::setHasNonPrivateConstructor(bool value)
+{
+ d->m_hasNonPrivateConstructor = value;
+}
+
+bool AbstractMetaClass::hasPrivateConstructor() const
+{
+ return d->m_hasPrivateConstructor;
+}
+
+void AbstractMetaClass::setHasPrivateConstructor(bool value)
+{
+ d->m_hasPrivateConstructor = value;
+}
+
+bool AbstractMetaClass::hasDeletedDefaultConstructor() const
+{
+ return d->m_hasDeletedDefaultConstructor;
+}
+
+void AbstractMetaClass::setHasDeletedDefaultConstructor(bool value)
+{
+ d->m_hasDeletedDefaultConstructor = value;
+}
+
+bool AbstractMetaClass::hasDeletedCopyConstructor() const
+{
+ return d->m_hasDeletedCopyConstructor;
+}
+
+void AbstractMetaClass::setHasDeletedCopyConstructor(bool value)
+{
+ d->m_hasDeletedCopyConstructor = value;
+}
+
+bool AbstractMetaClass::hasPrivateDestructor() const
+{
+ return d->m_hasPrivateDestructor;
+}
+
+void AbstractMetaClass::setHasPrivateDestructor(bool value)
+{
+ d->m_hasPrivateDestructor = value;
+}
+
+bool AbstractMetaClass::hasProtectedDestructor() const
+{
+ return d->m_hasProtectedDestructor;
+}
+
+void AbstractMetaClass::setHasProtectedDestructor(bool value)
+{
+ d->m_hasProtectedDestructor = value;
+}
+
+bool AbstractMetaClass::hasVirtualDestructor() const
+{
+ return d->m_hasVirtualDestructor;
+}
+
+void AbstractMetaClass::setHasVirtualDestructor(bool value)
+{
+ d->m_hasVirtualDestructor = value;
+ if (value)
+ d->m_hasVirtuals = d->m_isPolymorphic = 1;
+}
+
+bool AbstractMetaClass::isDefaultConstructible() const
+{
+ // Private constructors are skipped by the builder.
+ if (hasDeletedDefaultConstructor() || hasPrivateConstructor())
+ return false;
+ const AbstractMetaFunctionCList ctors =
+ queryFunctions(FunctionQueryOption::Constructors);
+ for (const auto &ct : ctors) {
+ if (ct->isDefaultConstructor())
+ return ct->isPublic();
+ }
+ return ctors.isEmpty() && isImplicitlyDefaultConstructible();
+}
+
+// Non-comprehensive check for default constructible field
+// (non-ref or not const value).
+static bool defaultConstructibleField(const AbstractMetaField &f)
+{
+ if (f.isStatic())
+ return true;
+ const auto &type = f.type();
+ return type.referenceType() == NoReference
+ && !(type.indirections() == 0 && type.isConstant()); // no const values
+}
+
+bool AbstractMetaClass::isImplicitlyDefaultConstructible() const
+{
+ return std::all_of(d->m_fields.cbegin(), d->m_fields.cend(),
+ defaultConstructibleField)
+ && std::all_of(d->m_baseClasses.cbegin(), d->m_baseClasses.cend(),
+ [] (const AbstractMetaClassCPtr &c) {
+ return c->isDefaultConstructible();
+ });
+}
+
+static bool canAddDefaultConstructorHelper(const AbstractMetaClass *cls)
+{
+ return !cls->isNamespace()
+ && !cls->hasDeletedDefaultConstructor()
+ && !cls->attributes().testFlag(AbstractMetaClass::HasRejectedConstructor)
+ && !cls->hasPrivateDestructor();
+}
+
+bool AbstractMetaClass::canAddDefaultConstructor() const
+{
+ return canAddDefaultConstructorHelper(this) && !hasConstructors()
+ && !hasPrivateConstructor() && isImplicitlyDefaultConstructible();
+}
+
+bool AbstractMetaClass::isCopyConstructible() const
+{
+ // Private constructors are skipped by the builder.
+ if (hasDeletedCopyConstructor() || hasPrivateCopyConstructor())
+ return false;
+ const AbstractMetaFunctionCList copyCtors =
+ queryFunctions(FunctionQueryOption::CopyConstructor);
+ return copyCtors.isEmpty()
+ ? isImplicitlyCopyConstructible()
+ : copyCtors.constFirst()->isPublic();
+}
+
+bool AbstractMetaClass::isImplicitlyCopyConstructible() const
+{
+ // Fields are currently not considered
+ return std::all_of(d->m_baseClasses.cbegin(), d->m_baseClasses.cend(),
+ [] (const AbstractMetaClassCPtr &c) {
+ return c->isCopyConstructible();
+ });
+}
+
+bool AbstractMetaClass::canAddDefaultCopyConstructor() const
+{
+ if (!canAddDefaultConstructorHelper(this)
+ || !d->m_typeEntry->isValue() || isAbstract()
+ || hasPrivateCopyConstructor() || hasCopyConstructor()) {
+ return false;
+ }
+ return isImplicitlyCopyConstructible();
+}
+
+static bool classHasParentManagement(const AbstractMetaClassCPtr &c)
+{
+ const auto flags = c->typeEntry()->typeFlags();
+ return flags.testFlag(ComplexTypeEntry::ParentManagement);
+}
+
+TypeEntryCPtr parentManagementEntry(const AbstractMetaClassCPtr &klass)
+{
+ if (klass->typeEntry()->isObject()) {
+ if (auto c = recurseClassHierarchy(klass, classHasParentManagement))
+ return c->typeEntry();
+ }
+ return nullptr;
+}
+
+bool AbstractMetaClass::generateExceptionHandling() const
+{
+ return queryFirstFunction(d->m_functions, FunctionQueryOption::Visible
+ | FunctionQueryOption::GenerateExceptionHandling) != nullptr;
+}
+
+static bool needsProtectedWrapper(const AbstractMetaFunctionCPtr &func)
+{
+ return func->isProtected()
+ && !(func->isSignal() || func->isModifiedRemoved())
+ && !func->isOperatorOverload();
+}
+
+static AbstractMetaClass::CppWrapper determineCppWrapper(const AbstractMetaClass *metaClass)
+{
+
+ AbstractMetaClass::CppWrapper result;
+
+ if (metaClass->isNamespace()
+ || metaClass->attributes().testFlag(AbstractMetaClass::FinalCppClass)
+ || metaClass->typeEntry()->typeFlags().testFlag(ComplexTypeEntry::DisableWrapper)) {
+ return result;
+ }
+
+#ifndef Q_CC_MSVC
+ // PYSIDE-504: When C++ 11 is used, then the destructor must always be
+ // declared. Only MSVC can handle this, the others generate a link error.
+ // See also HeaderGenerator::generateClass().
+ if (metaClass->hasPrivateDestructor())
+ return result;
+#endif
+
+ // Need checking for Python overrides?
+ if (metaClass->isPolymorphic())
+ result |= AbstractMetaClass::CppVirtualMethodWrapper;
+
+ // Is there anything protected that needs to be made accessible?
+ if (metaClass->hasProtectedFields() || metaClass->hasProtectedDestructor()
+ || std::any_of(metaClass->functions().cbegin(), metaClass->functions().cend(),
+ needsProtectedWrapper)) {
+ result |= AbstractMetaClass::CppProtectedHackWrapper;
+ }
+ return result;
+}
+
+AbstractMetaClass::CppWrapper AbstractMetaClass::cppWrapper() const
+{
+ if (!d->m_hasCachedWrapper) {
+ d->m_cachedWrapper = determineCppWrapper(this);
+ d->m_hasCachedWrapper = true;
+ }
+ return d->m_cachedWrapper;
+}
+
+const UsingMembers &AbstractMetaClass::usingMembers() const
+{
+ return d->m_usingMembers;
+}
+
+void AbstractMetaClass::addUsingMember(const UsingMember &um)
+{
+ d->m_usingMembers.append(um);
+}
+
+bool AbstractMetaClassPrivate::isUsingMember(const AbstractMetaClassCPtr &c,
+ const QString &memberName,
+ Access minimumAccess) const
+{
+ auto it = std::find_if(m_usingMembers.cbegin(), m_usingMembers.cend(),
+ [c, &memberName](const UsingMember &um) {
+ return um.baseClass == c && um.memberName == memberName;
+ });
+ return it != m_usingMembers.cend() && it->access >= minimumAccess;
+}
+
+bool AbstractMetaClass::isUsingMember(const AbstractMetaClassCPtr &c,
+ const QString &memberName,
+ Access minimumAccess) const
+{
+ return d->isUsingMember(c, memberName, minimumAccess);
+}
+
+bool AbstractMetaClass::hasUsingMemberFor(const QString &memberName) const
+{
+ return std::any_of(d->m_usingMembers.cbegin(), d->m_usingMembers.cend(),
+ [&memberName](const UsingMember &um) {
+ return um.memberName == memberName;
+ });
+}
+
+/* Goes through the list of functions and returns a list of all
+ functions matching all of the criteria in \a query.
+ */
+
+bool AbstractMetaClass::queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query)
+{
+ if ((query.testFlag(FunctionQueryOption::NotRemoved))) {
+ if (f->isModifiedRemoved())
+ return false;
+ if (f->isVirtual() && f->isModifiedRemoved(f->declaringClass()))
+ return false;
+ }
+
+ if (query.testFlag(FunctionQueryOption::Visible) && f->isPrivate())
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::Invisible) && !f->isPrivate())
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::Empty) && !f->isEmptyFunction())
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::ClassImplements) && f->ownerClass() != f->implementingClass())
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::VirtualInCppFunctions) && !f->isVirtual())
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::Signals) && (!f->isSignal()))
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::AnyConstructor)
+ && (!f->isConstructor() || f->ownerClass() != f->implementingClass())) {
+ return false;
+ }
+
+ if (query.testFlag(FunctionQueryOption::Constructors)
+ && (f->functionType() != AbstractMetaFunction::ConstructorFunction
+ || f->ownerClass() != f->implementingClass())) {
+ return false;
+ }
+
+ if (query.testFlag(FunctionQueryOption::CopyConstructor)
+ && (!f->isCopyConstructor() || f->ownerClass() != f->implementingClass())) {
+ return false;
+ }
+
+ // Destructors are never included in the functions of a class currently
+ /*
+ if ((query & Destructors) && (!f->isDestructor()
+ || f->ownerClass() != f->implementingClass())
+ || f->isDestructor() && (query & Destructors) == 0) {
+ return false;
+ }*/
+
+ if (query.testFlag(FunctionQueryOption::StaticFunctions) && (!f->isStatic() || f->isSignal()))
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::NonStaticFunctions) && (f->isStatic()))
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::NormalFunctions) && (f->isSignal()))
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::OperatorOverloads) && !f->isOperatorOverload())
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::GenerateExceptionHandling) && !f->generateExceptionHandling())
+ return false;
+
+ if (query.testFlag(FunctionQueryOption::GetAttroFunction)
+ && f->functionType() != AbstractMetaFunction::GetAttroFunction) {
+ return false;
+ }
+
+ if (query.testFlag(FunctionQueryOption::SetAttroFunction)
+ && f->functionType() != AbstractMetaFunction::SetAttroFunction) {
+ return false;
+ }
+
+ return true;
+}
+
+AbstractMetaFunctionCList AbstractMetaClass::queryFunctionList(const AbstractMetaFunctionCList &list,
+ FunctionQueryOptions query)
+{
+ AbstractMetaFunctionCList result;
+ for (const auto &f : list) {
+ if (queryFunction(f.get(), query))
+ result.append(f);
+ }
+ return result;
+}
+
+AbstractMetaFunctionCPtr AbstractMetaClass::queryFirstFunction(const AbstractMetaFunctionCList &list,
+ FunctionQueryOptions query)
+{
+ for (const auto &f : list) {
+ if (queryFunction(f.get(), query))
+ return f;
+ }
+ return {};
+}
+
+AbstractMetaFunctionCList AbstractMetaClass::queryFunctions(FunctionQueryOptions query) const
+{
+ return AbstractMetaClass::queryFunctionList(d->m_functions, query);
+}
+
+bool AbstractMetaClass::hasSignals() const
+{
+ return queryFirstFunction(d->m_functions,
+ FunctionQueryOption::Signals
+ | FunctionQueryOption::Visible
+ | FunctionQueryOption::NotRemoved) != nullptr;
+}
+
+AbstractMetaFunctionCList AbstractMetaClass::cppSignalFunctions() const
+{
+ return queryFunctions(FunctionQueryOption::Signals
+ | FunctionQueryOption::Visible
+ | FunctionQueryOption::NotRemoved);
+}
+
+std::optional<AbstractMetaField>
+ AbstractMetaClass::findField(QStringView name) const
+{
+ return AbstractMetaField::find(d->m_fields, name);
+}
+
+const AbstractMetaEnumList &AbstractMetaClass::enums() const
+{
+ return d->m_enums;
+}
+
+AbstractMetaEnumList &AbstractMetaClass::enums()
+{
+ return d->m_enums;
+}
+
+void AbstractMetaClass::setEnums(const AbstractMetaEnumList &enums)
+{
+ d->m_enums = enums;
+}
+
+void AbstractMetaClass::addEnum(const AbstractMetaEnum &e)
+{
+ d->m_enums << e;
+}
+
+std::optional<AbstractMetaEnum>
+ AbstractMetaClass::findEnum(const QString &enumName) const
+{
+ for (const auto &e : d->m_enums) {
+ if (e.name() == enumName)
+ return e;
+ }
+ return {};
+}
+
+/*! Recursively searches for the enum value named \a enumValueName in
+ this class and its superclasses and interfaces.
+*/
+std::optional<AbstractMetaEnumValue>
+ AbstractMetaClass::findEnumValue(const QString &enumValueName) const
+{
+ for (const AbstractMetaEnum &e : std::as_const(d->m_enums)) {
+ auto v = e.findEnumValue(enumValueName);
+ if (v.has_value())
+ return v;
+ }
+ if (baseClass())
+ return baseClass()->findEnumValue(enumValueName);
+
+ return {};
+}
+
+void AbstractMetaClass::getEnumsToBeGenerated(AbstractMetaEnumList *enumList) const
+{
+ for (const AbstractMetaEnum &metaEnum : d->m_enums) {
+ if (!metaEnum.isPrivate() && metaEnum.typeEntry()->generateCode())
+ enumList->append(metaEnum);
+ }
+}
+
+void AbstractMetaClass::getEnumsFromInvisibleNamespacesToBeGenerated(AbstractMetaEnumList *enumList) const
+{
+ if (isNamespace()) {
+ invisibleNamespaceRecursion([enumList](const AbstractMetaClassCPtr &c) {
+ c->getEnumsToBeGenerated(enumList);
+ });
+ }
+}
+
+void AbstractMetaClass::getFunctionsFromInvisibleNamespacesToBeGenerated(AbstractMetaFunctionCList *funcList) const
+{
+ if (isNamespace()) {
+ invisibleNamespaceRecursion([funcList](const AbstractMetaClassCPtr &c) {
+ funcList->append(c->functions());
+ });
+ }
+}
+
+QString AbstractMetaClass::fullName() const
+{
+ return package() + u'.' + d->m_typeEntry->targetLangName();
+}
+
+static void addExtraIncludeForType(const AbstractMetaClassPtr &metaClass,
+ const AbstractMetaType &type)
+{
+
+ Q_ASSERT(metaClass);
+ const auto entry = type.typeEntry();
+
+ if (entry && entry->include().isValid()) {
+ const auto class_entry = metaClass->typeEntry();
+ class_entry->addArgumentInclude(entry->include());
+ }
+
+ if (type.hasInstantiations()) {
+ for (const AbstractMetaType &instantiation : type.instantiations())
+ addExtraIncludeForType(metaClass, instantiation);
+ }
+}
+
+static void addExtraIncludesForFunction(const AbstractMetaClassPtr &metaClass,
+ const AbstractMetaFunctionCPtr &meta_function)
+{
+ Q_ASSERT(metaClass);
+ Q_ASSERT(meta_function);
+ addExtraIncludeForType(metaClass, meta_function->type());
+
+ const AbstractMetaArgumentList &arguments = meta_function->arguments();
+ for (const AbstractMetaArgument &argument : arguments) {
+ const auto &type = argument.type();
+ addExtraIncludeForType(metaClass, type);
+ if (argument.modifiedType() != type)
+ addExtraIncludeForType(metaClass, argument.modifiedType());
+ }
+}
+
+static bool addSuperFunction(const AbstractMetaFunctionCPtr &f)
+{
+ switch (f->functionType()) {
+ case AbstractMetaFunction::ConstructorFunction:
+ case AbstractMetaFunction::CopyConstructorFunction:
+ case AbstractMetaFunction::MoveConstructorFunction:
+ case AbstractMetaFunction::AssignmentOperatorFunction:
+ case AbstractMetaFunction::MoveAssignmentOperatorFunction:
+ case AbstractMetaFunction::DestructorFunction:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+// Add constructors imported via "using" from the base classes. This is not
+// needed for normal hidden inherited member functions since we generate a
+// cast to the base class to call them into binding code.
+void AbstractMetaClassPrivate::addUsingConstructors(const AbstractMetaClassPtr &q)
+{
+ // Restricted to the non-constructor case currently to avoid
+ // having to compare the parameter lists of existing constructors.
+ if (m_baseClasses.isEmpty() || m_usingMembers.isEmpty()
+ || hasConstructors()) {
+ return;
+ }
+
+ for (const auto &superClass : m_baseClasses) {
+ // Find any "using base-constructor" directives
+ if (isUsingMember(superClass, superClass->name(), Access::Protected)) {
+ // Add to derived class with parameter lists.
+ const auto ctors = superClass->queryFunctions(FunctionQueryOption::Constructors);
+ for (const auto &ctor : ctors) {
+ if (!ctor->isPrivate()) {
+ addConstructor(AbstractMetaFunction::ConstructorFunction,
+ ctor->access(), ctor->arguments(), q);
+ }
+ }
+ }
+ }
+}
+
+static inline bool isSignal(const AbstractMetaFunctionCPtr &f)
+{
+ return f->isSignal();
+}
+
+void AbstractMetaClass::fixFunctions(const AbstractMetaClassPtr &klass)
+{
+ auto *d = klass->d.data();
+ if (d->m_functionsFixed)
+ return;
+
+ d->m_functionsFixed = true;
+
+ AbstractMetaFunctionCList funcs = klass->functions();
+ AbstractMetaFunctionCList nonRemovedFuncs;
+ nonRemovedFuncs.reserve(funcs.size());
+
+ d->addUsingConstructors(klass);
+
+ for (const auto &f : std::as_const(funcs)) {
+ // Fishy: Setting up of implementing/declaring/base classes changes
+ // the applicable modifications; clear cached ones.
+ std::const_pointer_cast<AbstractMetaFunction>(f)->clearModificationsCache();
+ if (!f->isModifiedRemoved())
+ nonRemovedFuncs.append(f);
+ }
+
+ for (const auto &superClassC : d->m_baseClasses) {
+ for (const auto &pof : superClassC->userAddedPythonOverrides()) {
+ auto *clonedPof = pof->copy();
+ clonedPof->setOwnerClass(klass);
+ d->m_userAddedPythonOverrides.append(AbstractMetaFunctionCPtr{clonedPof});
+ }
+
+ auto superClass = std::const_pointer_cast<AbstractMetaClass>(superClassC);
+ AbstractMetaClass::fixFunctions(superClass);
+ // Since we always traverse the complete hierarchy we are only
+ // interrested in what each super class implements, not what
+ // we may have propagated from their base classes again.
+ AbstractMetaFunctionCList superFuncs;
+ superFuncs = superClass->queryFunctions(FunctionQueryOption::ClassImplements);
+ // We are not interested in signals as no bindings are generated for them;
+ // they cause documentation warnings.
+ superFuncs.erase(std::remove_if(superFuncs.begin(), superFuncs.end(), isSignal),
+ superFuncs.end());
+ const auto virtuals = superClass->queryFunctions(FunctionQueryOption::VirtualInCppFunctions);
+ superFuncs += virtuals;
+
+ QSet<AbstractMetaFunctionCPtr> funcsToAdd;
+ for (const auto &sf : std::as_const(superFuncs)) {
+ if (sf->isModifiedRemoved())
+ continue;
+
+ // skip functions added in base classes
+ if (sf->isUserAdded() && sf->declaringClass() != klass)
+ continue;
+
+ // Skip base class comparison operators declared as members (free
+ // operators are added later by traverseOperatorFunction().
+ if (sf->isComparisonOperator())
+ continue;
+
+ // we generally don't care about private functions, but we have to get the ones that are
+ // virtual in case they override abstract functions.
+ bool add = addSuperFunction(sf);
+ for (const auto &cf : std::as_const(nonRemovedFuncs)) {
+ AbstractMetaFunctionPtr f(std::const_pointer_cast<AbstractMetaFunction>(cf));
+ const AbstractMetaFunction::CompareResult cmp = cf->compareTo(sf.get());
+
+ if (cmp & AbstractMetaFunction::EqualModifiedName) {
+ add = false;
+ if (cmp & AbstractMetaFunction::EqualArguments) {
+ // Set "override" in case it was not spelled out (since it
+ // is then not detected by clang parsing).
+ const auto attributes = cf->cppAttributes();
+ if (attributes.testFlag(FunctionAttribute::Virtual)
+ && !attributes.testFlag(FunctionAttribute::Override)
+ && !attributes.testFlag(FunctionAttribute::Final)) {
+ f->setCppAttribute(FunctionAttribute::Override);
+ }
+
+ if (f->access() != sf->access()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgFunctionVisibilityModified(klass, f.get())));
+#if 0
+ // If new visibility is private, we can't
+ // do anything. If it isn't, then we
+ // prefer the parent class's visibility
+ // setting for the function.
+ if (!f->isPrivate() && !sf->isPrivate())
+ f->setVisibility(sf->visibility());
+#endif
+ // Private overrides of abstract functions have to go into the class or
+ // the subclasses will not compile as non-abstract classes.
+ // But they don't need to be implemented, since they can never be called.
+ if (f->isPrivate())
+ f->setFunctionType(AbstractMetaFunction::EmptyFunction);
+ }
+
+ // Set the class which first declares this function, afawk
+ f->setDeclaringClass(sf->declaringClass());
+ }
+
+ if (cmp & AbstractMetaFunction::EqualDefaultValueOverload) {
+ AbstractMetaArgumentList arguments;
+ if (f->arguments().size() < sf->arguments().size())
+ arguments = sf->arguments();
+ else
+ arguments = f->arguments();
+ //TODO: fix this
+ //for (int i=0; i<arguments.size(); ++i)
+ // arguments[i]->setDefaultValueExpression("<#>" + QString());
+ }
+
+
+ // Otherwise we have function shadowing and we can
+ // skip the thing...
+ } else if (cmp & AbstractMetaFunction::EqualName && !sf->isSignal()) {
+ // In the case of function shadowing where the function name has been altered to
+ // avoid conflict, we don't copy in the original.
+ add = false;
+ }
+ }
+
+ if (add)
+ funcsToAdd << sf;
+ }
+
+ for (const auto &f : std::as_const(funcsToAdd)) {
+ AbstractMetaFunction *copy = f->copy();
+ (*copy) += AbstractMetaFunction::AddedMethod;
+ funcs.append(AbstractMetaFunctionCPtr(copy));
+ }
+ }
+
+ bool hasPrivateConstructors = false;
+ bool hasPublicConstructors = false;
+ // Apply modifications after the declaring class has been set
+ for (const auto &func : std::as_const(funcs)) {
+ auto ncFunc = std::const_pointer_cast<AbstractMetaFunction>(func);
+ for (const auto &mod : func->modifications(klass)) {
+ if (mod.isRenameModifier())
+ ncFunc->setName(mod.renamedToName());
+ }
+ ncFunc->applyTypeModifications();
+
+ // Make sure class is abstract if one of the functions is
+ if (func->isAbstract()) {
+ (*klass) += AbstractMetaClass::Abstract;
+ (*klass) -= AbstractMetaClass::FinalInTargetLang;
+ }
+
+ if (func->isConstructor()) {
+ if (func->isPrivate())
+ hasPrivateConstructors = true;
+ else
+ hasPublicConstructors = true;
+ }
+
+
+
+ // Make sure that we include files for all classes that are in use
+ addExtraIncludesForFunction(klass, func);
+ }
+
+ if (hasPrivateConstructors && !hasPublicConstructors) {
+ (*klass) += AbstractMetaClass::Abstract;
+ (*klass) -= AbstractMetaClass::FinalInTargetLang;
+ }
+
+ d->setFunctions(funcs, klass);
+}
+
+bool AbstractMetaClass::needsInheritanceSetup() const
+{
+ if (d->m_typeEntry != nullptr) {
+ switch (d->m_typeEntry->type()) {
+ case TypeEntry::NamespaceType:
+ case TypeEntry::SmartPointerType:
+ case TypeEntry::ContainerType:
+ return false;
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+void AbstractMetaClass::setInheritanceDone(bool b)
+{
+ d->m_inheritanceDone = b;
+}
+
+bool AbstractMetaClass::inheritanceDone() const
+{
+ return d->m_inheritanceDone;
+}
+
+/*******************************************************************************
+ * Other stuff...
+ */
+
+std::optional<AbstractMetaEnumValue>
+ AbstractMetaClass::findEnumValue(const AbstractMetaClassList &classes,
+ const QString &name)
+{
+ const auto lst = QStringView{name}.split(u"::");
+
+ if (lst.size() > 1) {
+ const auto &prefixName = lst.at(0);
+ const auto &enumName = lst.at(1);
+ if (auto cl = findClass(classes, prefixName))
+ return cl->findEnumValue(enumName.toString());
+ }
+
+ for (const auto &metaClass : classes) {
+ auto enumValue = metaClass->findEnumValue(name);
+ if (enumValue.has_value())
+ return enumValue;
+ }
+
+ qCWarning(lcShiboken, "no matching enum '%s'", qPrintable(name));
+ return {};
+}
+
+/// Searches the list after a class that matches \a name; either as C++,
+/// Target language base name or complete Target language package.class name.
+
+template <class It>
+static It findClassHelper(It begin, It end, QAnyStringView name)
+{
+ if (name.isEmpty() || begin == end)
+ return end;
+
+ if (asv_contains(name,'.')) { // Search target lang name
+ for (auto it = begin; it != end; ++it) {
+ if ((*it)->fullName() == name)
+ return it;
+ }
+ return end;
+ }
+
+ for (auto it = begin; it != end; ++it) {
+ if ((*it)->qualifiedCppName() == name)
+ return it;
+ }
+
+ if (asv_contains(name, "::")) // Qualified, cannot possibly match name
+ return end;
+
+ for (auto it = begin; it != end; ++it) {
+ if ((*it)->name() == name)
+ return it;
+ }
+
+ return end;
+}
+
+AbstractMetaClassPtr AbstractMetaClass::findClass(const AbstractMetaClassList &classes,
+ QAnyStringView name)
+{
+ auto it =findClassHelper(classes.cbegin(), classes.cend(), name);
+ return it != classes.cend() ? *it : nullptr;
+}
+
+AbstractMetaClassCPtr AbstractMetaClass::findClass(const AbstractMetaClassCList &classes,
+ QAnyStringView name)
+{
+ auto it = findClassHelper(classes.cbegin(), classes.cend(), name);
+ return it != classes.cend() ? *it : nullptr;
+}
+
+AbstractMetaClassPtr AbstractMetaClass::findClass(const AbstractMetaClassList &classes,
+ const TypeEntryCPtr &typeEntry)
+{
+ for (AbstractMetaClassPtr c : classes) {
+ if (c->typeEntry() == typeEntry)
+ return c;
+ }
+ return nullptr;
+}
+
+AbstractMetaClassCPtr AbstractMetaClass::findClass(const AbstractMetaClassCList &classes,
+ const TypeEntryCPtr &typeEntry)
+{
+ for (auto c : classes) {
+ if (c->typeEntry() == typeEntry)
+ return c;
+ }
+ return nullptr;
+}
+
+/// Returns true if this class is a subclass of the given class
+bool inheritsFrom(const AbstractMetaClassCPtr &c, const AbstractMetaClassCPtr &cls)
+{
+ Q_ASSERT(cls != nullptr);
+
+ if (c == cls || c->templateBaseClass() == cls)
+ return true;
+
+ return bool(recurseClassHierarchy(c, [cls](const AbstractMetaClassCPtr &c) {
+ return cls.get() == c.get();
+ }));
+}
+
+bool inheritsFrom(const AbstractMetaClassCPtr &c, QAnyStringView name)
+{
+ if (c->qualifiedCppName() == name)
+ return true;
+
+ if (c->templateBaseClass() != nullptr
+ && c->templateBaseClass()->qualifiedCppName() == name) {
+ return true;
+ }
+
+ return bool(recurseClassHierarchy(c, [&name](const AbstractMetaClassCPtr &c) {
+ return c->qualifiedCppName() == name;
+ }));
+}
+
+AbstractMetaClassCPtr findBaseClass(const AbstractMetaClassCPtr &c,
+ const QString &qualifiedName)
+{
+ auto tp = c->templateBaseClass();
+ if (tp && tp->qualifiedCppName() == qualifiedName)
+ return tp;
+
+ return recurseClassHierarchy(c, [&qualifiedName](const AbstractMetaClassCPtr &c) {
+ return c->qualifiedCppName() == qualifiedName;
+ });
+}
+
+// Query functions for generators
+bool AbstractMetaClass::isObjectType() const
+{
+ return d->m_typeEntry->isObject();
+}
+
+bool AbstractMetaClass::isCopyable() const
+{
+ if (isNamespace() || d->m_typeEntry->isObject())
+ return false;
+ auto copyable = d->m_typeEntry->copyable();
+ return copyable == ComplexTypeEntry::CopyableSet
+ || (copyable == ComplexTypeEntry::Unknown && isCopyConstructible());
+}
+
+bool AbstractMetaClass::isValueTypeWithCopyConstructorOnly() const
+{
+ return d->m_valueTypeWithCopyConstructorOnly;
+}
+
+void AbstractMetaClass::setValueTypeWithCopyConstructorOnly(bool v)
+{
+ d->m_valueTypeWithCopyConstructorOnly = v;
+}
+
+bool AbstractMetaClass::determineValueTypeWithCopyConstructorOnly(const AbstractMetaClassCPtr &c,
+ bool avoidProtectedHack)
+{
+
+ if (!c->typeEntry()->isValue())
+ return false;
+ if (c->attributes().testFlag(AbstractMetaClass::HasRejectedDefaultConstructor))
+ return false;
+ const auto ctors = c->queryFunctions(FunctionQueryOption::AnyConstructor);
+ bool copyConstructorFound = false;
+ for (const auto &ctor : ctors) {
+ switch (ctor->functionType()) {
+ case AbstractMetaFunction::ConstructorFunction:
+ if (!ctor->isPrivate() && (ctor->isPublic() || !avoidProtectedHack))
+ return false;
+ break;
+ case AbstractMetaFunction::CopyConstructorFunction:
+ copyConstructorFound = true;
+ break;
+ case AbstractMetaFunction::MoveConstructorFunction:
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+ }
+ return copyConstructorFound;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+void AbstractMetaClass::format(QDebug &debug) const
+{
+ if (debug.verbosity() > 2)
+ debug << static_cast<const void *>(this) << ", ";
+ debug << '"' << qualifiedCppName();
+ if (const auto count = d->m_templateArgs.size()) {
+ for (qsizetype i = 0; i < count; ++i)
+ debug << (i ? ',' : '<') << d->m_templateArgs.at(i)->qualifiedCppName();
+ debug << '>';
+ }
+ debug << '"';
+ if (isNamespace())
+ debug << " [namespace]";
+ if (attributes().testFlag(AbstractMetaClass::FinalCppClass))
+ debug << " [final]";
+ if (attributes().testFlag(AbstractMetaClass::Deprecated))
+ debug << " [deprecated]";
+
+ if (d->m_hasPrivateConstructor)
+ debug << " [private constructor]";
+ if (d->m_hasDeletedDefaultConstructor)
+ debug << " [deleted default constructor]";
+ if (d->m_hasDeletedCopyConstructor)
+ debug << " [deleted copy constructor]";
+ if (d->m_hasPrivateDestructor)
+ debug << " [private destructor]";
+ if (d->m_hasProtectedDestructor)
+ debug << " [protected destructor]";
+ if (d->m_hasVirtualDestructor)
+ debug << " [virtual destructor]";
+ if (d->m_valueTypeWithCopyConstructorOnly)
+ debug << " [value type with copy constructor only]";
+
+ if (!d->m_baseClasses.isEmpty()) {
+ debug << ", inherits ";
+ for (const auto &b : d->m_baseClasses)
+ debug << " \"" << b->name() << '"';
+ }
+
+ if (const qsizetype count = d->m_usingMembers.size()) {
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ debug << ", ";
+ debug << d->m_usingMembers.at(i);
+ }
+ }
+
+ if (auto templateBase = templateBaseClass()) {
+ const auto &instantiatedTypes = templateBaseClassInstantiations();
+ debug << ", instantiates \"" << templateBase->name();
+ for (qsizetype i = 0, count = instantiatedTypes.size(); i < count; ++i)
+ debug << (i ? ',' : '<') << instantiatedTypes.at(i).name();
+ debug << ">\"";
+ }
+ if (const auto count = d->m_propertySpecs.size()) {
+ debug << ", properties (" << count << "): [";
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ debug << ", ";
+ d->m_propertySpecs.at(i).formatDebug(debug);
+ }
+ debug << ']';
+ }
+}
+
+void AbstractMetaClass::formatMembers(QDebug &debug) const
+{
+ if (!d->m_enums.isEmpty())
+ debug << ", enums[" << d->m_enums.size() << "]=" << d->m_enums;
+ if (!d->m_functions.isEmpty()) {
+ const auto count = d->m_functions.size();
+ debug << ", functions=[" << count << "](";
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ debug << ", ";
+ d->m_functions.at(i)->formatDebugBrief(debug);
+ }
+ debug << ')';
+ }
+ if (const auto count = d->m_fields.size()) {
+ debug << ", fields=[" << count << "](";
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ debug << ", ";
+ d->m_fields.at(i).formatDebug(debug);
+ }
+ debug << ')';
+ }
+}
+
+SourceLocation AbstractMetaClass::sourceLocation() const
+{
+ return d->m_sourceLocation;
+}
+
+void AbstractMetaClass::setSourceLocation(const SourceLocation &sourceLocation)
+{
+ d->m_sourceLocation = sourceLocation;
+}
+
+AbstractMetaClassCList allBaseClasses(const AbstractMetaClassCPtr metaClass)
+{
+ AbstractMetaClassCList result;
+ recurseClassHierarchy(metaClass, [&result] (const AbstractMetaClassCPtr &c) {
+ if (!result.contains(c))
+ result.append(c);
+ return false;
+ });
+ result.removeFirst(); // remove self
+ return result;
+}
+
+QDebug operator<<(QDebug debug, const UsingMember &d)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "UsingMember(" << d.access << ' '
+ << d.baseClass->qualifiedCppName() << "::" << d.memberName << ')';
+ return debug;
+}
+
+void formatMetaClass(QDebug &ddebug, const AbstractMetaClass *ac)
+{
+ QDebugStateSaver saver(ddebug);
+ ddebug.noquote();
+ ddebug.nospace();
+ ddebug << "AbstractMetaClass(";
+ if (ac != nullptr) {
+ ac->format(ddebug);
+ if (ddebug.verbosity() > 2)
+ ac->formatMembers(ddebug);
+ } else {
+ ddebug << '0';
+ }
+ ddebug << ')';
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaClassCPtr &ac)
+{
+ formatMetaClass(d, ac.get());
+ return d;
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaClassPtr &ac)
+{
+ formatMetaClass(d, ac.get());
+ return d;
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaClass *ac)
+{
+ formatMetaClass(d, ac);
+ return d;
+}
+
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.h b/sources/shiboken6/ApiExtractor/abstractmetalang.h
new file mode 100644
index 000000000..3dc876690
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang.h
@@ -0,0 +1,393 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETALANG_H
+#define ABSTRACTMETALANG_H
+
+#include "abstractmetalang_enums.h"
+#include "abstractmetalang_typedefs.h"
+#include "enclosingclassmixin.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/qobjectdefs.h>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QStringList>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+enum class Access;
+class AbstractMetaClassPrivate;
+class ComplexTypeEntry;
+class Documentation;
+class EnumTypeEntry;
+class QPropertySpec;
+class SourceLocation;
+struct UsingMember;
+
+class AbstractMetaClass : public EnclosingClassMixin
+{
+ Q_GADGET
+public:
+ Q_DISABLE_COPY_MOVE(AbstractMetaClass)
+
+ enum CppWrapperFlag {
+ NoCppWrapper = 0x0,
+ CppProtectedHackWrapper = 0x1,// Make protected functions accessible
+ CppVirtualMethodWrapper = 0x2 // Need C++ wrapper for calling Python overrides
+ };
+ Q_DECLARE_FLAGS(CppWrapper, CppWrapperFlag)
+
+ enum Attribute {
+ None = 0x00000000,
+
+ Abstract = 0x00000001,
+ FinalInTargetLang = 0x00000002,
+
+ HasRejectedConstructor = 0x00000010,
+ HasRejectedDefaultConstructor = 0x00000020,
+
+ FinalCppClass = 0x00000100,
+ Deprecated = 0x00000200,
+ Struct = 0x00000400
+ };
+ Q_DECLARE_FLAGS(Attributes, Attribute)
+ Q_FLAG(Attribute)
+
+ Attributes attributes() const;
+ void setAttributes(Attributes attributes);
+
+ void operator+=(Attribute attribute);
+ void operator-=(Attribute attribute);
+
+ bool isFinalInTargetLang() const;
+ bool isAbstract() const;
+
+ AbstractMetaClass();
+ ~AbstractMetaClass();
+
+ const AbstractMetaFunctionCList &functions() const;
+ const AbstractMetaFunctionCList &userAddedPythonOverrides() const;
+ void setFunctions(const AbstractMetaFunctionCList &functions);
+ static void addFunction(const AbstractMetaClassPtr &klass,
+ const AbstractMetaFunctionCPtr &function);
+ bool hasFunction(const QString &str) const;
+ AbstractMetaFunctionCPtr findFunction(QAnyStringView functionName) const;
+ AbstractMetaFunctionCList findFunctions(QAnyStringView functionName) const;
+ AbstractMetaFunctionCPtr findOperatorBool() const;
+ // Find a Qt-style isNull() method suitable for nb_bool
+ AbstractMetaFunctionCPtr findQtIsNullMethod() const;
+ bool hasSignal(const AbstractMetaFunction *f) const;
+
+ bool hasConstructors() const;
+ AbstractMetaFunctionCPtr copyConstructor() const;
+ bool hasCopyConstructor() const;
+ bool hasPrivateCopyConstructor() const;
+
+ static void addDefaultConstructor(const AbstractMetaClassPtr &klass);
+ static void addDefaultCopyConstructor(const AbstractMetaClassPtr &klass);
+
+ bool hasNonPrivateConstructor() const;
+ void setHasNonPrivateConstructor(bool value);
+
+ bool hasPrivateConstructor() const;
+ void setHasPrivateConstructor(bool value);
+
+ bool hasDeletedDefaultConstructor() const;
+ void setHasDeletedDefaultConstructor(bool value);
+
+ bool hasDeletedCopyConstructor() const;
+ void setHasDeletedCopyConstructor(bool value);
+
+ bool hasPrivateDestructor() const;
+ void setHasPrivateDestructor(bool value);
+
+ bool hasProtectedDestructor() const;
+ void setHasProtectedDestructor(bool value);
+
+ bool hasVirtualDestructor() const;
+ void setHasVirtualDestructor(bool value);
+
+ bool isDefaultConstructible() const;
+ bool isImplicitlyDefaultConstructible() const;
+ bool canAddDefaultConstructor() const;
+
+ bool isCopyConstructible() const;
+ bool isImplicitlyCopyConstructible() const;
+ bool canAddDefaultCopyConstructor() const;
+
+ static void addSynthesizedComparisonOperators(const AbstractMetaClassPtr &c);
+
+ bool generateExceptionHandling() const;
+
+ CppWrapper cppWrapper() const;
+
+ const UsingMembers &usingMembers() const;
+ void addUsingMember(const UsingMember &um);
+ bool isUsingMember(const AbstractMetaClassCPtr &c, const QString &memberName,
+ Access minimumAccess) const;
+ bool hasUsingMemberFor(const QString &memberName) const;
+
+ AbstractMetaFunctionCList queryFunctionsByName(const QString &name) const;
+ static bool queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query);
+ static AbstractMetaFunctionCList queryFunctionList(const AbstractMetaFunctionCList &list,
+ FunctionQueryOptions query);
+ static AbstractMetaFunctionCPtr queryFirstFunction(const AbstractMetaFunctionCList &list,
+ FunctionQueryOptions query);
+
+ AbstractMetaFunctionCList queryFunctions(FunctionQueryOptions query) const;
+ AbstractMetaFunctionCList functionsInTargetLang() const;
+ AbstractMetaFunctionCList cppSignalFunctions() const;
+ AbstractMetaFunctionCList implicitConversions() const;
+
+ /**
+ * Retrieves all class' operator overloads that meet
+ * query criteria defined with the OperatorQueryOption
+ * enum.
+ * /param query composition of OperatorQueryOption enum values
+ * /return list of operator overload methods that meet the
+ * query criteria
+ */
+ AbstractMetaFunctionCList operatorOverloads(OperatorQueryOptions query) const;
+
+ bool hasArithmeticOperatorOverload() const;
+ bool hasIncDecrementOperatorOverload() const;
+ bool hasBitwiseOperatorOverload() const;
+ bool hasComparisonOperatorOverload() const;
+ bool hasLogicalOperatorOverload() const;
+
+ const AbstractMetaFieldList &fields() const;
+ AbstractMetaFieldList &fields();
+ void setFields(const AbstractMetaFieldList &fields);
+ void addField(const AbstractMetaField &field);
+ bool hasStaticFields() const;
+
+ std::optional<AbstractMetaField> findField(QStringView name) const;
+
+ const AbstractMetaEnumList &enums() const;
+ AbstractMetaEnumList &enums();
+ void setEnums(const AbstractMetaEnumList &enums);
+ void addEnum(const AbstractMetaEnum &e);
+
+ std::optional<AbstractMetaEnum> findEnum(const QString &enumName) const;
+ std::optional<AbstractMetaEnumValue> findEnumValue(const QString &enumName) const;
+ void getEnumsToBeGenerated(AbstractMetaEnumList *enumList) const;
+ void getEnumsFromInvisibleNamespacesToBeGenerated(AbstractMetaEnumList *enumList) const;
+
+ void getFunctionsFromInvisibleNamespacesToBeGenerated(AbstractMetaFunctionCList *funcList) const;
+
+ QString fullName() const;
+
+ /**
+ * Retrieves the class name without any namespace/scope information.
+ * /return the class name without scope information
+ */
+ QString name() const;
+
+ const Documentation &documentation() const;
+ void setDocumentation(const Documentation& doc);
+
+ QString baseClassName() const;
+
+ AbstractMetaClassCPtr defaultSuperclass() const; // Attribute "default-superclass"
+ void setDefaultSuperclass(const AbstractMetaClassPtr &s);
+
+ AbstractMetaClassCPtr baseClass() const;
+ const AbstractMetaClassCList &baseClasses() const;
+ // base classes including defaultSuperclass
+ AbstractMetaClassCList typeSystemBaseClasses() const;
+ // Recursive list of all base classes including defaultSuperclass
+ AbstractMetaClassCList allTypeSystemAncestors() const;
+
+ void addBaseClass(const AbstractMetaClassCPtr &base_class);
+ void setBaseClass(const AbstractMetaClassCPtr &base_class);
+
+ /**
+ * \return the namespace from another package which this namespace extends.
+ */
+ AbstractMetaClassCPtr extendedNamespace() const;
+ void setExtendedNamespace(const AbstractMetaClassCPtr &e);
+
+ const AbstractMetaClassCList &innerClasses() const;
+ void addInnerClass(const AbstractMetaClassPtr &cl);
+ void setInnerClasses(const AbstractMetaClassCList &innerClasses);
+
+ QString package() const;
+
+ bool isNamespace() const;
+ bool isInvisibleNamespace() const;
+ bool isInlineNamespace() const;
+
+ bool isQtNamespace() const;
+
+ QString qualifiedCppName() const;
+
+ bool hasSignals() const;
+
+ /**
+ * Says if the class that declares or inherits a virtual function.
+ * \return true if the class implements or inherits any virtual methods
+ */
+ bool isPolymorphic() const;
+
+ /**
+ * Tells if this class has one or more fields (member variables) that are protected.
+ * \return true if the class has protected fields.
+ */
+ bool hasProtectedFields() const;
+
+
+ const TypeEntryCList &templateArguments() const;
+ void setTemplateArguments(const TypeEntryCList &);
+
+ // only valid during metabuilder's run
+ const QStringList &baseClassNames() const;
+ void setBaseClassNames(const QStringList &names);
+
+ ComplexTypeEntryCPtr typeEntry() const;
+ ComplexTypeEntryPtr typeEntry();
+ void setTypeEntry(const ComplexTypeEntryPtr &type);
+
+ /// Returns the global hash function as found by the code parser
+ QString hashFunction() const;
+ void setHashFunction(const QString &);
+
+ /// Returns whether the class has a qHash() overload. Currently unused,
+ /// specified in type system.
+ bool hasHashFunction() const;
+
+ const QList<QPropertySpec> &propertySpecs() const;
+ void addPropertySpec(const QPropertySpec &spec);
+ void setPropertyDocumentation(const QString &name, const Documentation &doc);
+
+ // Helpers to search whether a functions is a property setter/getter/reset
+ enum class PropertyFunction
+ {
+ Read,
+ Write,
+ Reset,
+ Notify
+ };
+ struct PropertyFunctionSearchResult
+ {
+ qsizetype index;
+ PropertyFunction function;
+ };
+
+ PropertyFunctionSearchResult searchPropertyFunction(const QString &name) const;
+
+ std::optional<QPropertySpec> propertySpecByName(const QString &name) const;
+
+ /// Returns a list of conversion operators for this class. The conversion
+ /// operators are defined in other classes of the same module.
+ const AbstractMetaFunctionCList &externalConversionOperators() const;
+ /// Adds a converter operator for this class.
+ void addExternalConversionOperator(const AbstractMetaFunctionCPtr &conversionOp);
+ /// Returns true if this class has any converter operators defined elsewhere.
+ bool hasExternalConversionOperators() const;
+
+ void sortFunctions();
+
+ AbstractMetaClassCPtr templateBaseClass() const;
+ void setTemplateBaseClass(const AbstractMetaClassCPtr &cls);
+
+ bool hasTemplateBaseClassInstantiations() const;
+ const AbstractMetaTypeList &templateBaseClassInstantiations() const;
+ void setTemplateBaseClassInstantiations(const AbstractMetaTypeList& instantiations);
+
+ void setTypeDef(bool typeDef);
+ bool isTypeDef() const;
+
+ bool isStream() const;
+ void setStream(bool stream);
+
+ bool hasToStringCapability() const;
+ void setToStringCapability(bool value, uint indirections = 0);
+
+ uint toStringCapabilityIndirections() const;
+
+ bool deleteInMainThread() const;
+
+ // Query functions for generators
+ bool isObjectType() const;
+ bool isCopyable() const;
+ bool isValueTypeWithCopyConstructorOnly() const;
+ void setValueTypeWithCopyConstructorOnly(bool v);
+ static bool determineValueTypeWithCopyConstructorOnly(const AbstractMetaClassCPtr &c,
+ bool avoidProtectedHack);
+
+ static AbstractMetaClassPtr findClass(const AbstractMetaClassList &classes,
+ QAnyStringView name);
+ static AbstractMetaClassCPtr findClass(const AbstractMetaClassCList &classes,
+ QAnyStringView name);
+ static AbstractMetaClassPtr findClass(const AbstractMetaClassList &classes,
+ const TypeEntryCPtr &typeEntry);
+ static AbstractMetaClassCPtr findClass(const AbstractMetaClassCList &classes,
+ const TypeEntryCPtr &typeEntry);
+ AbstractMetaClassCPtr findBaseClass(const QString &qualifiedName) const;
+
+ static std::optional<AbstractMetaEnumValue> findEnumValue(const AbstractMetaClassList &classes,
+ const QString &string);
+
+ SourceLocation sourceLocation() const;
+ void setSourceLocation(const SourceLocation &sourceLocation);
+
+ // For AbstractMetaBuilder
+ static void fixFunctions(const AbstractMetaClassPtr &klass);
+ bool needsInheritanceSetup() const;
+ void setInheritanceDone(bool b);
+ bool inheritanceDone() const;
+
+ template <class Function>
+ void invisibleNamespaceRecursion(Function f) const;
+
+private:
+#ifndef QT_NO_DEBUG_STREAM
+ void format(QDebug &d) const;
+ void formatMembers(QDebug &d) const;
+ friend QDebug operator<<(QDebug d, const AbstractMetaClassCPtr &ac);
+ friend QDebug operator<<(QDebug d, const AbstractMetaClassPtr &ac);
+ friend QDebug operator<<(QDebug d, const AbstractMetaClass *ac);
+ friend void formatMetaClass(QDebug &, const AbstractMetaClass *);
+#endif
+
+ QScopedPointer<AbstractMetaClassPrivate> d;
+};
+
+inline bool AbstractMetaClass::isAbstract() const
+{
+ return attributes().testFlag(Abstract);
+}
+
+template <class Function>
+void AbstractMetaClass::invisibleNamespaceRecursion(Function f) const
+{
+ for (const auto &ic : innerClasses()) {
+ if (ic->isInvisibleNamespace()) {
+ f(ic);
+ ic->invisibleNamespaceRecursion(f);
+ }
+ }
+}
+
+bool inheritsFrom(const AbstractMetaClassCPtr &c, const AbstractMetaClassCPtr &other);
+bool inheritsFrom(const AbstractMetaClassCPtr &c, QAnyStringView name);
+inline bool isQObject(const AbstractMetaClassCPtr &c)
+{
+ return inheritsFrom(c, "QObject");
+}
+
+AbstractMetaClassCPtr findBaseClass(const AbstractMetaClassCPtr &c,
+ const QString &qualifiedName);
+
+/// Return type entry of the base class that declares the parent management
+TypeEntryCPtr parentManagementEntry(const AbstractMetaClassCPtr &klass);
+inline bool hasParentManagement(const AbstractMetaClassCPtr &c)
+{ return bool(parentManagementEntry(c)); }
+
+AbstractMetaClassCList allBaseClasses(const AbstractMetaClassCPtr metaClass);
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaClass::CppWrapper);
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaClass::Attributes);
+
+#endif // ABSTRACTMETALANG_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h b/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h
new file mode 100644
index 000000000..9047c6bcd
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETALANG_ENUMS_H
+#define ABSTRACTMETALANG_ENUMS_H
+
+#include <QtCore/QFlags>
+
+enum class FunctionQueryOption {
+ AnyConstructor = 0x0000001, // Any constructor (copy/move)
+ Constructors = 0x0000002, // Constructors except copy/move
+ CopyConstructor = 0x0000004, // Only copy constructors
+ //Destructors = 0x0000002, // Only destructors. Not included in class.
+ ClassImplements = 0x0000020, // Only functions implemented by the current class
+ StaticFunctions = 0x0000080, // Only static functions
+ Signals = 0x0000100, // Only signals
+ NormalFunctions = 0x0000200, // Only functions that aren't signals
+ Visible = 0x0000400, // Only public and protected functions
+ NonStaticFunctions = 0x0004000, // No static functions
+ Empty = 0x0008000, // Empty overrides of abstract functions
+ Invisible = 0x0010000, // Only private functions
+ VirtualInCppFunctions = 0x0020000, // Only functions that are virtual in C++
+ NotRemoved = 0x0400000, // Only functions that have not been removed
+ OperatorOverloads = 0x2000000, // Only functions that are operator overloads
+ GenerateExceptionHandling = 0x4000000,
+ GetAttroFunction = 0x8000000,
+ SetAttroFunction = 0x10000000
+};
+
+Q_DECLARE_FLAGS(FunctionQueryOptions, FunctionQueryOption)
+Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionQueryOptions)
+
+enum class OperatorQueryOption {
+ ArithmeticOp = 0x01, // Arithmetic: +, -, *, /, %, +=, -=, *=, /=, %=, unary+, unary-
+ IncDecrementOp = 0x02, // ++, --
+ BitwiseOp = 0x04, // Bitwise: <<, <<=, >>, >>=, ~, &, &=, |, |=, ^, ^=
+ ComparisonOp = 0x08, // Comparison: <, <=, >, >=, !=, ==
+ // Comparing to instances of owner class: <, <=, >, >=, !=, ==
+ // (bool operator==(QByteArray,QByteArray) but not bool operator==(QByteArray,const char *)
+ SymmetricalComparisonOp = 0x10,
+ LogicalOp = 0x20, // Logical: !, &&, ||
+ ConversionOp = 0x40, // Conversion: operator [const] TYPE()
+ SubscriptionOp = 0x80, // Subscription: []
+ AssignmentOp = 0x100 // Assignment: =
+};
+
+Q_DECLARE_FLAGS(OperatorQueryOptions, OperatorQueryOption)
+Q_DECLARE_OPERATORS_FOR_FLAGS(OperatorQueryOptions)
+
+#endif // ABSTRACTMETALANG_ENUMS_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang_helpers.h b/sources/shiboken6/ApiExtractor/abstractmetalang_helpers.h
new file mode 100644
index 000000000..2a053ceaf
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang_helpers.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETALANG_HELPERS_H
+#define ABSTRACTMETALANG_HELPERS_H
+
+#include "abstractmetalang_typedefs.h"
+
+template <class MetaClass>
+std::shared_ptr<MetaClass> findByName(const QList<std::shared_ptr<MetaClass> > &haystack,
+ QStringView needle)
+{
+ for (const auto &c : haystack) {
+ if (c->name() == needle)
+ return c;
+ }
+ return {};
+}
+
+// Helper for recursing the base classes of an AbstractMetaClass.
+// Returns the class for which the predicate is true.
+template <class Predicate>
+AbstractMetaClassCPtr recurseClassHierarchy(const AbstractMetaClassCPtr &klass,
+ Predicate pred)
+{
+ if (pred(klass))
+ return klass;
+ for (auto base : klass->baseClasses()) {
+ if (auto r = recurseClassHierarchy(base, pred))
+ return r;
+ }
+ return {};
+}
+
+#endif // ABSTRACTMETALANG_HELPERS_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h b/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h
new file mode 100644
index 000000000..802f549cf
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETALANG_TYPEDEFS_H
+#define ABSTRACTMETALANG_TYPEDEFS_H
+
+#include <QtCore/QList>
+
+#include <memory>
+
+class AbstractMetaClass;
+class AbstractMetaField;
+class AbstractMetaArgument;
+class AbstractMetaEnum;
+class AbstractMetaEnumValue;
+class AbstractMetaFunction;
+class AbstractMetaType;
+struct UsingMember;
+
+using AbstractMetaFunctionPtr = std::shared_ptr<AbstractMetaFunction>;
+using AbstractMetaFunctionCPtr = std::shared_ptr<const AbstractMetaFunction>;
+using AbstractMetaClassPtr = std::shared_ptr<AbstractMetaClass>;
+using AbstractMetaClassCPtr = std::shared_ptr<const AbstractMetaClass>;
+
+using AbstractMetaArgumentList = QList<AbstractMetaArgument>;
+using AbstractMetaClassList = QList<AbstractMetaClassPtr>;
+using AbstractMetaClassCList = QList<AbstractMetaClassCPtr>;
+using AbstractMetaEnumList = QList<AbstractMetaEnum>;
+using AbstractMetaEnumValueList = QList<AbstractMetaEnumValue>;
+using AbstractMetaFieldList = QList<AbstractMetaField>;
+using AbstractMetaFunctionRawPtrList = QList<AbstractMetaFunction *>;
+using AbstractMetaFunctionCList = QList<AbstractMetaFunctionCPtr>;
+using AbstractMetaTypeList = QList<AbstractMetaType>;
+using UsingMembers = QList<UsingMember>;
+
+#endif // ABSTRACTMETALANG_TYPEDEFS_H
diff --git a/sources/shiboken6/ApiExtractor/abstractmetatype.cpp b/sources/shiboken6/ApiExtractor/abstractmetatype.cpp
new file mode 100644
index 000000000..3ec07509d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetatype.cpp
@@ -0,0 +1,1120 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstractmetatype.h"
+#include "abstractmetabuilder.h"
+#include "abstractmetalang.h"
+#include "messages.h"
+#include "typedatabase.h"
+#include "containertypeentry.h"
+#include "enumtypeentry.h"
+#include "flagstypeentry.h"
+
+#include "qtcompat.h"
+#include "typeinfo.h"
+
+#ifndef QT_NO_DEBUG_STREAM
+# include <QtCore/QDebug>
+#endif
+
+#include <QtCore/QHash>
+#include <QtCore/QSharedData>
+#include <QtCore/QStack>
+
+#include <memory>
+
+using namespace Qt::StringLiterals;
+
+using AbstractMetaTypeCPtr = std::shared_ptr<const AbstractMetaType>;
+
+const QSet<QString> &AbstractMetaType::cppFloatTypes()
+{
+ static const QSet<QString> result{u"double"_s, u"float"_s};
+ return result;
+}
+
+const QSet<QString> &AbstractMetaType::cppSignedCharTypes()
+{
+ static const QSet<QString> result{u"char"_s, u"signed char"_s};
+ return result;
+}
+
+const QSet<QString> &AbstractMetaType::cppUnsignedCharTypes()
+{
+ static const QSet<QString> result{u"unsigned char"_s};
+ return result;
+}
+
+const QSet<QString> &AbstractMetaType::cppCharTypes()
+{
+ static const QSet<QString> result = cppSignedCharTypes() | cppUnsignedCharTypes();
+ return result;
+}
+
+const QSet<QString> &AbstractMetaType::cppSignedIntTypes()
+{
+ static QSet<QString> result;
+ if (result.isEmpty()) {
+ result = {u"char"_s, u"signed char"_s, u"short"_s, u"short int"_s,
+ u"signed short"_s, u"signed short int"_s,
+ u"int"_s, u"signed int"_s,
+ u"long"_s, u"long int"_s,
+ u"signed long"_s, u"signed long int"_s,
+ u"long long"_s, u"long long int"_s,
+ u"signed long long int"_s,
+ u"ptrdiff_t"_s};
+ result |= cppSignedCharTypes();
+ }
+ return result;
+}
+
+const QSet<QString> &AbstractMetaType::cppUnsignedIntTypes()
+{
+ static QSet<QString> result;
+ if (result.isEmpty()) {
+ result = {u"unsigned short"_s, u"unsigned short int"_s,
+ u"unsigned"_s, u"unsigned int"_s,
+ u"unsigned long"_s, u"unsigned long int"_s,
+ u"unsigned long long"_s,
+ u"unsigned long long int"_s,
+ u"size_t"_s};
+ result |= cppUnsignedCharTypes();
+ }
+ return result;
+}
+
+const QSet<QString> &AbstractMetaType::cppIntegralTypes()
+{
+ static QSet<QString> result;
+ if (result.isEmpty()) {
+ result |= cppSignedIntTypes();
+ result |= cppUnsignedIntTypes();
+ result.insert(u"bool"_s);
+ }
+ return result;
+}
+
+const QSet<QString> &AbstractMetaType::cppPrimitiveTypes()
+{
+ static QSet<QString> result;
+ if (result.isEmpty()) {
+ result |= cppIntegralTypes();
+ result |= cppFloatTypes();
+ result.insert(u"wchar_t"_s);
+ }
+ return result;
+}
+
+class AbstractMetaTypeData : public QSharedData
+{
+public:
+ AbstractMetaTypeData(const TypeEntryCPtr &t);
+
+ int actualIndirections() const;
+ bool passByConstRef() const;
+ bool passByValue() const;
+ AbstractMetaType::TypeUsagePattern determineUsagePattern() const;
+ bool hasTemplateChildren() const;
+ QString formatSignature(bool minimal) const;
+ QString formatPythonSignature() const;
+ bool isEquivalent(const AbstractMetaTypeData &rhs) const;
+ bool equals(const AbstractMetaTypeData &rhs) const;
+ QStringList instantiationCppSignatures() const;
+
+ template <class Predicate>
+ bool generateOpaqueContainer(Predicate p) const;
+
+ TypeEntryCPtr m_typeEntry;
+ AbstractMetaTypeList m_instantiations;
+ mutable QString m_cachedCppSignature;
+ mutable QString m_cachedPythonSignature;
+ QString m_originalTypeDescription;
+
+ int m_arrayElementCount = -1;
+ AbstractMetaTypeCPtr m_arrayElementType;
+ AbstractMetaTypeCPtr m_originalTemplateType;
+ AbstractMetaTypeCPtr m_viewOn;
+ AbstractMetaType::Indirections m_indirections;
+
+ AbstractMetaType::TypeUsagePattern m_pattern = AbstractMetaType::VoidPattern;
+ uint m_constant : 1;
+ uint m_volatile : 1;
+ uint m_signaturesDirty : 1;
+ uint m_reserved : 29; // unused
+
+ ReferenceType m_referenceType = NoReference;
+ AbstractMetaTypeList m_children;
+};
+
+AbstractMetaTypeData::AbstractMetaTypeData(const TypeEntryCPtr &t) :
+ m_typeEntry(t),
+ m_constant(false),
+ m_volatile(false),
+ m_signaturesDirty(true),
+ m_reserved(0)
+{
+}
+
+QStringList AbstractMetaTypeData::instantiationCppSignatures() const
+{
+ QStringList result;
+ for (const auto &i : m_instantiations)
+ result.append(i.cppSignature());
+ return result;
+}
+
+AbstractMetaType::AbstractMetaType(const TypeEntryCPtr &t) :
+ d(new AbstractMetaTypeData(t))
+{
+ Q_ASSERT(t);
+}
+
+AbstractMetaType::AbstractMetaType()
+{
+ *this = AbstractMetaType::createVoid();
+}
+
+AbstractMetaType &AbstractMetaType::operator=(const AbstractMetaType &) = default;
+
+AbstractMetaType::AbstractMetaType(const AbstractMetaType &rhs) = default;
+
+AbstractMetaType::AbstractMetaType(AbstractMetaType &&) noexcept = default;
+
+AbstractMetaType &AbstractMetaType::operator=(AbstractMetaType &&) noexcept = default;
+
+AbstractMetaType::~AbstractMetaType() = default;
+
+QString AbstractMetaType::package() const
+{
+ return d->m_typeEntry->targetLangPackage();
+}
+
+QString AbstractMetaType::name() const
+{
+ return d->m_typeEntry->targetLangEntryName();
+}
+
+QString AbstractMetaType::fullName() const
+{
+ return d->m_typeEntry->qualifiedTargetLangName();
+}
+
+void AbstractMetaType::setTypeUsagePattern(AbstractMetaType::TypeUsagePattern pattern)
+{
+ if (d->m_pattern != pattern)
+ d->m_pattern = pattern;
+}
+
+AbstractMetaType::TypeUsagePattern AbstractMetaType::typeUsagePattern() const
+{
+ return d->m_pattern;
+}
+
+bool AbstractMetaType::hasInstantiations() const
+{
+ return !d->m_instantiations.isEmpty();
+}
+
+void AbstractMetaType::addInstantiation(const AbstractMetaType &inst)
+{
+ d->m_instantiations << inst;
+}
+
+void AbstractMetaType::setInstantiations(const AbstractMetaTypeList &insts)
+{
+ if (insts != d->m_instantiations)
+ d->m_instantiations = insts;
+}
+
+const AbstractMetaTypeList &AbstractMetaType::instantiations() const
+{
+ return d->m_instantiations;
+}
+
+QStringList AbstractMetaType::instantiationCppSignatures() const
+{
+ return d->instantiationCppSignatures();
+}
+
+// For applying the <array> function argument modification: change into a type
+// where "int *" becomes "int[]".
+bool AbstractMetaType::applyArrayModification(QString *errorMessage)
+{
+
+ if (d->m_pattern == AbstractMetaType::NativePointerAsArrayPattern) {
+ *errorMessage = u"<array> modification already applied."_s;
+ return false;
+ }
+ if (d->m_arrayElementType) {
+ QTextStream(errorMessage) << "The type \"" << cppSignature()
+ << "\" is an array of " << d->m_arrayElementType->name() << '.';
+ return false;
+ }
+ if (d->m_indirections.isEmpty()) {
+ QTextStream(errorMessage) << "The type \"" << cppSignature()
+ << "\" does not have indirections.";
+ return false;
+ }
+ // Element type to be used for ArrayHandle<>, strip constness.
+
+ auto elementType = new AbstractMetaType(*this);
+ auto indir = indirectionsV();
+ indir.pop_front();
+ elementType->setIndirectionsV(indir);
+ elementType->setConstant(false);
+ elementType->setVolatile(false);
+ elementType->decideUsagePattern();
+ d->m_arrayElementType.reset(elementType);
+ d->m_pattern = AbstractMetaType::NativePointerAsArrayPattern;
+ return true;
+}
+
+TypeEntryCPtr AbstractMetaType::typeEntry() const
+{
+ return d->m_typeEntry;
+}
+
+void AbstractMetaType::setTypeEntry(const TypeEntryCPtr &type)
+{
+ if (d->m_typeEntry != type)
+ d->m_typeEntry = type;
+}
+
+void AbstractMetaType::setOriginalTypeDescription(const QString &otd)
+{
+ if (d->m_originalTypeDescription != otd)
+ d->m_originalTypeDescription = otd;
+}
+
+QString AbstractMetaType::originalTypeDescription() const
+{
+ return d->m_originalTypeDescription;
+}
+
+void AbstractMetaType::setOriginalTemplateType(const AbstractMetaType &type)
+{
+ if (!d->m_originalTemplateType || *d->m_originalTemplateType != type)
+ d->m_originalTemplateType.reset(new AbstractMetaType(type));
+}
+
+const AbstractMetaType *AbstractMetaType::originalTemplateType() const
+{
+ return d->m_originalTemplateType.get();
+}
+
+AbstractMetaType AbstractMetaType::getSmartPointerInnerType() const
+{
+ Q_ASSERT(isSmartPointer());
+ Q_ASSERT(!d->m_instantiations.isEmpty());
+ AbstractMetaType innerType = d->m_instantiations.at(0);
+ return innerType;
+}
+
+QString AbstractMetaType::getSmartPointerInnerTypeName() const
+{
+ Q_ASSERT(isSmartPointer());
+ return getSmartPointerInnerType().name();
+}
+
+AbstractMetaTypeList AbstractMetaType::nestedArrayTypes() const
+{
+ AbstractMetaTypeList result;
+ switch (d->m_pattern) {
+ case ArrayPattern:
+ for (AbstractMetaType t = *this; t.typeUsagePattern() == ArrayPattern; ) {
+ const AbstractMetaType *elt = t.arrayElementType();
+ result.append(*elt);
+ t = *elt;
+ }
+ break;
+ case NativePointerAsArrayPattern:
+ result.append(*d->m_arrayElementType.get());
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+bool AbstractMetaTypeData::passByConstRef() const
+{
+ return m_constant && m_referenceType == LValueReference && m_indirections.isEmpty();
+}
+
+bool AbstractMetaType::passByConstRef() const
+{
+ return d->passByConstRef();
+}
+
+bool AbstractMetaTypeData::passByValue() const
+{
+ return m_referenceType == NoReference && m_indirections.isEmpty();
+}
+
+bool AbstractMetaType::passByValue() const
+{
+ return d->passByValue();
+}
+
+bool AbstractMetaType::useStdMove() const
+{
+ return (isUniquePointer() && d->passByValue())
+ || d->m_referenceType == RValueReference;
+}
+
+ReferenceType AbstractMetaType::referenceType() const
+{
+ return d->m_referenceType;
+}
+
+void AbstractMetaType::setReferenceType(ReferenceType ref)
+{
+ if (d->m_referenceType != ref) {
+ d->m_referenceType = ref;
+ d->m_signaturesDirty = true;
+ }
+}
+
+int AbstractMetaTypeData::actualIndirections() const
+{
+ return m_indirections.size() + (m_referenceType == LValueReference ? 1 : 0);
+}
+
+int AbstractMetaType::actualIndirections() const
+{
+ return d->actualIndirections();
+}
+
+AbstractMetaType::Indirections AbstractMetaType::indirectionsV() const
+{
+ return d->m_indirections;
+}
+
+void AbstractMetaType::setIndirectionsV(const AbstractMetaType::Indirections &i)
+{
+ if (d->m_indirections != i) {
+ d->m_indirections = i;
+ d->m_signaturesDirty = true;
+ }
+}
+
+void AbstractMetaType::clearIndirections()
+{
+ if (!d->m_indirections.isEmpty()) {
+ d->m_indirections.clear();
+ d->m_signaturesDirty = true;
+ }
+}
+
+int AbstractMetaType::indirections() const
+{
+ return d->m_indirections.size();
+}
+
+void AbstractMetaType::setIndirections(int indirections)
+{
+ const Indirections newValue(indirections, Indirection::Pointer);
+ if (d->m_indirections != newValue) {
+ d->m_indirections = newValue;
+ d->m_signaturesDirty = true;
+ }
+}
+
+void AbstractMetaType::addIndirection(Indirection i)
+{
+ d->m_indirections.append(i);
+}
+
+void AbstractMetaType::setArrayElementCount(int n)
+{
+ if (d->m_arrayElementCount != n) {
+ d->m_arrayElementCount = n;
+ d->m_signaturesDirty = true;
+ }
+}
+
+int AbstractMetaType::arrayElementCount() const
+{
+ return d->m_arrayElementCount;
+}
+
+const AbstractMetaType *AbstractMetaType::arrayElementType() const
+{
+ return d->m_arrayElementType.get();
+}
+
+void AbstractMetaType::setArrayElementType(const AbstractMetaType &t)
+{
+ if (!d->m_arrayElementType || *d->m_arrayElementType != t) {
+ d->m_arrayElementType.reset(new AbstractMetaType(t));
+ d->m_signaturesDirty = true;
+ }
+}
+
+AbstractMetaType AbstractMetaType::plainType() const
+{
+ AbstractMetaType result = *this;
+ result.clearIndirections();
+ result.setReferenceType(NoReference);
+ result.setConstant(false);
+ result.setVolatile(false);
+ result.decideUsagePattern();
+ return result;
+}
+
+QString AbstractMetaType::cppSignature() const
+{
+ const AbstractMetaTypeData *cd = d.constData();
+ if (cd->m_cachedCppSignature.isEmpty() || cd->m_signaturesDirty)
+ cd->m_cachedCppSignature = formatSignature(false);
+ return cd->m_cachedCppSignature;
+}
+
+QString AbstractMetaType::pythonSignature() const
+{
+ // PYSIDE-921: Handle container returntypes correctly.
+ // This is now a clean reimplementation.
+ const AbstractMetaTypeData *cd = d.constData();
+ if (cd->m_cachedPythonSignature.isEmpty() || cd->m_signaturesDirty)
+ cd->m_cachedPythonSignature = formatPythonSignature();
+ return cd->m_cachedPythonSignature;
+}
+
+AbstractMetaType::TypeUsagePattern AbstractMetaTypeData::determineUsagePattern() const
+{
+ if (m_typeEntry->isTemplateArgument())
+ return AbstractMetaType::TemplateArgument;
+
+ if (m_typeEntry->type() == TypeEntry::ConstantValueType)
+ return AbstractMetaType::NonTypeTemplateArgument;
+
+ if (m_typeEntry->isPrimitive() && (actualIndirections() == 0 || passByConstRef()))
+ return AbstractMetaType::PrimitivePattern;
+
+ if (m_typeEntry->isVoid()) {
+ return m_arrayElementCount < 0 && m_referenceType == NoReference
+ && m_indirections.isEmpty() && m_constant == 0 && m_volatile == 0
+ ? AbstractMetaType::VoidPattern : AbstractMetaType::NativePointerPattern;
+ }
+
+ if (m_typeEntry->isVarargs())
+ return AbstractMetaType::VarargsPattern;
+
+ if (m_typeEntry->isEnum() && (actualIndirections() == 0 || passByConstRef()))
+ return AbstractMetaType::EnumPattern;
+
+ if (m_typeEntry->isObject()) {
+ if (m_indirections.isEmpty() && m_referenceType == NoReference)
+ return AbstractMetaType::ValuePattern;
+ return AbstractMetaType::ObjectPattern;
+ }
+
+ if (m_typeEntry->isContainer() && m_indirections.isEmpty())
+ return AbstractMetaType::ContainerPattern;
+
+ if (m_typeEntry->isSmartPointer() && m_indirections.isEmpty())
+ return AbstractMetaType::SmartPointerPattern;
+
+ if (m_typeEntry->isFlags() && (actualIndirections() == 0 || passByConstRef()))
+ return AbstractMetaType::FlagsPattern;
+
+ if (m_typeEntry->isArray())
+ return AbstractMetaType::ArrayPattern;
+
+ if (m_typeEntry->isValue())
+ return m_indirections.size() == 1 ? AbstractMetaType::ValuePointerPattern : AbstractMetaType::ValuePattern;
+
+ return AbstractMetaType::NativePointerPattern;
+}
+
+AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() const
+{
+ return d->determineUsagePattern();
+}
+
+void AbstractMetaType::decideUsagePattern()
+{
+ TypeUsagePattern pattern = determineUsagePattern();
+ if (d->m_typeEntry->isObject() && indirections() == 1
+ && d->m_referenceType == LValueReference && isConstant()) {
+ // const-references to pointers can be passed as pointers
+ setReferenceType(NoReference);
+ setConstant(false);
+ pattern = ObjectPattern;
+ }
+ setTypeUsagePattern(pattern);
+ Q_ASSERT(pattern != ContainerPattern || !d->m_instantiations.isEmpty());
+}
+
+bool AbstractMetaTypeData::hasTemplateChildren() const
+{
+ QStack<AbstractMetaType> children;
+ children << m_instantiations;
+
+ // Recursively iterate over the children / descendants of the type, to check if any of them
+ // corresponds to a template argument type.
+ while (!children.isEmpty()) {
+ AbstractMetaType child = children.pop();
+ if (child.typeEntry()->isTemplateArgument())
+ return true;
+ children << child.instantiations();
+ }
+ return false;
+}
+
+bool AbstractMetaType::hasTemplateChildren() const
+{
+ return d->hasTemplateChildren();
+}
+
+static inline QString formatArraySize(int e)
+{
+ QString result;
+ result += u'[';
+ if (e >= 0)
+ result += QString::number(e);
+ result += u']';
+ return result;
+}
+
+// Return the number of template parameters; remove the default
+// non template type parameter of std::span from the signature.
+static qsizetype stripDefaultTemplateArgs(const TypeEntryCPtr &te,
+ const AbstractMetaTypeList &instantiations)
+{
+ static const char16_t dynamicExtent64[] = u"18446744073709551615"; // size_t(-1)
+ static const char16_t dynamicExtent32[] = u"4294967295";
+
+ qsizetype result = instantiations.size();
+ if (result == 0 || !te->isContainer())
+ return result;
+ auto cte = std::static_pointer_cast<const ContainerTypeEntry>(te);
+ if (cte->containerKind() != ContainerTypeEntry::SpanContainer)
+ return result;
+ const auto lastTe = instantiations.constLast().typeEntry();
+ if (lastTe->type() == TypeEntry::ConstantValueType) {
+ const QString &name = lastTe->name();
+ if (name == dynamicExtent64 || name == dynamicExtent32)
+ --result;
+ }
+ return result;
+}
+
+QString AbstractMetaTypeData::formatSignature(bool minimal) const
+{
+ QString result;
+ if (m_constant)
+ result += u"const "_s;
+ if (m_volatile)
+ result += u"volatile "_s;
+ if (m_pattern == AbstractMetaType::ArrayPattern) {
+ // Build nested array dimensions a[2][3] in correct order
+ result += m_arrayElementType->minimalSignature();
+ const int arrayPos = result.indexOf(u'[');
+ if (arrayPos != -1)
+ result.insert(arrayPos, formatArraySize(m_arrayElementCount));
+ else
+ result.append(formatArraySize(m_arrayElementCount));
+ } else {
+ result += m_typeEntry->qualifiedCppName();
+ }
+ if (!m_instantiations.isEmpty()) {
+ result += u'<';
+ if (minimal)
+ result += u' ';
+ const auto size = stripDefaultTemplateArgs(m_typeEntry, m_instantiations);
+ for (qsizetype i = 0; i < size; ++i) {
+ if (i > 0)
+ result += u',';
+ result += m_instantiations.at(i).minimalSignature();
+ }
+ result += u'>';
+ }
+
+ if (!minimal && (!m_indirections.isEmpty() || m_referenceType != NoReference))
+ result += u' ';
+ for (Indirection i : m_indirections)
+ result += TypeInfo::indirectionKeyword(i);
+ switch (m_referenceType) {
+ case NoReference:
+ break;
+ case LValueReference:
+ result += u'&';
+ break;
+ case RValueReference:
+ result += u"&&"_s;
+ break;
+ }
+ return result;
+}
+
+QString AbstractMetaType::formatSignature(bool minimal) const
+{
+ return d->formatSignature(minimal);
+}
+
+QString AbstractMetaTypeData::formatPythonSignature() const
+{
+ /*
+ * This is a version of the above, more suitable for Python.
+ * We avoid extra keywords that are not needed in Python.
+ * We prepend the package name, unless it is a primitive type.
+ *
+ * Primitive types like 'int', 'char' etc.:
+ * When we have a primitive with an indirection, we use that '*'
+ * character for later postprocessing, since those indirections
+ * need to be modified into a result tuple.
+ * Smart pointer instantiations: Drop the package
+ */
+ QString result;
+ if (m_pattern == AbstractMetaType::NativePointerAsArrayPattern)
+ result += u"array "_s;
+ // We no longer use the "const" qualifier for heuristics. Instead,
+ // NativePointerAsArrayPattern indicates when we have <array> in XML.
+ // if (m_typeEntry->isPrimitive() && isConstant())
+ // result += QLatin1String("const ");
+ if (!m_typeEntry->isPrimitive() && !m_typeEntry->isSmartPointer()) {
+ const QString package = m_typeEntry->targetLangPackage();
+ if (!package.isEmpty())
+ result += package + u'.';
+ }
+ if (m_pattern == AbstractMetaType::ArrayPattern) {
+ // Build nested array dimensions a[2][3] in correct order
+ result += m_arrayElementType->formatPythonSignature();
+ const int arrayPos = result.indexOf(u'[');
+ if (arrayPos != -1)
+ result.insert(arrayPos, formatArraySize(m_arrayElementCount));
+ else
+ result.append(formatArraySize(m_arrayElementCount));
+ } else {
+ result += m_typeEntry->targetLangName();
+ }
+ if (!m_instantiations.isEmpty()) {
+ result += u'[';
+ for (qsizetype i = 0, size = m_instantiations.size(); i < size; ++i) {
+ if (i > 0)
+ result += u", "_s;
+ result += m_instantiations.at(i).formatPythonSignature();
+ }
+ result += u']';
+ }
+ if (m_typeEntry->isPrimitive())
+ for (Indirection i : m_indirections)
+ result += TypeInfo::indirectionKeyword(i);
+ // If it is a flags type, we replace it with the full name of the enum:
+ // "PySide6.QtCore.Qt.ItemFlag" instead of "PySide6.QtCore.QFlags<Qt.ItemFlag>"
+ if (m_typeEntry->isFlags()) {
+ const auto fte = std::static_pointer_cast<const FlagsTypeEntry>(m_typeEntry);
+ result = fte->originator()->qualifiedTargetLangName();
+ }
+ result.replace(u"::"_s, u"."_s);
+ return result;
+}
+
+QString AbstractMetaType::formatPythonSignature() const
+{
+ return d->formatPythonSignature();
+}
+
+bool AbstractMetaType::isCppPrimitive() const
+{
+ return d->m_pattern == PrimitivePattern && ::isCppPrimitive(d->m_typeEntry);
+}
+
+bool AbstractMetaType::isConstant() const
+{
+ return d->m_constant;
+}
+
+void AbstractMetaType::setConstant(bool constant)
+{
+ if (d->m_constant != constant) {
+ d->m_constant = constant;
+ d->m_signaturesDirty = true;
+ }
+}
+
+bool AbstractMetaType::isVolatile() const
+{
+ return d->m_volatile;
+}
+
+void AbstractMetaType::setVolatile(bool v)
+{
+ if (d->m_volatile != v) {
+ d->m_volatile = v;
+ d->m_signaturesDirty = true;\
+ }
+}
+
+static bool equalsCPtr(const AbstractMetaTypeCPtr &t1, const AbstractMetaTypeCPtr &t2)
+{
+ if (bool(t1) != bool(t2))
+ return false;
+ return !t1 || *t1 == *t2;
+}
+
+bool AbstractMetaTypeData::isEquivalent(const AbstractMetaTypeData &rhs) const
+{
+ if (m_typeEntry != rhs.m_typeEntry
+ || m_indirections != rhs.m_indirections
+ || m_arrayElementCount != rhs.m_arrayElementCount) {
+ return false;
+ }
+
+ if (!equalsCPtr(m_arrayElementType, rhs.m_arrayElementType))
+ return false;
+
+ if (!equalsCPtr(m_viewOn, rhs.m_viewOn))
+ return false;
+
+ if (m_instantiations != rhs.m_instantiations)
+ return false;
+ return true;
+}
+
+bool AbstractMetaTypeData::equals(const AbstractMetaTypeData &rhs) const
+{
+ return m_constant == rhs.m_constant && m_volatile == rhs.m_volatile
+ && m_referenceType == rhs.m_referenceType && isEquivalent(rhs);
+}
+
+bool comparesEqual(const AbstractMetaType &lhs, const AbstractMetaType &rhs) noexcept
+{
+ return lhs.d->equals(*rhs.d);
+}
+
+bool AbstractMetaType::isEquivalent(const AbstractMetaType &rhs) const
+{
+ return d->isEquivalent(*rhs.d);
+}
+
+const AbstractMetaType *AbstractMetaType::viewOn() const
+{
+ return d->m_viewOn.get();
+}
+
+void AbstractMetaType::setViewOn(const AbstractMetaType &v)
+{
+ if (!d->m_viewOn || *d->m_viewOn != v)
+ d->m_viewOn.reset(new AbstractMetaType(v));
+}
+
+AbstractMetaType AbstractMetaType::createVoid()
+{
+ static QScopedPointer<AbstractMetaType> metaType;
+ if (metaType.isNull()) {
+ static TypeEntryCPtr voidTypeEntry = TypeDatabase::instance()->findType(u"void"_s);
+ Q_ASSERT(voidTypeEntry);
+ metaType.reset(new AbstractMetaType(voidTypeEntry));
+ metaType->decideUsagePattern();
+ }
+ return *metaType.data();
+}
+
+void AbstractMetaType::dereference(QString *type)
+{
+ type->prepend(u"(*"_s);
+ type->append(u')');
+}
+
+QString AbstractMetaType::dereferencePrefix(qsizetype n)
+{
+ const QChar c = n > 0 ? u'*' : u'&';
+ return QString(qAbs(n), c);
+}
+
+void AbstractMetaType::applyDereference(QString *type, qsizetype n)
+{
+ if (n == 0)
+ return;
+
+ type->prepend(dereferencePrefix(n));
+ type->prepend(u'(');
+ type->append(u')');
+}
+
+bool AbstractMetaType::stripDereference(QString *type)
+{
+ if (type->startsWith(u"(*") && type->endsWith(u')')) {
+ type->chop(1);
+ type->remove(0, 2);
+ *type = type->trimmed();
+ return true;
+ }
+ if (type->startsWith(u'*')) {
+ type->remove(0, 1);
+ *type = type->trimmed();
+ return true;
+ }
+ return false;
+}
+
+// Query functions for generators
+bool AbstractMetaType::isObjectType() const
+{
+ return d->m_typeEntry->isObject();
+}
+
+bool AbstractMetaType::isUniquePointer() const
+{
+ return isSmartPointer() && d->m_typeEntry->isUniquePointer();
+}
+
+bool AbstractMetaType::isPointer() const
+{
+ return !d->m_indirections.isEmpty()
+ || isNativePointer() || isValuePointer();
+}
+
+bool AbstractMetaType::isPointerToConst() const
+{
+ return d->m_constant && !d->m_indirections.isEmpty()
+ && d->m_indirections.constLast() != Indirection::ConstPointer;
+}
+
+bool AbstractMetaType::isCString() const
+{
+ return isNativePointer()
+ && d->m_indirections.size() == 1
+ && name() == u"char";
+}
+
+bool AbstractMetaType::isVoidPointer() const
+{
+ return isNativePointer()
+ && d->m_indirections.size() == 1
+ && name() == u"void";
+}
+
+bool AbstractMetaType::isUserPrimitive() const
+{
+ return d->m_indirections.isEmpty() && ::isUserPrimitive(d->m_typeEntry);
+}
+
+bool AbstractMetaType::isObjectTypeUsedAsValueType() const
+{
+ return d->m_typeEntry->isObject() && d->m_referenceType == NoReference
+ && d->m_indirections.isEmpty();
+}
+
+bool AbstractMetaType::isWrapperType() const
+{
+ return d->m_typeEntry->isWrapperType();
+}
+
+bool AbstractMetaType::isPointerToWrapperType() const
+{
+ return (isObjectType() && d->m_indirections.size() == 1) || isValuePointer();
+}
+
+bool AbstractMetaType::isWrapperPassedByReference() const
+{
+ return d->m_referenceType == LValueReference && isWrapperType()
+ && !isPointer();
+}
+
+bool AbstractMetaType::isCppIntegralPrimitive() const
+{
+ return ::isCppIntegralPrimitive(d->m_typeEntry);
+}
+
+bool AbstractMetaType::isExtendedCppPrimitive() const
+{
+ if (isCString() || isVoidPointer())
+ return true;
+ if (!d->m_indirections.isEmpty())
+ return false;
+ return ::isExtendedCppPrimitive(d->m_typeEntry);
+}
+
+bool AbstractMetaType::isValueTypeWithCopyConstructorOnly() const
+{
+ bool result = false;
+ if (d->m_typeEntry->isComplex()) {
+ const auto cte = std::static_pointer_cast<const ComplexTypeEntry>(d->m_typeEntry);
+ result = cte->isValueTypeWithCopyConstructorOnly();
+ }
+ return result;
+}
+
+bool AbstractMetaType::valueTypeWithCopyConstructorOnlyPassed() const
+{
+ return (passByValue() || passByConstRef())
+ && isValueTypeWithCopyConstructorOnly();
+}
+
+using AbstractMetaTypeCache = QHash<QString, AbstractMetaType>;
+
+Q_GLOBAL_STATIC(AbstractMetaTypeCache, metaTypeFromStringCache)
+
+std::optional<AbstractMetaType>
+AbstractMetaType::fromString(const QString &typeSignatureIn, QString *errorMessage)
+{
+ auto &cache = *metaTypeFromStringCache();
+ auto it = cache.find(typeSignatureIn);
+ if (it != cache.end())
+ return it.value();
+
+ QString typeSignature = typeSignatureIn.trimmed();
+ if (typeSignature.startsWith(u"::"))
+ typeSignature.remove(0, 2);
+
+ it = cache.find(typeSignature);
+ if (it == cache.end()) {
+ auto metaType =
+ AbstractMetaBuilder::translateType(typeSignature, nullptr, {}, errorMessage);
+ if (Q_UNLIKELY(!metaType.has_value())) {
+ if (errorMessage)
+ errorMessage->prepend(msgCannotBuildMetaType(typeSignature));
+ return {};
+ }
+ if (typeSignature != typeSignatureIn)
+ cache.insert(typeSignatureIn, metaType.value());
+ it = cache.insert(typeSignature, metaType.value());
+ }
+ return it.value();
+}
+
+AbstractMetaType AbstractMetaType::fromTypeEntry(const TypeEntryCPtr &typeEntry)
+{
+ QString typeName = typeEntry->qualifiedCppName();
+ if (typeName.startsWith(u"::"))
+ typeName.remove(0, 2);
+ auto &cache = *metaTypeFromStringCache();
+ auto it = cache.find(typeName);
+ if (it != cache.end())
+ return it.value();
+ AbstractMetaType metaType = AbstractMetaType(typeEntry).plainType();
+ cache.insert(typeName, metaType);
+ return metaType;
+}
+
+AbstractMetaType AbstractMetaType::fromAbstractMetaClass(const AbstractMetaClassCPtr &metaClass)
+{
+ return fromTypeEntry(metaClass->typeEntry());
+}
+
+template <class Predicate> // Predicate(containerTypeEntry, signature)
+bool AbstractMetaTypeData::generateOpaqueContainer(Predicate pred) const
+{
+ // Allow for passing containers by pointer as well.
+ if (!m_typeEntry->isContainer())
+ return false;
+ if (m_indirections.size() > 1)
+ return false;
+ auto containerTypeEntry = std::static_pointer_cast<const ContainerTypeEntry>(m_typeEntry);
+ auto kind = containerTypeEntry->containerKind();
+ if (kind != ContainerTypeEntry::ListContainer && kind != ContainerTypeEntry::SpanContainer)
+ return false;
+
+ const auto &firstInstantiation = m_instantiations.constFirst();
+ if (firstInstantiation.referenceType() != NoReference)
+ return false;
+ switch (firstInstantiation.typeEntry()->type()) {
+ case TypeEntry::PrimitiveType:
+ case TypeEntry::FlagsType:
+ case TypeEntry::EnumType:
+ case TypeEntry::BasicValueType:
+ case TypeEntry::ObjectType:
+ case TypeEntry::CustomType:
+ break;
+ default:
+ return false;
+ }
+
+ return pred(containerTypeEntry, instantiationCppSignatures());
+}
+
+// Simple predicate for checking whether an opaque container should be generated
+static bool opaqueContainerPredicate(const ContainerTypeEntryCPtr &t,
+ const QStringList &instantiations)
+{
+ return t->generateOpaqueContainer(instantiations);
+}
+
+bool AbstractMetaType::generateOpaqueContainer() const
+{
+ return d->generateOpaqueContainer(opaqueContainerPredicate);
+}
+
+// Helper for determining whether a function should return an opaque container,
+// that is, the function return type is modified accordingly
+// (cf AbstractMetaFunction::generateOpaqueContainerReturn())
+bool AbstractMetaType::generateOpaqueContainerForGetter(const QString &modifiedType) const
+{
+ auto predicate = [&modifiedType](const ContainerTypeEntryCPtr &t,
+ const QStringList &instantiations) {
+ return t->opaqueContainerName(instantiations) == modifiedType;
+ };
+ return d->generateOpaqueContainer(predicate);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void AbstractMetaType::formatDebug(QDebug &debug) const
+{
+ debug << '"' << name() << '"';
+ if (debug.verbosity() > 2 && !isVoid()) {
+ auto te = typeEntry();
+ debug << ", typeEntry=";
+ if (debug.verbosity() > 3)
+ debug << te;
+ else
+ debug << "(\"" << te->qualifiedCppName() << "\", " << te->type() << ')';
+ debug << ", signature=\"" << cppSignature() << "\", pattern="
+ << typeUsagePattern();
+ const auto indirections = indirectionsV();
+ if (!indirections.isEmpty()) {
+ debug << ", indirections=";
+ for (auto i : indirections)
+ debug << ' ' << TypeInfo::indirectionKeyword(i);
+ }
+ if (referenceType() != NoReference)
+ debug << ", reftype=" << referenceType();
+ if (isConstant())
+ debug << ", [const]";
+ if (isVolatile())
+ debug << ", [volatile]";
+ if (isArray()) {
+ debug << ", array of \"" << arrayElementType()->cppSignature()
+ << "\", arrayElementCount=" << arrayElementCount();
+ }
+ const auto &instantiations = this->instantiations();
+ if (const auto instantiationsSize = instantiations.size()) {
+ debug << ", instantiations[" << instantiationsSize << "]=<";
+ for (qsizetype i = 0; i < instantiationsSize; ++i) {
+ if (i)
+ debug << ", ";
+ instantiations.at(i).formatDebug(debug);
+ }
+ }
+ debug << '>';
+ if (viewOn())
+ debug << ", views " << viewOn()->name();
+ }
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaType &at)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaType(";
+ at.formatDebug(d);
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaType *at)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ if (at)
+ d << *at;
+ else
+ d << "AbstractMetaType(0)";
+ return d;
+}
+
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/abstractmetatype.h b/sources/shiboken6/ApiExtractor/abstractmetatype.h
new file mode 100644
index 000000000..8a1ecdf20
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetatype.h
@@ -0,0 +1,276 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACTMETATYPE_H
+#define ABSTRACTMETATYPE_H
+
+#include "abstractmetalang_enums.h"
+#include "abstractmetalang_typedefs.h"
+#include "parser/codemodel_enums.h"
+#include "typedatabase_typedefs.h"
+
+#include <QtCore/QtCompare>
+#include <QtCore/qobjectdefs.h>
+#include <QtCore/QHashFunctions>
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QList>
+#include <QtCore/QSet>
+
+#include <optional>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class AbstractMetaTypeData;
+class TypeEntry;
+
+class AbstractMetaType
+{
+ Q_GADGET
+public:
+ using Indirections = QList<Indirection>;
+
+ enum TypeUsagePattern {
+ PrimitivePattern,
+ FlagsPattern,
+ EnumPattern,
+ ValuePattern,
+ ObjectPattern,
+ ValuePointerPattern,
+ NativePointerPattern,
+ NativePointerAsArrayPattern, // "int*" as "int[]"
+ ContainerPattern,
+ SmartPointerPattern,
+ VarargsPattern,
+ ArrayPattern,
+ VoidPattern, // Plain "void", no "void *" or similar.
+ TemplateArgument, // 'T' in std::array<T,2>
+ NonTypeTemplateArgument // '2' in in std::array<T,2>
+ };
+ Q_ENUM(TypeUsagePattern)
+
+ AbstractMetaType();
+ explicit AbstractMetaType(const TypeEntryCPtr &t);
+ AbstractMetaType(const AbstractMetaType &);
+ AbstractMetaType &operator=(const AbstractMetaType &);
+ AbstractMetaType(AbstractMetaType &&) noexcept;
+ AbstractMetaType &operator=(AbstractMetaType &&) noexcept;
+ ~AbstractMetaType();
+
+ QString package() const;
+ QString name() const;
+ QString fullName() const;
+
+ void setTypeUsagePattern(TypeUsagePattern pattern);
+ TypeUsagePattern typeUsagePattern() const;
+
+ // true when use pattern is container
+ bool hasInstantiations() const;
+
+ const AbstractMetaTypeList &instantiations() const;
+ void addInstantiation(const AbstractMetaType &inst);
+ void setInstantiations(const AbstractMetaTypeList &insts);
+ QStringList instantiationCppSignatures() const;
+
+ QString minimalSignature() const { return formatSignature(true); }
+
+ // returns true if the typs is used as a non complex primitive, no & or *'s
+ bool isPrimitive() const { return typeUsagePattern() == PrimitivePattern; }
+
+ bool isCppPrimitive() const;
+
+ // returns true if the type is used as an enum
+ bool isEnum() const { return typeUsagePattern() == EnumPattern; }
+
+ // returns true if the type is used as an object, e.g. Xxx *
+ bool isObject() const { return typeUsagePattern() == ObjectPattern; }
+
+ // returns true if the type is indicated an object by the TypeEntry
+ bool isObjectType() const;
+
+ // returns true if the type is used as an array, e.g. Xxx[42]
+ bool isArray() const { return typeUsagePattern() == ArrayPattern; }
+
+ // returns true if the type is used as a value type (X or const X &)
+ bool isValue() const { return typeUsagePattern() == ValuePattern; }
+
+ bool isValuePointer() const { return typeUsagePattern() == ValuePointerPattern; }
+
+ // returns true for more complex types...
+ bool isNativePointer() const { return typeUsagePattern() == NativePointerPattern; }
+
+ // return true if the type was originally a varargs
+ bool isVarargs() const { return typeUsagePattern() == VarargsPattern; }
+
+ // returns true if the type was used as a container
+ bool isContainer() const { return typeUsagePattern() == ContainerPattern; }
+
+ // returns true if the type was used as a smart pointer
+ bool isSmartPointer() const { return typeUsagePattern() == SmartPointerPattern; }
+ bool isUniquePointer() const;
+
+ // returns true if the type was used as a flag
+ bool isFlags() const { return typeUsagePattern() == FlagsPattern; }
+
+ bool isVoid() const { return typeUsagePattern() == VoidPattern; }
+
+ bool isConstant() const;
+ void setConstant(bool constant);
+
+ bool isVolatile() const;
+ void setVolatile(bool v);
+
+ bool passByConstRef() const;
+ bool passByValue() const;
+ bool useStdMove() const;
+
+ ReferenceType referenceType() const;
+ void setReferenceType(ReferenceType ref);
+
+ int actualIndirections() const;
+
+ Indirections indirectionsV() const;
+ void setIndirectionsV(const Indirections &i);
+ void clearIndirections();
+
+ // "Legacy"?
+ int indirections() const;
+ void setIndirections(int indirections);
+ void addIndirection(Indirection i = Indirection::Pointer);
+
+ void setArrayElementCount(int n);
+ int arrayElementCount() const;
+
+ const AbstractMetaType *arrayElementType() const;
+ void setArrayElementType(const AbstractMetaType &t);
+
+ AbstractMetaTypeList nestedArrayTypes() const;
+
+ /// Strip const/indirections/reference from the type
+ AbstractMetaType plainType() const;
+
+ QString cppSignature() const;
+
+ QString pythonSignature() const;
+
+ bool applyArrayModification(QString *errorMessage);
+
+ TypeEntryCPtr typeEntry() const;
+ void setTypeEntry(const TypeEntryCPtr &type);
+
+ void setOriginalTypeDescription(const QString &otd);
+ QString originalTypeDescription() const;
+
+ void setOriginalTemplateType(const AbstractMetaType &type);
+ const AbstractMetaType *originalTemplateType() const;
+
+ AbstractMetaType getSmartPointerInnerType() const;
+
+ QString getSmartPointerInnerTypeName() const;
+
+ /// Decides and sets the proper usage patter for the current meta type.
+ void decideUsagePattern();
+
+ bool hasTemplateChildren() const;
+
+ /// Is equivalent from the POV of argument passing (differ by const ref)
+ bool isEquivalent(const AbstractMetaType &rhs) const;
+
+ // View on: Type to use for function argument conversion, fex
+ // std::string_view -> std::string for foo(std::string_view);
+ // cf TypeEntry::viewOn()
+ const AbstractMetaType *viewOn() const;
+ void setViewOn(const AbstractMetaType &v);
+
+ static AbstractMetaType createVoid();
+
+ /// Builds an AbstractMetaType object from a QString.
+ /// Returns nullopt if no type could be built from the string.
+ /// \param typeSignature The string describing the type to be built.
+ /// \return A new AbstractMetaType object or nullopt in case of failure.
+ static std::optional<AbstractMetaType>
+ fromString(const QString &typeSignatureIn, QString *errorMessage = nullptr);
+ /// Creates an AbstractMetaType object from a TypeEntry.
+ static AbstractMetaType fromTypeEntry(const TypeEntryCPtr &typeEntry);
+ /// Creates an AbstractMetaType object from an AbstractMetaClass.
+ static AbstractMetaType fromAbstractMetaClass(const AbstractMetaClassCPtr &metaClass);
+
+ static void dereference(QString *type); // "foo" -> "(*foo)"
+ /// Apply the result of shouldDereferenceArgument()
+ static QString dereferencePrefix(qsizetype n); // Return the prefix **/& as as required
+ static void applyDereference(QString *type, qsizetype n);
+ static bool stripDereference(QString *type); // "(*foo)" -> "foo"
+
+ // Query functions for generators
+ /// Check if type is a pointer.
+ bool isPointer() const;
+ /// Helper for field setters: Check for "const QWidget *" (settable field),
+ /// but not "int *const" (read-only field).
+ bool isPointerToConst() const;
+ /// Returns true if the type is a C string (const char *).
+ bool isCString() const;
+ /// Returns true if the type is a void pointer.
+ bool isVoidPointer() const;
+ /// Returns true if the type is a primitive but not a C++ primitive.
+ bool isUserPrimitive() const;
+ /// Returns true if it is an Object Type used as a value.
+ bool isObjectTypeUsedAsValueType() const;
+ /// Returns true if the type passed has a Python wrapper for it.
+ /// Although namespace has a Python wrapper, it's not considered a type.
+ bool isWrapperType() const;
+ /// Checks if the type is an Object/QObject or pointer to Value Type.
+ /// In other words, tells if the type is "T*" and T has a Python wrapper.
+ bool isPointerToWrapperType() const;
+ /// Wrapper type passed by reference
+ bool isWrapperPassedByReference() const;
+ /// Returns true if the type is a C++ integral primitive,
+ /// i.e. bool, char, int, long, and their unsigned counterparts.
+ bool isCppIntegralPrimitive() const;
+ /// Returns true if the type is an extended C++ primitive, a void*,
+ /// a const char*, or a std::string (cf isCppPrimitive()).
+ bool isExtendedCppPrimitive() const;
+ /// Returns whether the underlying type is a value type with copy constructor only
+ bool isValueTypeWithCopyConstructorOnly() const;
+ /// Returns whether the type (function argument) is a value type with
+ /// copy constructor only is passed as value or const-ref and thus
+ /// no default value can be constructed.
+ bool valueTypeWithCopyConstructorOnlyPassed() const;
+ /// Returns whether to generate an opaque container for the type
+ bool generateOpaqueContainer() const;
+ /// Returns whether to generate an opaque container for a getter
+ bool generateOpaqueContainerForGetter(const QString &modifiedType) const;
+
+ /// Types for which libshiboken has built-in primitive converters
+ static const QSet<QString> &cppFloatTypes();
+ static const QSet<QString> &cppSignedCharTypes();
+ static const QSet<QString> &cppUnsignedCharTypes();
+ static const QSet<QString> &cppCharTypes();
+ static const QSet<QString> &cppSignedIntTypes();
+ static const QSet<QString> &cppUnsignedIntTypes();
+ static const QSet<QString> &cppIntegralTypes();
+ static const QSet<QString> &cppPrimitiveTypes();
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &debug) const;
+#endif
+
+private:
+ friend size_t qHash(const AbstractMetaType &t, size_t seed = 0) noexcept
+ { return qHash(t.typeEntry().get(), seed); }
+ friend bool comparesEqual(const AbstractMetaType &lhs,
+ const AbstractMetaType &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(AbstractMetaType)
+
+ friend class AbstractMetaTypeData;
+ QSharedDataPointer<AbstractMetaTypeData> d;
+
+ TypeUsagePattern determineUsagePattern() const;
+ QString formatSignature(bool minimal) const;
+ QString formatPythonSignature() const;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaType &at);
+QDebug operator<<(QDebug d, const AbstractMetaType *at);
+#endif
+
+#endif // ABSTRACTMETALANG_H
diff --git a/sources/shiboken6/ApiExtractor/addedfunction.cpp b/sources/shiboken6/ApiExtractor/addedfunction.cpp
new file mode 100644
index 000000000..9d95b734c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/addedfunction.cpp
@@ -0,0 +1,216 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "addedfunction.h"
+#include "addedfunction_p.h"
+#include "typeparser.h"
+
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+constexpr auto callOperator = "operator()"_L1;
+
+// Helpers to split a parameter list of <add-function>, <declare-function>
+// (@ denoting names), like
+// "void foo(QList<X,Y> &@list@ = QList<X,Y>{1,2}, int @b@=5, ...)"
+namespace AddedFunctionParser {
+
+QDebug operator<<(QDebug d, const Argument &a)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "Argument(type=\"" << a.type << '"';
+ if (!a.name.isEmpty())
+ d << ", name=\"" << a.name << '"';
+ if (!a.defaultValue.isEmpty())
+ d << ", defaultValue=\"" << a.defaultValue << '"';
+ d << ')';
+ return d;
+}
+
+// Helper for finding the end of a function parameter, observing
+// nested template parameters or lists.
+static qsizetype parameterTokenEnd(qsizetype startPos, QStringView paramString)
+{
+ const auto end = paramString.size();
+ int nestingLevel = 0;
+ for (qsizetype p = startPos; p < end; ++p) {
+ switch (paramString.at(p).toLatin1()) {
+ case ',':
+ if (nestingLevel == 0)
+ return p;
+ break;
+ case '<': // templates
+ case '{': // initializer lists of default values
+ case '(': // initialization, function pointers
+ case '[': // array dimensions
+ ++nestingLevel;
+ break;
+ case '>':
+ case '}':
+ case ')':
+ case ']':
+ --nestingLevel;
+ break;
+ }
+ }
+ return end;
+}
+
+// Split a function parameter list into string tokens containing one
+// parameters (including default value, etc).
+static QList<QStringView> splitParameterTokens(QStringView paramString)
+{
+ QList<QStringView> result;
+ qsizetype startPos = 0;
+ for ( ; startPos < paramString.size(); ) {
+ const auto end = parameterTokenEnd(startPos, paramString);
+ result.append(paramString.mid(startPos, end - startPos).trimmed());
+ startPos = end + 1;
+ }
+ return result;
+}
+
+// Split a function parameter list
+Arguments splitParameters(QStringView paramString, QString *errorMessage)
+{
+ Arguments result;
+ const QList<QStringView> tokens = splitParameterTokens(paramString);
+
+ for (const auto &t : tokens) {
+ Argument argument;
+ // Check defaultValue, "int @b@=5"
+ const auto equalPos = t.lastIndexOf(u'=');
+ if (equalPos != -1) {
+ const int defaultValuePos = equalPos + 1;
+ argument.defaultValue =
+ t.mid(defaultValuePos, t.size() - defaultValuePos).trimmed().toString();
+ }
+ QString typeString = (equalPos != -1 ? t.left(equalPos) : t).trimmed().toString();
+ // Check @name@
+ const auto atPos = typeString.indexOf(u'@');
+ if (atPos != -1) {
+ const int namePos = atPos + 1;
+ const int nameEndPos = typeString.indexOf(u'@', namePos);
+ if (nameEndPos == -1) {
+ if (errorMessage != nullptr) {
+ *errorMessage = u"Mismatched @ in \""_s
+ + paramString.toString() + u'"';
+ }
+ return {};
+ }
+ argument.name = typeString.mid(namePos, nameEndPos - namePos).trimmed();
+ typeString.remove(atPos, nameEndPos - atPos + 1);
+ }
+ argument.type = typeString.trimmed();
+ result.append(argument);
+ }
+
+ return result;
+}
+
+} // namespace AddedFunctionParser
+
+AddedFunction::AddedFunction(const QString &name, const QList<Argument> &arguments,
+ const TypeInfo &returnType) :
+ m_name(name),
+ m_arguments(arguments),
+ m_returnType(returnType)
+{
+}
+
+AddedFunction::AddedFunctionPtr
+ AddedFunction::createAddedFunction(const QString &signatureIn, const QString &returnTypeIn,
+ QString *errorMessage)
+
+{
+ errorMessage->clear();
+
+ QList<Argument> arguments;
+ const TypeInfo returnType = returnTypeIn.isEmpty()
+ ? TypeInfo::voidType()
+ : TypeParser::parse(returnTypeIn, errorMessage);
+ if (!errorMessage->isEmpty())
+ return {};
+
+ QStringView signature = QStringView{signatureIn}.trimmed();
+
+ // Skip past "operator()(...)"
+ const auto parenSearchStartPos = signature.startsWith(callOperator)
+ ? callOperator.size() : 0;
+ const auto openParenPos = signature.indexOf(u'(', parenSearchStartPos);
+ if (openParenPos < 0) {
+ return AddedFunctionPtr(new AddedFunction(signature.toString(),
+ arguments, returnType));
+ }
+
+ const QString name = signature.left(openParenPos).trimmed().toString();
+ const auto closingParenPos = signature.lastIndexOf(u')');
+ if (closingParenPos < 0) {
+ *errorMessage = u"Missing closing parenthesis"_s;
+ return {};
+ }
+
+ // Check for "foo() const"
+ bool isConst = false;
+ const auto signatureLength = signature.length();
+ const auto qualifierLength = signatureLength - closingParenPos - 1;
+ if (qualifierLength >= 5
+ && signature.right(qualifierLength).contains(u"const")) {
+ isConst = true;
+ }
+
+ const auto paramString = signature.mid(openParenPos + 1, closingParenPos - openParenPos - 1);
+ const auto params = AddedFunctionParser::splitParameters(paramString, errorMessage);
+ if (params.isEmpty() && !errorMessage->isEmpty())
+ return {};
+ for (const auto &p : params) {
+ TypeInfo type = p.type == u"..."
+ ? TypeInfo::varArgsType() : TypeParser::parse(p.type, errorMessage);
+ if (!errorMessage->isEmpty()) {
+ errorMessage->prepend(u"Unable to parse added function "_s + signatureIn
+ + u": "_s);
+ return {};
+ }
+ arguments.append({type, p.name, p.defaultValue});
+ }
+
+ auto result = std::make_shared<AddedFunction>(name, arguments, returnType);
+ result->setConstant(isConst);
+ return result;
+}
+
+QDebug operator<<(QDebug d, const AddedFunction::Argument &a)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "Argument(";
+ d << a.typeInfo;
+ if (!a.name.isEmpty())
+ d << ' ' << a.name;
+ if (!a.defaultValue.isEmpty())
+ d << " = " << a.defaultValue;
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const AddedFunction &af)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AddedFunction(";
+ if (af.access() == AddedFunction::Protected)
+ d << "protected";
+ if (af.isStatic())
+ d << " static";
+ d << af.returnType() << ' ' << af.name() << '(' << af.arguments() << ')';
+ if (af.isConstant())
+ d << " const";
+ if (af.isDeclaration())
+ d << " [declaration]";
+ return d;
+}
diff --git a/sources/shiboken6/ApiExtractor/addedfunction.h b/sources/shiboken6/ApiExtractor/addedfunction.h
new file mode 100644
index 000000000..b8d189b7a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/addedfunction.h
@@ -0,0 +1,113 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ADDEDFUNCTION_H
+#define ADDEDFUNCTION_H
+
+#include "modifications.h"
+#include "parser/typeinfo.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+#include <memory>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+/// \internal
+/// Struct used to store information about functions added by the typesystem.
+/// This info will be used later to create a fake AbstractMetaFunction which
+/// will be inserted into the right AbstractMetaClass.
+struct AddedFunction
+{
+ using AddedFunctionPtr = std::shared_ptr<AddedFunction>;
+
+ /// Function access types.
+ enum Access {
+ Protected = 0x1,
+ Public = 0x2
+ };
+
+ struct Argument
+ {
+ TypeInfo typeInfo;
+ QString name;
+ QString defaultValue;
+ };
+
+ /// Creates a new AddedFunction with a signature and a return type.
+ explicit AddedFunction(const QString &name, const QList<Argument> &arguments,
+ const TypeInfo &returnType);
+
+ static AddedFunctionPtr createAddedFunction(const QString &signatureIn,
+ const QString &returnTypeIn,
+ QString *errorMessage);
+
+ AddedFunction() = default;
+
+ /// Returns the function name.
+ QString name() const { return m_name; }
+
+ /// Set the function access type.
+ void setAccess(Access access) { m_access = access; }
+
+ /// Returns the function access type.
+ Access access() const { return m_access; }
+
+ /// Returns the function return type.
+ const TypeInfo &returnType() const { return m_returnType; }
+
+ /// Returns a list of argument type infos.
+ const QList<Argument> &arguments() const { return m_arguments; }
+
+ /// Returns true if this is a constant method.
+ bool isConstant() const { return m_isConst; }
+ void setConstant(bool c) { m_isConst = c; };
+
+ /// Set this method static.
+ void setStatic(bool value) { m_isStatic = value; }
+
+ /// Set this method as a classmethod.
+ void setClassMethod(bool value) { m_isClassMethod = value; }
+
+ /// Returns true if this is a static method.
+ bool isStatic() const { return m_isStatic; }
+
+ /// Returns true if this is a class method.
+ bool isClassMethod() const { return m_isClassMethod; }
+
+ bool isDeclaration() const { return m_isDeclaration; } // <declare-function>
+ void setDeclaration(bool value) { m_isDeclaration = value; }
+
+ bool isPythonOverride() const { return m_isPythonOverride; }
+ void setPythonOverride(bool o) { m_isPythonOverride = o; }
+
+ const FunctionModificationList &modifications() const { return m_modifications; }
+ FunctionModificationList &modifications() { return m_modifications; }
+
+ const DocModificationList &docModifications() const { return m_docModifications; }
+ DocModificationList &docModifications() { return m_docModifications; }
+ void addDocModification(const DocModification &m) { m_docModifications.append(m); }
+
+ QString targetLangPackage() const { return m_targetLangPackage; }
+ void setTargetLangPackage(const QString &p) { m_targetLangPackage = p; }
+
+private:
+ QString m_name;
+ QList<Argument> m_arguments;
+ TypeInfo m_returnType;
+ FunctionModificationList m_modifications;
+ DocModificationList m_docModifications;
+ QString m_targetLangPackage;
+ Access m_access = Public;
+ bool m_isConst = false;
+ bool m_isClassMethod = false;
+ bool m_isStatic = false;
+ bool m_isDeclaration = false;
+ bool m_isPythonOverride = false;
+};
+
+QDebug operator<<(QDebug d, const AddedFunction::Argument &a);
+QDebug operator<<(QDebug d, const AddedFunction &af);
+
+#endif // ADDEDFUNCTION_H
diff --git a/sources/shiboken6/ApiExtractor/addedfunction_p.h b/sources/shiboken6/ApiExtractor/addedfunction_p.h
new file mode 100644
index 000000000..40b69a5df
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/addedfunction_p.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ADDEDFUNCTION_P_H
+#define ADDEDFUNCTION_P_H
+
+#include <QtCore/QtCompare>
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QStringView>
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+QT_END_NAMESPACE
+
+// Helpers to split a parameter list of <add-function>, <declare-function>
+// in a separate header for testing purposes
+
+namespace AddedFunctionParser {
+
+struct Argument
+{
+ QString type;
+ QString name;
+ QString defaultValue;
+
+ friend bool comparesEqual(const Argument &lhs, const Argument &rhs) noexcept
+ {
+ return lhs.type == rhs.type && lhs.name == rhs.name
+ && lhs.defaultValue == rhs.defaultValue;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(Argument)
+};
+
+using Arguments = QList<Argument>;
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const Argument &a);
+#endif
+
+Arguments splitParameters(QStringView paramString, QString *errorMessage = nullptr);
+
+} // namespace AddedFunctionParser
+
+#endif // MODIFICATIONS_P_H
diff --git a/sources/shiboken6/ApiExtractor/anystringview_helpers.cpp b/sources/shiboken6/ApiExtractor/anystringview_helpers.cpp
new file mode 100644
index 000000000..35d2d535a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/anystringview_helpers.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "anystringview_helpers.h"
+
+#include <QtCore/QString> // Must go before QAnyStringView for operator<<(QTextStream,QASV)!
+#include <QtCore/QAnyStringView>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+
+#include <cstring>
+
+QTextStream &operator<<(QTextStream &str, QAnyStringView asv)
+{
+ asv.visit([&str](auto s) { str << s; });
+ return str;
+}
+
+static bool asv_containsImpl(QLatin1StringView v, char c)
+{
+ return v.contains(uint16_t(c));
+}
+
+static bool asv_containsImpl(QUtf8StringView v, char c)
+{
+ return std::strchr(v.data(), c) != nullptr;
+}
+
+static bool asv_containsImpl(QStringView v, char c)
+{
+ return v.contains(uint16_t(c));
+}
+
+bool asv_contains(QAnyStringView asv, char needle)
+{
+ return asv.visit([needle](auto s) { return asv_containsImpl(s, needle); });
+}
+
+static bool asv_containsImpl(QLatin1StringView v, const char *c)
+{
+ return v.contains(QLatin1StringView(c));
+}
+static bool asv_containsImpl(QUtf8StringView v, const char *c)
+{
+ return std::strstr(v.data(), c) != nullptr;
+}
+
+static bool asv_containsImpl(QStringView v, const char *c)
+{
+ return v.contains(QLatin1StringView(c));
+}
+
+bool asv_contains(QAnyStringView asv, const char *needle)
+{
+ return asv.visit([needle](auto s) { return asv_containsImpl(s, needle); });
+}
diff --git a/sources/shiboken6/ApiExtractor/anystringview_helpers.h b/sources/shiboken6/ApiExtractor/anystringview_helpers.h
new file mode 100644
index 000000000..e1e6ab7f0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/anystringview_helpers.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ANYSTRINGVIEW_STREAM_H
+#define ANYSTRINGVIEW_STREAM_H
+
+#include <QtCore/QtClassHelperMacros>
+
+QT_FORWARD_DECLARE_CLASS(QAnyStringView)
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+QTextStream &operator<<(QTextStream &str, QAnyStringView asv);
+
+bool asv_contains(QAnyStringView asv, char needle);
+bool asv_contains(QAnyStringView asv, const char *needle);
+
+#endif // ANYSTRINGVIEW_STREAM_H
diff --git a/sources/shiboken6/ApiExtractor/apiextractor.cpp b/sources/shiboken6/ApiExtractor/apiextractor.cpp
new file mode 100644
index 000000000..786cd0783
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/apiextractor.cpp
@@ -0,0 +1,849 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "apiextractor.h"
+#include "apiextractorresult.h"
+#include "abstractmetaargument.h"
+#include "abstractmetabuilder.h"
+#include "abstractmetaenum.h"
+#include "abstractmetafield.h"
+#include "abstractmetafunction.h"
+#include "abstractmetalang.h"
+#include "codesnip.h"
+#include "exception.h"
+#include "messages.h"
+#include "modifications.h"
+#include "optionsparser.h"
+#include "reporthandler.h"
+#include "typedatabase.h"
+#include "customconversion.h"
+#include "containertypeentry.h"
+#include "primitivetypeentry.h"
+#include "smartpointertypeentry.h"
+#include "typedefentry.h"
+#include "namespacetypeentry.h"
+#include "typesystemtypeentry.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QTemporaryFile>
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+
+using namespace Qt::StringLiterals;
+
+struct InstantiationCollectContext
+{
+ AbstractMetaTypeList instantiatedContainers;
+ InstantiatedSmartPointers instantiatedSmartPointers;
+ QStringList instantiatedContainersNames;
+};
+
+struct ApiExtractorOptions
+{
+ QString m_typeSystemFileName;
+ QFileInfoList m_cppFileNames;
+ HeaderPaths m_includePaths;
+ QStringList m_clangOptions;
+ QString m_logDirectory;
+ LanguageLevel m_languageLevel = LanguageLevel::Default;
+ bool m_skipDeprecated = false;
+};
+
+static inline QString languageLevelDescription()
+{
+ return u"C++ Language level (c++11..c++17, default="_s
+ + QLatin1StringView(clang::languageLevelOption(clang::emulatedCompilerLanguageLevel()))
+ + u')';
+}
+
+QList<OptionDescription> ApiExtractor::options()
+{
+ return {
+ {u"use-global-header"_s,
+ u"Use the global headers in generated code."_s},
+ {u"clang-option"_s,
+ u"Option to be passed to clang"_s},
+ {u"clang-options"_s,
+ u"A comma-separated list of options to be passed to clang"_s},
+ {u"skip-deprecated"_s,
+ u"Skip deprecated functions"_s},
+ {u"-F<path>"_s, {} },
+ {u"framework-include-paths="_s + OptionsParser::pathSyntax(),
+ u"Framework include paths used by the C++ parser"_s},
+ {u"-isystem<path>"_s, {} },
+ {u"system-include-paths="_s + OptionsParser::pathSyntax(),
+ u"System include paths used by the C++ parser"_s},
+ {u"language-level=, -std=<level>"_s,
+ languageLevelDescription()},
+ };
+}
+
+class ApiExtractorOptionsParser : public OptionsParser
+{
+public:
+ explicit ApiExtractorOptionsParser(ApiExtractorOptions *o) : m_options(o) {}
+
+ bool handleBoolOption(const QString &key, OptionSource source) override;
+ bool handleOption(const QString &key, const QString &value,
+ OptionSource source) override;
+
+private:
+ void parseIncludePathOption(const QString &value, HeaderType headerType);
+ void parseIncludePathOption(const QStringList &values, HeaderType headerType);
+ void setLanguageLevel(const QString &value);
+
+ ApiExtractorOptions *m_options;
+};
+
+void ApiExtractorOptionsParser::parseIncludePathOption(const QString &value,
+ HeaderType headerType)
+{
+ if (value.isEmpty())
+ throw Exception(u"Empty value passed to include path option"_s);
+ const auto path = QFile::encodeName(QDir::cleanPath(value));
+ m_options->m_includePaths.append(HeaderPath{path, headerType});
+}
+
+void ApiExtractorOptionsParser::parseIncludePathOption(const QStringList &values,
+ HeaderType headerType)
+{
+ for (const auto &value : values)
+ parseIncludePathOption(value, headerType);
+}
+
+void ApiExtractorOptionsParser::setLanguageLevel(const QString &value)
+{
+ const QByteArray languageLevelBA = value.toLatin1();
+ const LanguageLevel level = clang::languageLevelFromOption(languageLevelBA.constData());
+ if (level == LanguageLevel::Default)
+ throw Exception(msgInvalidLanguageLevel(value));
+ m_options->m_languageLevel = level;
+}
+
+bool ApiExtractorOptionsParser::handleBoolOption(const QString &key, OptionSource source)
+{
+ static const auto isystemOption = "isystem"_L1;
+
+ switch (source) {
+ case OptionSource::CommandLine:
+ case OptionSource::ProjectFile:
+ if (key == u"use-global-header") {
+ AbstractMetaBuilder::setUseGlobalHeader(true);
+ return true;
+ }
+ if (key == u"skip-deprecated") {
+ m_options->m_skipDeprecated = true;
+ return true;
+ }
+ break;
+
+ case OptionSource::CommandLineSingleDash:
+ if (key.startsWith(u'I')) { // Shorthand path arguments -I/usr/include...
+ parseIncludePathOption(key.sliced(1), HeaderType::Standard);
+ return true;
+ }
+ if (key.startsWith(u'F')) {
+ parseIncludePathOption(key.sliced(1), HeaderType::Framework);
+ return true;
+ }
+ if (key.startsWith(isystemOption)) {
+ parseIncludePathOption(key.sliced(isystemOption.size()), HeaderType::System);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+bool ApiExtractorOptionsParser::handleOption(const QString &key, const QString &value,
+ OptionSource source)
+{
+ if (source == OptionSource::CommandLineSingleDash) {
+ if (key == u"std") {
+ setLanguageLevel(value);
+ return true;
+ }
+ return false;
+ }
+
+ if (key == u"clang-option") {
+ m_options->m_clangOptions.append(value);
+ return true;
+ }
+ if (key == u"clang-options") {
+ m_options->m_clangOptions.append(value.split(u',', Qt::SkipEmptyParts));
+ return true;
+ }
+ if (key == u"include-paths") {
+ parseIncludePathOption(value.split(QDir::listSeparator(), Qt::SkipEmptyParts),
+ HeaderType::Standard);
+ return true;
+ }
+ if (key == u"framework-include-paths") {
+ parseIncludePathOption(value.split(QDir::listSeparator(), Qt::SkipEmptyParts),
+ HeaderType::Framework);
+ return true;
+ }
+ if (key == u"system-include-paths") {
+ parseIncludePathOption(value.split(QDir::listSeparator(), Qt::SkipEmptyParts),
+ HeaderType::System);
+ return true;
+ }
+ if (key == u"language-level") {
+ setLanguageLevel(value);
+ return true;
+ }
+
+ if (source == OptionSource::ProjectFile) {
+ if (key == u"include-path") {
+ parseIncludePathOption(value, HeaderType::Standard);
+ return true;
+ }
+ if (key == u"framework-include-path") {
+ parseIncludePathOption(value, HeaderType::Framework);
+ return true;
+ }
+ if (key == u"system-include-path") {
+ parseIncludePathOption(value, HeaderType::System);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+std::shared_ptr<OptionsParser> ApiExtractor::createOptionsParser()
+{
+ return std::make_shared<ApiExtractorOptionsParser>(d);
+}
+
+struct ApiExtractorPrivate : public ApiExtractorOptions
+{
+ bool runHelper(ApiExtractorFlags flags);
+
+ static QString getSimplifiedContainerTypeName(const AbstractMetaType &type);
+ void addInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context,
+ const AbstractMetaType &type,
+ const QString &contextName);
+ void collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context,
+ const AbstractMetaFunctionCPtr &func);
+ void collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context,
+ const AbstractMetaClassCPtr &metaClass);
+ void collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context);
+ void collectInstantiatedOpqaqueContainers(InstantiationCollectContext &context);
+ void collectContainerTypesFromSnippets(InstantiationCollectContext &context);
+ void collectContainerTypesFromConverterMacros(InstantiationCollectContext &context,
+ const QString &code,
+ bool toPythonMacro);
+ void addInstantiatedSmartPointer(InstantiationCollectContext &context,
+ const AbstractMetaType &type);
+
+ AbstractMetaBuilder *m_builder = nullptr;
+};
+
+ApiExtractor::ApiExtractor() :
+ d(new ApiExtractorPrivate)
+{
+}
+
+ApiExtractor::~ApiExtractor()
+{
+ delete d->m_builder;
+ delete d;
+}
+
+HeaderPaths ApiExtractor::includePaths() const
+{
+ return d->m_includePaths;
+}
+
+void ApiExtractor::setLogDirectory(const QString& logDir)
+{
+ d->m_logDirectory = logDir;
+}
+
+void ApiExtractor::setCppFileNames(const QFileInfoList &cppFileName)
+{
+ d->m_cppFileNames = cppFileName;
+}
+
+QFileInfoList ApiExtractor::cppFileNames() const
+{
+ return d->m_cppFileNames;
+}
+
+void ApiExtractor::setTypeSystem(const QString& typeSystemFileName)
+{
+ d->m_typeSystemFileName = typeSystemFileName;
+}
+
+QString ApiExtractor::typeSystem() const
+{
+ return d->m_typeSystemFileName;
+}
+
+const AbstractMetaEnumList &ApiExtractor::globalEnums() const
+{
+ Q_ASSERT(d->m_builder);
+ return d->m_builder->globalEnums();
+}
+
+const AbstractMetaFunctionCList &ApiExtractor::globalFunctions() const
+{
+ Q_ASSERT(d->m_builder);
+ return d->m_builder->globalFunctions();
+}
+
+const AbstractMetaClassList &ApiExtractor::classes() const
+{
+ Q_ASSERT(d->m_builder);
+ return d->m_builder->classes();
+}
+
+const AbstractMetaClassList &ApiExtractor::smartPointers() const
+{
+ Q_ASSERT(d->m_builder);
+ return d->m_builder->smartPointers();
+}
+
+// Add defines required for parsing Qt code headers
+static void addPySideExtensions(QByteArrayList *a)
+{
+ // Make "signals:", "slots:" visible as access specifiers
+ a->append(QByteArrayLiteral("-DQT_ANNOTATE_ACCESS_SPECIFIER(a)=__attribute__((annotate(#a)))"));
+
+ // Q_PROPERTY is defined as class annotation which does not work since a
+ // sequence of properties will to expand to a sequence of annotations
+ // annotating nothing, causing clang to complain. Instead, define it away in a
+ // static assert with the stringified argument in a ','-operator (cf qdoc).
+ a->append(QByteArrayLiteral("-DQT_ANNOTATE_CLASS(type,...)=static_assert(sizeof(#__VA_ARGS__),#type);"));
+
+ // With Qt6, qsimd.h became public header and was included in <QtCore>. That
+ // introduced a conflict with libclang headers on macOS. To be able to include
+ // <QtCore>, we prevent its inclusion by adding its include guard.
+ a->append(QByteArrayLiteral("-DQSIMD_H"));
+}
+
+bool ApiExtractorPrivate::runHelper(ApiExtractorFlags flags)
+{
+ if (m_builder)
+ return false;
+
+ if (!TypeDatabase::instance()->parseFile(m_typeSystemFileName)) {
+ std::cerr << "Cannot parse file: " << qPrintable(m_typeSystemFileName);
+ return false;
+ }
+
+ const QString pattern = QDir::tempPath() + u'/'
+ + m_cppFileNames.constFirst().baseName() + "_XXXXXX.hpp"_L1;
+ QTemporaryFile ppFile(pattern);
+ bool autoRemove = !qEnvironmentVariableIsSet("KEEP_TEMP_FILES");
+ // make sure that a tempfile can be written
+ if (!ppFile.open()) {
+ std::cerr << "could not create tempfile " << qPrintable(pattern)
+ << ": " << qPrintable(ppFile.errorString()) << '\n';
+ return false;
+ }
+ for (const auto &cppFileName : std::as_const(m_cppFileNames)) {
+ ppFile.write("#include \"");
+ ppFile.write(cppFileName.absoluteFilePath().toLocal8Bit());
+ ppFile.write("\"\n");
+ }
+ const QString preprocessedCppFileName = ppFile.fileName();
+ ppFile.close();
+ m_builder = new AbstractMetaBuilder;
+ m_builder->setLogDirectory(m_logDirectory);
+ m_builder->setGlobalHeaders(m_cppFileNames);
+ m_builder->setSkipDeprecated(m_skipDeprecated);
+ m_builder->setHeaderPaths(m_includePaths);
+ m_builder->setApiExtractorFlags(flags);
+
+ QByteArrayList arguments;
+ const auto clangOptionsSize = m_clangOptions.size();
+ arguments.reserve(m_includePaths.size() + clangOptionsSize + 1);
+
+ bool addCompilerSupportArguments = true;
+ if (clangOptionsSize > 0) {
+ qsizetype i = 0;
+ if (m_clangOptions.at(i) == u"-") {
+ ++i;
+ addCompilerSupportArguments = false; // No built-in options
+ }
+ for (; i < clangOptionsSize; ++i)
+ arguments.append(m_clangOptions.at(i).toUtf8());
+ }
+
+ for (const HeaderPath &headerPath : std::as_const(m_includePaths))
+ arguments.append(HeaderPath::includeOption(headerPath));
+ if (flags.testFlag(ApiExtractorFlag::UsePySideExtensions))
+ addPySideExtensions(&arguments);
+ arguments.append(QFile::encodeName(preprocessedCppFileName));
+
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug)) {
+ qCInfo(lcShiboken).noquote().nospace()
+ << "clang language level: " << int(m_languageLevel)
+ << "\nclang arguments: " << arguments;
+ }
+
+ const bool result = m_builder->build(arguments, flags, addCompilerSupportArguments,
+ m_languageLevel);
+ if (!result)
+ autoRemove = false;
+ if (!autoRemove) {
+ ppFile.setAutoRemove(false);
+ std::cerr << "Keeping temporary file: " << qPrintable(QDir::toNativeSeparators(preprocessedCppFileName)) << '\n';
+ }
+ return result;
+}
+
+static inline void classListToCList(const AbstractMetaClassList &list, AbstractMetaClassCList *target)
+{
+ target->reserve(list.size());
+ std::copy(list.cbegin(), list.cend(), std::back_inserter(*target));
+}
+
+std::optional<ApiExtractorResult> ApiExtractor::run(ApiExtractorFlags flags)
+{
+ if (!d->runHelper(flags))
+ return {};
+ InstantiationCollectContext collectContext;
+ d->collectInstantiatedContainersAndSmartPointers(collectContext);
+
+ ApiExtractorResult result;
+ classListToCList(d->m_builder->takeClasses(), &result.m_metaClasses);
+ classListToCList(d->m_builder->takeSmartPointers(), &result.m_smartPointers);
+ result.m_globalFunctions = d->m_builder->globalFunctions();
+ result.m_globalEnums = d->m_builder->globalEnums();
+ result.m_enums = d->m_builder->typeEntryToEnumsHash();
+ result.m_flags = flags;
+ result.m_typedefTargetToName = d->m_builder->typedefTargetToName();
+ qSwap(result.m_instantiatedContainers, collectContext.instantiatedContainers);
+ qSwap(result.m_instantiatedSmartPointers, collectContext.instantiatedSmartPointers);
+ return result;
+}
+
+LanguageLevel ApiExtractor::languageLevel() const
+{
+ return d->m_languageLevel;
+}
+
+QStringList ApiExtractor::clangOptions() const
+{
+ return d->m_clangOptions;
+}
+
+AbstractMetaFunctionPtr
+ ApiExtractor::inheritTemplateFunction(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes)
+{
+ return AbstractMetaBuilder::inheritTemplateFunction(function, templateTypes);
+}
+
+AbstractMetaFunctionPtr
+ ApiExtractor::inheritTemplateMember(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaClassPtr &subclass)
+{
+ return AbstractMetaBuilder::inheritTemplateMember(function, templateTypes,
+ templateClass, subclass);
+}
+
+AbstractMetaClassPtr ApiExtractor::inheritTemplateClass(const ComplexTypeEntryPtr &te,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaTypeList &templateTypes)
+{
+ return AbstractMetaBuilder::inheritTemplateClass(te, templateClass,
+ templateTypes);
+}
+
+QString ApiExtractorPrivate::getSimplifiedContainerTypeName(const AbstractMetaType &type)
+{
+ const QString signature = type.cppSignature();
+ if (!type.typeEntry()->isContainer() && !type.typeEntry()->isSmartPointer())
+ return signature;
+ QString typeName = signature;
+ if (type.isConstant())
+ typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
+ switch (type.referenceType()) {
+ case NoReference:
+ break;
+ case LValueReference:
+ typeName.chop(1);
+ break;
+ case RValueReference:
+ typeName.chop(2);
+ break;
+ }
+ while (typeName.endsWith(u'*') || typeName.endsWith(u' '))
+ typeName.chop(1);
+ return typeName;
+}
+
+// Strip a "const QSharedPtr<const Foo> &" or similar to "QSharedPtr<Foo>" (PYSIDE-1016/454)
+AbstractMetaType canonicalSmartPtrInstantiation(const AbstractMetaType &type)
+{
+ const AbstractMetaTypeList &instantiations = type.instantiations();
+ Q_ASSERT(instantiations.size() == 1);
+ const bool needsFix = type.isConstant() || type.referenceType() != NoReference;
+ const bool pointeeNeedsFix = instantiations.constFirst().isConstant();
+ if (!needsFix && !pointeeNeedsFix)
+ return type;
+ auto fixedType = type;
+ fixedType.setReferenceType(NoReference);
+ fixedType.setConstant(false);
+ if (pointeeNeedsFix) {
+ auto fixedPointeeType = instantiations.constFirst();
+ fixedPointeeType.setConstant(false);
+ fixedType.setInstantiations(AbstractMetaTypeList(1, fixedPointeeType));
+ }
+ return fixedType;
+}
+
+static inline TypeEntryCPtr pointeeTypeEntry(const AbstractMetaType &smartPtrType)
+{
+ return smartPtrType.instantiations().constFirst().typeEntry();
+}
+
+static AbstractMetaType simplifiedType(AbstractMetaType type)
+{
+ type.setIndirections(0);
+ type.setConstant(false);
+ type.setReferenceType(NoReference);
+ type.decideUsagePattern();
+ return type;
+}
+
+void
+ApiExtractorPrivate::addInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context,
+ const AbstractMetaType &type,
+ const QString &contextName)
+{
+ for (const auto &t : type.instantiations())
+ addInstantiatedContainersAndSmartPointers(context, t, contextName);
+ const auto typeEntry = type.typeEntry();
+ const bool isContainer = typeEntry->isContainer();
+ if (!isContainer
+ && !(typeEntry->isSmartPointer() && typeEntry->generateCode())) {
+ return;
+ }
+ if (type.hasTemplateChildren()) {
+ const auto piece = isContainer ? "container"_L1 : "smart pointer"_L1;
+ QString warning =
+ QString::fromLatin1("Skipping instantiation of %1 '%2' because it has template"
+ " arguments.").arg(piece, type.originalTypeDescription());
+ if (!contextName.isEmpty())
+ warning.append(" Calling context: "_L1 + contextName);
+
+ qCWarning(lcShiboken).noquote().nospace() << warning;
+ return;
+
+ }
+ if (isContainer) {
+ const QString typeName = getSimplifiedContainerTypeName(type);
+ if (!context.instantiatedContainersNames.contains(typeName)) {
+ context.instantiatedContainersNames.append(typeName);
+ context.instantiatedContainers.append(simplifiedType(type));
+ }
+ return;
+ }
+
+ // Is smart pointer. Check if the (const?) pointee is already known for the given
+ // smart pointer type entry.
+ auto pt = pointeeTypeEntry(type);
+ const bool present =
+ std::any_of(context.instantiatedSmartPointers.cbegin(),
+ context.instantiatedSmartPointers.cend(),
+ [typeEntry, pt] (const InstantiatedSmartPointer &smp) {
+ return smp.type.typeEntry() == typeEntry
+ && pointeeTypeEntry(smp.type) == pt;
+ });
+ if (!present)
+ addInstantiatedSmartPointer(context, type);
+}
+
+// Create a modification that invalidates the pointee argument of a smart
+// pointer constructor or reset().
+static FunctionModification invalidateArgMod(const AbstractMetaFunctionCPtr &f, int index = 1)
+{
+ ArgumentModification argMod;
+ argMod.setTargetOwnerShip(TypeSystem::CppOwnership);
+ argMod.setIndex(index);
+ FunctionModification funcMod;
+ funcMod.setSignature(f->minimalSignature());
+ funcMod.setArgument_mods({argMod});
+ return funcMod;
+}
+
+static void addOwnerModification(const AbstractMetaFunctionCList &functions,
+ const ComplexTypeEntryPtr &typeEntry)
+{
+ for (const auto &f : functions) {
+ if (!f->arguments().isEmpty()
+ && f->arguments().constFirst().type().indirections() > 0) {
+ std::const_pointer_cast<AbstractMetaFunction>(f)->clearModificationsCache();
+ typeEntry->addFunctionModification(invalidateArgMod(f));
+ }
+ }
+}
+
+void ApiExtractorPrivate::addInstantiatedSmartPointer(InstantiationCollectContext &context,
+ const AbstractMetaType &type)
+{
+ InstantiatedSmartPointer smp;
+ smp.type = canonicalSmartPtrInstantiation(type);
+ smp.smartPointer = AbstractMetaClass::findClass(m_builder->smartPointers(),
+ type.typeEntry());
+ Q_ASSERT(smp.smartPointer);
+
+ const auto &instantiatedType = type.instantiations().constFirst();
+ const auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(smp.smartPointer->typeEntry());
+ QString name = ste->getTargetName(smp.type);
+ auto parentTypeEntry = ste->parent();
+
+ // 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;
+ if (withinNameSpace) { // user defined
+ const QString nameSpace = name.left(colonPos);
+ name.remove(0, colonPos + 2);
+ const auto nameSpaces = TypeDatabase::instance()->findNamespaceTypes(nameSpace);
+ if (nameSpaces.isEmpty())
+ throw Exception(msgNamespaceNotFound(name));
+ parentTypeEntry = nameSpaces.constFirst();
+ }
+
+ 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});
+ Q_ASSERT(smp.specialized);
+ 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);
+ specialized->setEnclosingClass(enclClass);
+ enclClass->addInnerClass(specialized);
+ }
+
+ if (instantiationEntry->isComplex()) {
+ addOwnerModification(smp.specialized->queryFunctions(FunctionQueryOption::Constructors),
+ instantiationEntry);
+ if (!ste->resetMethod().isEmpty()) {
+ addOwnerModification(smp.specialized->findFunctions(ste->resetMethod()),
+ instantiationEntry);
+ }
+ }
+
+ context.instantiatedSmartPointers.append(smp);
+}
+
+void
+ApiExtractorPrivate::collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context,
+ const AbstractMetaFunctionCPtr &func)
+{
+ addInstantiatedContainersAndSmartPointers(context, func->type(), func->signature());
+ for (const AbstractMetaArgument &arg : func->arguments()) {
+ const auto argType = arg.type();
+ const auto type = argType.viewOn() != nullptr ? *argType.viewOn() : argType;
+ addInstantiatedContainersAndSmartPointers(context, type, func->signature());
+ }
+}
+
+void
+ApiExtractorPrivate::collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ if (!metaClass->typeEntry()->generateCode())
+ return;
+ for (const auto &func : metaClass->functions())
+ collectInstantiatedContainersAndSmartPointers(context, func);
+ for (const auto &func : metaClass->userAddedPythonOverrides())
+ collectInstantiatedContainersAndSmartPointers(context, func);
+ for (const AbstractMetaField &field : metaClass->fields())
+ addInstantiatedContainersAndSmartPointers(context, field.type(), field.name());
+
+ // The list of inner classes might be extended when smart pointer
+ // instantiations are specified to be in namespaces.
+ const auto &innerClasses = metaClass->innerClasses();
+ for (auto i = innerClasses.size() - 1; i >= 0; --i) {
+ const auto innerClass = innerClasses.at(i);
+ if (!innerClass->typeEntry()->isSmartPointer())
+ collectInstantiatedContainersAndSmartPointers(context, innerClass);
+ }
+}
+
+void
+ApiExtractorPrivate::collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context)
+{
+ collectInstantiatedOpqaqueContainers(context);
+ for (const auto &func : m_builder->globalFunctions())
+ collectInstantiatedContainersAndSmartPointers(context, func);
+ for (const auto &metaClass : m_builder->classes())
+ collectInstantiatedContainersAndSmartPointers(context, metaClass);
+ collectContainerTypesFromSnippets(context);
+}
+
+// Whether to generate an opaque container: If the instantiation type is in
+// the current package or, for primitive types, if the container is in the
+// current package.
+static bool generateOpaqueContainer(const AbstractMetaType &type,
+ const TypeSystemTypeEntryCPtr &moduleEntry)
+{
+ auto te = type.instantiations().constFirst().typeEntry();
+ auto typeModuleEntry = typeSystemTypeEntry(te);
+ return typeModuleEntry == moduleEntry
+ || (te->isPrimitive() && typeSystemTypeEntry(type.typeEntry()) == moduleEntry);
+}
+
+void ApiExtractorPrivate::collectInstantiatedOpqaqueContainers(InstantiationCollectContext &context)
+{
+ // Add all instantiations of opaque containers for types from the current
+ // module.
+ auto *td = TypeDatabase::instance();
+ const auto moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
+ const auto &containers = td->containerTypes();
+ for (const auto &container : containers) {
+ for (const auto &oc : container->opaqueContainers()) {
+ QString errorMessage;
+ const QString typeName = container->qualifiedCppName() + oc.templateParameters();
+ auto typeOpt = AbstractMetaType::fromString(typeName, &errorMessage);
+ if (typeOpt.has_value()
+ && generateOpaqueContainer(typeOpt.value(), moduleEntry)) {
+ addInstantiatedContainersAndSmartPointers(context, typeOpt.value(),
+ u"opaque containers"_s);
+ }
+ }
+ }
+}
+
+static void getCode(QStringList &code, const CodeSnipList &codeSnips)
+{
+ for (const CodeSnip &snip : std::as_const(codeSnips))
+ code.append(snip.code());
+}
+
+static void getCode(QStringList &code, const TypeEntryCPtr &type)
+{
+ if (type->isComplex())
+ getCode(code, std::static_pointer_cast<const ComplexTypeEntry>(type)->codeSnips());
+ else if (type->isTypeSystem())
+ getCode(code, std::static_pointer_cast<const TypeSystemTypeEntry>(type)->codeSnips());
+
+ auto customConversion = CustomConversion::getCustomConversion(type);
+ if (!customConversion)
+ return;
+
+ if (!customConversion->nativeToTargetConversion().isEmpty())
+ code.append(customConversion->nativeToTargetConversion());
+
+ const auto &toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+
+ for (const auto &toNative : std::as_const(toCppConversions))
+ code.append(toNative.conversion());
+}
+
+void ApiExtractorPrivate::collectContainerTypesFromSnippets(InstantiationCollectContext &context)
+{
+ QStringList snips;
+ auto *td = TypeDatabase::instance();
+ const PrimitiveTypeEntryCList &primitiveTypeList = td->primitiveTypes();
+ for (const auto &type : primitiveTypeList)
+ getCode(snips, type);
+ const ContainerTypeEntryCList &containerTypeList = td->containerTypes();
+ for (const auto &type : containerTypeList)
+ getCode(snips, type);
+ for (const auto &metaClass : m_builder->classes())
+ getCode(snips, metaClass->typeEntry());
+
+ const auto moduleEntry = td->defaultTypeSystemType();
+ Q_ASSERT(moduleEntry);
+ getCode(snips, moduleEntry);
+
+ for (const auto &func : m_builder->globalFunctions())
+ getCode(snips, func->injectedCodeSnips());
+
+ for (const QString &code : std::as_const(snips)) {
+ collectContainerTypesFromConverterMacros(context, code, true);
+ collectContainerTypesFromConverterMacros(context, code, false);
+ }
+}
+
+void
+ApiExtractorPrivate::collectContainerTypesFromConverterMacros(InstantiationCollectContext &context,
+ const QString &code,
+ bool toPythonMacro)
+{
+ QString convMacro = toPythonMacro ? u"%CONVERTTOPYTHON["_s : u"%CONVERTTOCPP["_s;
+ const qsizetype offset = toPythonMacro ? sizeof("%CONVERTTOPYTHON") : sizeof("%CONVERTTOCPP");
+ qsizetype start = 0;
+ QString errorMessage;
+ while ((start = code.indexOf(convMacro, start)) != -1) {
+ int end = code.indexOf(u']', start);
+ start += offset;
+ if (code.at(start) != u'%') {
+ QString typeString = code.mid(start, end - start);
+ auto type = AbstractMetaType::fromString(typeString, &errorMessage);
+ if (type.has_value()) {
+ const QString &d = type->originalTypeDescription();
+ addInstantiatedContainersAndSmartPointers(context, type.value(), d);
+ } else {
+ QString m;
+ QTextStream(&m) << __FUNCTION__ << ": Cannot translate type \""
+ << typeString << "\": " << errorMessage;
+ throw Exception(m);
+ }
+ }
+ start = end;
+ }
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class Container>
+static void debugFormatSequence(QDebug &d, const char *key, const Container& c)
+{
+ if (c.isEmpty())
+ return;
+ const auto begin = c.begin();
+ d << "\n " << key << '[' << c.size() << "]=(";
+ for (auto it = begin, end = c.end(); it != end; ++it) {
+ if (it != begin)
+ d << ", ";
+ d << *it;
+ }
+ d << ')';
+}
+
+QDebug operator<<(QDebug d, const ApiExtractor &ae)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ if (ReportHandler::debugLevel() >= ReportHandler::FullDebug)
+ d.setVerbosity(3); // Trigger verbose output of AbstractMetaClass
+ d << "ApiExtractor(typeSystem=\"" << ae.typeSystem() << "\", cppFileNames=\""
+ << ae.cppFileNames() << ", ";
+ ae.d->m_builder->formatDebug(d);
+ d << ')';
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/apiextractor.h b/sources/shiboken6/ApiExtractor/apiextractor.h
new file mode 100644
index 000000000..7bff5c252
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/apiextractor.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef APIEXTRACTOR_H
+#define APIEXTRACTOR_H
+
+#include "abstractmetalang_typedefs.h"
+#include "apiextractorflags.h"
+#include "header_paths.h"
+#include "clangparser/compilersupport.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QFileInfoList>
+#include <QtCore/QStringList>
+
+#include <optional>
+
+class ApiExtractorResult;
+class AbstractMetaClass;
+class AbstractMetaEnum;
+class AbstractMetaFunction;
+class ComplexTypeEntry;
+struct OptionDescription;
+class OptionsParser;
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+class QIODevice;
+QT_END_NAMESPACE
+
+struct ApiExtractorPrivate;
+
+class ApiExtractor
+{
+public:
+ Q_DISABLE_COPY_MOVE(ApiExtractor)
+
+ ApiExtractor();
+ ~ApiExtractor();
+
+ static QList<OptionDescription> options();
+ std::shared_ptr<OptionsParser> createOptionsParser();
+
+ void setTypeSystem(const QString& typeSystemFileName);
+ QString typeSystem() const;
+ void setCppFileNames(const QFileInfoList &cppFileNames);
+ QFileInfoList cppFileNames() const;
+ HeaderPaths includePaths() const;
+ void setLogDirectory(const QString& logDir);
+ LanguageLevel languageLevel() const;
+ QStringList clangOptions() const;
+
+ const AbstractMetaEnumList &globalEnums() const;
+ const AbstractMetaFunctionCList &globalFunctions() const;
+ const AbstractMetaClassList &classes() const;
+ const AbstractMetaClassList &smartPointers() const;
+
+ std::optional<ApiExtractorResult> run(ApiExtractorFlags flags);
+
+ /// Forwards to AbstractMetaBuilder::inheritTemplateFunction()
+ static AbstractMetaFunctionPtr
+ inheritTemplateFunction(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes);
+
+ /// Forwards to AbstractMetaBuilder::inheritTemplateMember()
+ static AbstractMetaFunctionPtr
+ inheritTemplateMember(const AbstractMetaFunctionCPtr &function,
+ const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaClassPtr &subclass);
+
+ /// Forwards to AbstractMetaBuilder::inheritTemplateClass()
+ static AbstractMetaClassPtr
+ inheritTemplateClass(const ComplexTypeEntryPtr &te,
+ const AbstractMetaClassCPtr &templateClass,
+ const AbstractMetaTypeList &templateTypes);
+
+private:
+ ApiExtractorPrivate *d;
+
+#ifndef QT_NO_DEBUG_STREAM
+ friend QDebug operator<<(QDebug d, const ApiExtractor &ae);
+#endif
+};
+
+#endif // APIEXTRACTOR_H
+
diff --git a/sources/shiboken6/ApiExtractor/apiextractorflags.h b/sources/shiboken6/ApiExtractor/apiextractorflags.h
new file mode 100644
index 000000000..6f69b8b77
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/apiextractorflags.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef APIEXTRACTORFLAGS_H
+#define APIEXTRACTORFLAGS_H
+
+#include <QtCore/QFlags>
+
+enum class ApiExtractorFlag
+{
+ UsePySideExtensions = 0x1,
+ AvoidProtectedHack = 0x2
+};
+
+Q_DECLARE_FLAGS(ApiExtractorFlags, ApiExtractorFlag)
+Q_DECLARE_OPERATORS_FOR_FLAGS(ApiExtractorFlags)
+
+#endif // APIEXTRACTORFLAGS_H
diff --git a/sources/shiboken6/ApiExtractor/apiextractorresult.cpp b/sources/shiboken6/ApiExtractor/apiextractorresult.cpp
new file mode 100644
index 000000000..b53ffa9b6
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/apiextractorresult.cpp
@@ -0,0 +1,103 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "apiextractorresult.h"
+#include "abstractmetalang.h"
+#include "abstractmetaenum.h"
+
+#include "enumtypeentry.h"
+#include "flagstypeentry.h"
+
+ApiExtractorResult::ApiExtractorResult() = default;
+
+ApiExtractorResult::ApiExtractorResult(const ApiExtractorResult &) = default;
+
+ApiExtractorResult &ApiExtractorResult::operator=(const ApiExtractorResult &) = default;
+
+ApiExtractorResult::ApiExtractorResult(ApiExtractorResult &&) noexcept = default;
+
+ApiExtractorResult &ApiExtractorResult::operator=(ApiExtractorResult &&) noexcept = default;
+
+ApiExtractorResult::~ApiExtractorResult() = default;
+
+const AbstractMetaEnumList &ApiExtractorResult::globalEnums() const
+{
+ return m_globalEnums;
+}
+
+const AbstractMetaFunctionCList &ApiExtractorResult::globalFunctions() const
+{
+ return m_globalFunctions;
+}
+
+const AbstractMetaClassCList &ApiExtractorResult::classes() const
+{
+ return m_metaClasses;
+}
+
+const AbstractMetaClassCList &ApiExtractorResult::smartPointers() const
+{
+ return m_smartPointers;
+}
+
+const AbstractMetaTypeList &ApiExtractorResult::instantiatedContainers() const
+{
+ return m_instantiatedContainers;
+}
+
+const InstantiatedSmartPointers &ApiExtractorResult::instantiatedSmartPointers() const
+{
+ 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;
+}
+
+ApiExtractorFlags ApiExtractorResult::flags() const
+{
+ return m_flags;
+}
+
+void ApiExtractorResult::setFlags(ApiExtractorFlags f)
+{
+ m_flags = f;
+}
+
+std::optional<AbstractMetaEnum>
+ ApiExtractorResult::findAbstractMetaEnum(TypeEntryCPtr typeEntry) const
+{
+ if (typeEntry && typeEntry->isFlags())
+ typeEntry = std::static_pointer_cast<const FlagsTypeEntry>(typeEntry)->originator();
+ const auto it = m_enums.constFind(typeEntry);
+ if (it == m_enums.constEnd())
+ return {};
+ return it.value();
+}
+
+AbstractMetaFunctionCList ApiExtractorResult::implicitConversions(const TypeEntryCPtr &type) const
+{
+ if (type->isValue()) {
+ if (auto metaClass = AbstractMetaClass::findClass(m_metaClasses, type))
+ return metaClass->implicitConversions();
+ }
+ return {};
+}
+
+AbstractMetaFunctionCList ApiExtractorResult::implicitConversions(const AbstractMetaType &metaType) const
+{
+ return implicitConversions(metaType.typeEntry());
+}
diff --git a/sources/shiboken6/ApiExtractor/apiextractorresult.h b/sources/shiboken6/ApiExtractor/apiextractorresult.h
new file mode 100644
index 000000000..b2aae88ed
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/apiextractorresult.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef APIEXTRACTORRESULT_H
+#define APIEXTRACTORRESULT_H
+
+#include "apiextractorflags.h"
+#include "abstractmetatype.h"
+#include "abstractmetalang_typedefs.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QMultiHash>
+
+#include <optional>
+
+class ApiExtractorResultData;
+
+struct InstantiatedSmartPointer
+{
+ AbstractMetaClassCPtr smartPointer; // Template class
+ AbstractMetaClassCPtr specialized; // Specialized for type
+ AbstractMetaType type;
+};
+
+using InstantiatedSmartPointers = QList<InstantiatedSmartPointer>;
+
+/// Result of an ApiExtractor run.
+class ApiExtractorResult
+{
+public:
+ ApiExtractorResult();
+ ApiExtractorResult(const ApiExtractorResult &);
+ ApiExtractorResult &operator=(const ApiExtractorResult &);
+ ApiExtractorResult(ApiExtractorResult &&) noexcept;
+ ApiExtractorResult &operator=(ApiExtractorResult &&) noexcept;
+ ~ApiExtractorResult();
+
+ const AbstractMetaEnumList &globalEnums() const;
+ const AbstractMetaFunctionCList &globalFunctions() const;
+ const AbstractMetaClassCList &classes() const;
+ const AbstractMetaClassCList &smartPointers() const;
+
+ 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;
+
+ // Query functions for the generators
+ std::optional<AbstractMetaEnum>
+ findAbstractMetaEnum(TypeEntryCPtr typeEntry) const;
+
+ /// Retrieves a list of constructors used in implicit conversions
+ /// available on the given type. The TypeEntry must be a value-type
+ /// or else it will return an empty list.
+ /// \param type a TypeEntry that is expected to be a value-type
+ /// \return a list of constructors that could be used as implicit converters
+ AbstractMetaFunctionCList implicitConversions(const TypeEntryCPtr &type) const;
+ AbstractMetaFunctionCList implicitConversions(const AbstractMetaType &metaType) const;
+
+ ApiExtractorFlags flags() const;
+ void setFlags(ApiExtractorFlags f);
+
+private:
+ AbstractMetaClassCList m_metaClasses;
+ AbstractMetaClassCList m_smartPointers;
+ AbstractMetaFunctionCList m_globalFunctions;
+ AbstractMetaEnumList m_globalEnums;
+ AbstractMetaTypeList m_instantiatedContainers;
+ InstantiatedSmartPointers m_instantiatedSmartPointers;
+ QHash<TypeEntryCPtr, AbstractMetaEnum> m_enums;
+ QMultiHash<QString, QString> m_typedefTargetToName;
+ ApiExtractorFlags m_flags;
+
+ friend class ApiExtractor;
+};
+
+#endif // APIEXTRACTORRESULT_H
diff --git a/sources/shiboken6/ApiExtractor/arraytypeentry.h b/sources/shiboken6/ApiExtractor/arraytypeentry.h
new file mode 100644
index 000000000..5b9bb191e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/arraytypeentry.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ARRAYTYPEENTRY_H
+#define ARRAYTYPEENTRY_H
+
+#include "typesystem.h"
+
+class ArrayTypeEntryPrivate;
+
+class ArrayTypeEntry : public TypeEntry
+{
+public:
+ explicit ArrayTypeEntry(const TypeEntryCPtr &nested_type, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ void setNestedTypeEntry(const TypeEntryPtr &nested);
+ TypeEntryCPtr nestedTypeEntry() const;
+
+ TypeEntry *clone() const override;
+
+protected:
+ explicit ArrayTypeEntry(ArrayTypeEntryPrivate *d);
+
+ QString buildTargetLangName() const override;
+};
+
+#endif // ARRAYTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
new file mode 100644
index 000000000..31e7efb05
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
@@ -0,0 +1,1296 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "clangbuilder.h"
+#include "compilersupport.h"
+#include "clangutils.h"
+#include "clangdebugutils.h"
+
+#include <codemodel.h>
+#include <reporthandler.h>
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStack>
+#include <QtCore/QList>
+
+#include <cstring>
+#include <ctype.h>
+
+using namespace Qt::StringLiterals;
+
+namespace clang {
+
+static inline bool isClassCursor(const CXCursor &c)
+{
+ return c.kind == CXCursor_ClassDecl || c.kind == CXCursor_StructDecl
+ || c.kind == CXCursor_ClassTemplate
+ || c.kind == CXCursor_ClassTemplatePartialSpecialization;
+}
+
+static inline bool isClassOrNamespaceCursor(const CXCursor &c)
+{
+ return c.kind == CXCursor_Namespace || isClassCursor(c);
+}
+
+static inline bool withinClassDeclaration(const CXCursor &cursor)
+{
+ return isClassCursor(clang_getCursorLexicalParent(cursor));
+}
+
+static QString fixTypeName(QString t)
+{
+ // Fix "Foo &" -> "Foo&", similarly "Bar **" -> "Bar**"
+ auto pos = t.size() - 1;
+ for (; pos >= 0 && (t.at(pos) == u'&' || t.at(pos) == u'*'); --pos) {}
+ if (pos > 0 && t.at(pos) == u' ')
+ t.remove(pos, 1);
+ return t;
+}
+
+// Insert template parameter to class name: "Foo<>" -> "Foo<T1>" -> "Foo<T1,T2>"
+// This needs to be done immediately when template parameters are encountered since
+// the class name "Foo<T1,T2>" is the scope for nested items.
+static bool insertTemplateParameterIntoClassName(const QString &parmName, QString *name)
+{
+ if (Q_UNLIKELY(!name->endsWith(u'>')))
+ return false;
+ const bool needsComma = name->at(name->size() - 2) != u'<';
+ const auto insertionPos = name->size() - 1;
+ name->insert(insertionPos, parmName);
+ if (needsComma)
+ name->insert(insertionPos, u',');
+ return true;
+}
+
+static inline bool insertTemplateParameterIntoClassName(const QString &parmName,
+ const ClassModelItem &item)
+{
+ QString name = item->name();
+ const bool result = insertTemplateParameterIntoClassName(parmName, &name);
+ item->setName(name);
+ return result;
+}
+
+static inline Access accessPolicy(CX_CXXAccessSpecifier access)
+{
+ Access result = Access::Public;
+ switch (access) {
+ case CX_CXXProtected:
+ result = Access::Protected;
+ break;
+ case CX_CXXPrivate:
+ result = Access::Private;
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+static bool isSigned(CXTypeKind kind)
+{
+ switch (kind) {
+ case CXType_UChar:
+ case CXType_Char16:
+ case CXType_Char32:
+ case CXType_UShort:
+ case CXType_UInt:
+ case CXType_ULong:
+ case CXType_ULongLong:
+ case CXType_UInt128:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+class BuilderPrivate {
+public:
+ Q_DISABLE_COPY_MOVE(BuilderPrivate)
+
+ enum class SpecialSystemHeader {
+ None,
+ Types,
+ OpenGL,
+ WhiteListed,
+ WhiteListedPath
+ };
+
+ using CursorClassHash = QHash<CXCursor, ClassModelItem>;
+ using TypeInfoHash = QHash<CXType, TypeInfo>;
+
+ explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel)
+ {
+ m_scopeStack.push(NamespaceModelItem(new _FileModelItem(m_model)));
+ }
+ ~BuilderPrivate()
+ {
+ delete m_model;
+ }
+
+ // Determine scope from top item. Note that the scope list does not necessarily
+ // match the scope stack in case of forward-declared inner classes whose definition
+ // appears in the translation unit while the scope is the outer class.
+ void updateScope()
+ {
+ if (m_scopeStack.size() <= 1)
+ m_scope.clear();
+ else
+ m_scope = m_scopeStack.back()->scope() << m_scopeStack.back()->name();
+ }
+
+ void pushScope(const ScopeModelItem &i)
+ {
+ m_scopeStack.push(i);
+ updateScope();
+ }
+
+ void popScope()
+ {
+ m_scopeStack.back()->purgeClassDeclarations();
+ m_scopeStack.pop();
+ updateScope();
+ }
+
+ bool addClass(const CXCursor &cursor, CodeModel::ClassType t);
+ FunctionModelItem createFunction(const CXCursor &cursor,
+ CodeModel::FunctionType t = CodeModel::Normal,
+ bool isTemplateCode = false);
+ FunctionModelItem createMemberFunction(const CXCursor &cursor,
+ bool isTemplateCode = false);
+ void qualifyConstructor(const CXCursor &cursor);
+ TypeInfo createTypeInfoUncached(const CXType &type,
+ bool *cacheable = nullptr) const;
+ TypeInfo createTypeInfo(const CXType &type) const;
+ TypeInfo createTypeInfo(const CXCursor &cursor) const
+ { return createTypeInfo(clang_getCursorType(cursor)); }
+ void addTemplateInstantiations(const CXType &type,
+ QString *typeName,
+ TypeInfo *t) const;
+ bool addTemplateInstantiationsRecursion(const CXType &type, TypeInfo *t) const;
+
+ void addTypeDef(const CXCursor &cursor, const CXType &cxType);
+ ClassModelItem currentTemplateClass() const;
+ void startTemplateTypeAlias(const CXCursor &cursor);
+ void endTemplateTypeAlias(const CXCursor &typeAliasCursor);
+
+ TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const;
+ TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const;
+ void addField(const CXCursor &cursor);
+
+ static QString cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor);
+ std::pair<QString, ClassModelItem> getBaseClass(CXType type) const;
+ void addBaseClass(const CXCursor &cursor);
+
+ SpecialSystemHeader specialSystemHeader(const QString &fileName) const;
+ bool visitHeader(const QString &fileName) const;
+ static const char *specialSystemHeaderReason(SpecialSystemHeader sh);
+
+ void setFileName(const CXCursor &cursor, _CodeModelItem *item);
+
+ BaseVisitor *m_baseVisitor;
+ CodeModel *m_model;
+
+ QStack<ScopeModelItem> m_scopeStack;
+ QStringList m_scope;
+ // Store all classes by cursor so that base classes can be found and inner
+ // classes can be correctly parented in case of forward-declared inner classes
+ // (QMetaObject::Connection)
+ CursorClassHash m_cursorClassHash;
+
+ mutable TypeInfoHash m_typeInfoHash; // Cache type information
+ mutable QHash<QString, TemplateTypeAliasModelItem> m_templateTypeAliases;
+
+ ClassModelItem m_currentClass;
+ EnumModelItem m_currentEnum;
+ FunctionModelItem m_currentFunction;
+ ArgumentModelItem m_currentArgument;
+ VariableModelItem m_currentField;
+ TemplateTypeAliasModelItem m_currentTemplateTypeAlias;
+ QStringList m_forceProcessSystemIncludes; // files, like "memory"
+ QStringList m_forceProcessSystemIncludePaths; // paths, like "/usr/include/Qt/"
+ QString m_usingTypeRef; // Base classes in "using Base::member;"
+ bool m_withinUsingDeclaration = false;
+
+ int m_anonymousEnumCount = 0;
+ CodeModel::FunctionType m_currentFunctionType = CodeModel::Normal;
+ bool m_withinFriendDecl = false;
+ mutable QHash<QString, SpecialSystemHeader> m_systemHeaders;
+};
+
+bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t)
+{
+ QString className = getCursorSpelling(cursor);
+ m_currentClass.reset(new _ClassModelItem(m_model, className));
+ setFileName(cursor, m_currentClass.get());
+ m_currentClass->setClassType(t);
+ // Some inner class? Note that it does not need to be (lexically) contained in a
+ // class since it is possible to forward declare an inner class:
+ // class QMetaObject { class Connection; }
+ // class QMetaObject::Connection {}
+ const CXCursor semPar = clang_getCursorSemanticParent(cursor);
+ if (isClassCursor(semPar)) {
+ const CursorClassHash::const_iterator it = m_cursorClassHash.constFind(semPar);
+ if (it == m_cursorClassHash.constEnd()) {
+ QString message;
+ QTextStream(&message) << "Unable to find containing class \""
+ << getCursorSpelling(semPar) << "\" of inner class \""
+ << className << "\".";
+ // PYSIDE-1501: Has been observed to fail for inner class of
+ // template with separated implementation where a forward
+ // declaration of the outer template is reported (Boost).
+ const auto severity = semPar.kind == CXCursor_ClassTemplate
+ ? CXDiagnostic_Warning : CXDiagnostic_Error;
+ const Diagnostic d(message, cursor, severity);
+ qWarning() << d;
+ m_baseVisitor->appendDiagnostic(d);
+ return false;
+ }
+ const ClassModelItem &containingClass = it.value();
+ containingClass->addClass(m_currentClass);
+ m_currentClass->setScope(containingClass->scope() << containingClass->name());
+ } else {
+ m_currentClass->setScope(m_scope);
+ m_scopeStack.back()->addClass(m_currentClass);
+ }
+ pushScope(m_currentClass);
+ m_cursorClassHash.insert(cursor, m_currentClass);
+ return true;
+}
+
+static QString msgCannotDetermineException(const std::string_view &snippetV)
+{
+ const auto newLine = snippetV.find('\n'); // Multiline noexcept specifications have been found in Qt
+ const bool truncate = newLine != std::string::npos;
+ const qsizetype length = qsizetype(truncate ? newLine : snippetV.size());
+ QString snippet = QString::fromUtf8(snippetV.data(), length);
+ if (truncate)
+ snippet += "..."_L1;
+
+ return u"Cannot determine exception specification: \""_s + snippet + u'"';
+}
+
+// Return whether noexcept(<value>) throws. noexcept() takes a constexpr value.
+// Try to determine the simple cases (true|false) via code snippet.
+static ExceptionSpecification computedExceptionSpecificationFromClang(BaseVisitor *bv,
+ const CXCursor &cursor,
+ bool isTemplateCode)
+{
+ const std::string_view snippet = bv->getCodeSnippet(cursor);
+ if (snippet.empty())
+ return ExceptionSpecification::Unknown; // Macro expansion, cannot tell
+ if (snippet.find("noexcept(false)") != std::string::npos)
+ return ExceptionSpecification::Throws;
+ if (snippet.find("noexcept(true)") != std::string::npos)
+ return ExceptionSpecification::NoExcept;
+ // Warn about it unless it is some form of template code where it is common
+ // to have complicated code, which is of no concern to shiboken, like:
+ // "QList::emplace(T) noexcept(is_pod<T>)".
+ if (!isTemplateCode && ReportHandler::isDebug(ReportHandler::FullDebug)) {
+ const Diagnostic d(msgCannotDetermineException(snippet), cursor, CXDiagnostic_Warning);
+ qWarning() << d;
+ bv->appendDiagnostic(d);
+ }
+ return ExceptionSpecification::Unknown;
+}
+
+static ExceptionSpecification exceptionSpecificationFromClang(BaseVisitor *bv,
+ const CXCursor &cursor,
+ bool isTemplateCode)
+{
+ const auto ce = clang_getCursorExceptionSpecificationType(cursor);
+ switch (ce) {
+ case CXCursor_ExceptionSpecificationKind_ComputedNoexcept:
+ return computedExceptionSpecificationFromClang(bv, cursor, isTemplateCode);
+ case CXCursor_ExceptionSpecificationKind_BasicNoexcept:
+ case CXCursor_ExceptionSpecificationKind_DynamicNone: // throw()
+ case CXCursor_ExceptionSpecificationKind_NoThrow:
+ return ExceptionSpecification::NoExcept;
+ case CXCursor_ExceptionSpecificationKind_Dynamic: // throw(t1..)
+ case CXCursor_ExceptionSpecificationKind_MSAny: // throw(...)
+ return ExceptionSpecification::Throws;
+ default:
+ // CXCursor_ExceptionSpecificationKind_None,
+ // CXCursor_ExceptionSpecificationKind_Unevaluated,
+ // CXCursor_ExceptionSpecificationKind_Uninstantiated
+ break;
+ }
+ return ExceptionSpecification::Unknown;
+}
+
+FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor,
+ CodeModel::FunctionType t,
+ bool isTemplateCode)
+{
+ QString name = getCursorSpelling(cursor);
+ // Apply type fixes to "operator X &" -> "operator X&"
+ if (name.startsWith(u"operator "))
+ name = fixTypeName(name);
+ auto result = std::make_shared<_FunctionModelItem>(m_model, name);
+ setFileName(cursor, result.get());
+ const auto type = clang_getCursorResultType(cursor);
+ result->setType(createTypeInfo(type));
+ result->setScopeResolution(hasScopeResolution(type));
+ result->setFunctionType(t);
+ result->setScope(m_scope);
+ result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static);
+ result->setExceptionSpecification(exceptionSpecificationFromClang(m_baseVisitor, cursor, isTemplateCode));
+ switch (clang_getCursorAvailability(cursor)) {
+ case CXAvailability_Available:
+ break;
+ case CXAvailability_Deprecated:
+ result->setAttribute(FunctionAttribute::Deprecated);
+ break;
+ case CXAvailability_NotAvailable: // "Foo(const Foo&) = delete;"
+ result->setDeleted(true);
+ break;
+ case CXAvailability_NotAccessible:
+ break;
+ }
+ return result;
+}
+
+static inline CodeModel::FunctionType functionTypeFromCursor(const CXCursor &cursor)
+{
+ CodeModel::FunctionType result = CodeModel::Normal;
+ switch (cursor.kind) {
+ case CXCursor_Constructor:
+ if (clang_CXXConstructor_isCopyConstructor(cursor) != 0)
+ result = CodeModel::CopyConstructor;
+ else if (clang_CXXConstructor_isMoveConstructor(cursor) != 0)
+ result = CodeModel::MoveConstructor;
+ else
+ result = CodeModel::Constructor;
+ break;
+ case CXCursor_Destructor:
+ result = CodeModel::Destructor;
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor,
+ bool isTemplateCode)
+{
+ const CodeModel::FunctionType functionType =
+ m_currentFunctionType == CodeModel::Signal || m_currentFunctionType == CodeModel::Slot
+ ? m_currentFunctionType // by annotation
+ : functionTypeFromCursor(cursor);
+ isTemplateCode |= m_currentClass->name().endsWith(u'>');
+ auto result = createFunction(cursor, functionType, isTemplateCode);
+ result->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ result->setConstant(clang_CXXMethod_isConst(cursor) != 0);
+ result->setAttribute(FunctionAttribute::Static, clang_CXXMethod_isStatic(cursor) != 0);
+ result->setAttribute(FunctionAttribute::Virtual, clang_CXXMethod_isVirtual(cursor) != 0);
+ result->setAttribute(FunctionAttribute::Abstract, clang_CXXMethod_isPureVirtual(cursor) != 0);
+ return result;
+}
+
+// For CXCursor_Constructor, on endToken().
+void BuilderPrivate::qualifyConstructor(const CXCursor &cursor)
+{
+ // Clang does not tell us whether a constructor is explicit, preventing it
+ // from being used for implicit conversions. Try to guess whether a
+ // constructor is explicit in the C++99 sense (1 parameter) by checking for
+ // isConvertingConstructor() == 0. Fixme: The notion of "isConvertingConstructor"
+ // should be used in the code model instead of "explicit"
+ if (clang_CXXConstructor_isDefaultConstructor(cursor) == 0
+ && m_currentFunction->arguments().size() == 1
+ && clang_CXXConstructor_isCopyConstructor(cursor) == 0
+ && clang_CXXConstructor_isMoveConstructor(cursor) == 0) {
+ m_currentFunction->setAttribute(FunctionAttribute::Explicit,
+ clang_CXXConstructor_isConvertingConstructor(cursor) == 0);
+ }
+}
+
+TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCursor &cursor) const
+{
+ return std::make_shared<_TemplateParameterModelItem>(m_model, getCursorSpelling(cursor));
+}
+
+TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const
+{
+ TemplateParameterModelItem result = createTemplateParameter(cursor);
+ result->setType(createTypeInfo(clang_getCursorType(cursor)));
+ return result;
+}
+
+// CXCursor_VarDecl, CXCursor_FieldDecl cursors
+void BuilderPrivate::addField(const CXCursor &cursor)
+{
+ auto field = std::make_shared<_VariableModelItem>(m_model, getCursorSpelling(cursor));
+ field->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ field->setScope(m_scope);
+ field->setType(createTypeInfo(cursor));
+ field->setMutable(clang_CXXField_isMutable(cursor) != 0);
+ setFileName(cursor, field.get());
+ m_currentField = field;
+ m_scopeStack.back()->addVariable(field);
+}
+
+// Create qualified name "std::list<std::string>" -> ("std", "list<std::string>")
+static QStringList qualifiedName(const QString &t)
+{
+ QStringList result;
+ int end = t.indexOf(u'<');
+ if (end == -1)
+ end = t.indexOf(u'(');
+ if (end == -1)
+ end = t.size();
+ int lastPos = 0;
+ while (true) {
+ const int nextPos = t.indexOf(u"::"_s, lastPos);
+ if (nextPos < 0 || nextPos >= end)
+ break;
+ result.append(t.mid(lastPos, nextPos - lastPos));
+ lastPos = nextPos + 2;
+ }
+ result.append(t.right(t.size() - lastPos));
+ return result;
+}
+
+static bool isArrayType(CXTypeKind k)
+{
+ return k == CXType_ConstantArray || k == CXType_IncompleteArray
+ || k == CXType_VariableArray || k == CXType_DependentSizedArray;
+}
+
+static bool isPointerType(CXTypeKind k)
+{
+ return k == CXType_Pointer || k == CXType_LValueReference || k == CXType_RValueReference;
+}
+
+bool BuilderPrivate::addTemplateInstantiationsRecursion(const CXType &type, TypeInfo *t) const
+{
+ // Template arguments
+ switch (type.kind) {
+ case CXType_Elaborated:
+ case CXType_Record:
+ case CXType_Unexposed:
+ if (const int numTemplateArguments = qMax(0, clang_Type_getNumTemplateArguments(type))) {
+ for (unsigned tpl = 0; tpl < unsigned(numTemplateArguments); ++tpl) {
+ const CXType argType = clang_Type_getTemplateArgumentAsType(type, tpl);
+ // CXType_Invalid is returned when hitting on a specialization
+ // of a non-type template (template <int v>).
+ if (argType.kind == CXType_Invalid)
+ return false;
+ t->addInstantiation(createTypeInfoUncached(argType));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+static void dummyTemplateArgumentHandler(int, QStringView) {}
+
+void BuilderPrivate::addTemplateInstantiations(const CXType &type,
+ QString *typeName,
+ TypeInfo *t) const
+{
+ // In most cases, for templates like "Vector<A>", Clang will give us the
+ // arguments by recursing down the type. However this will fail for example
+ // within template classes (for functions like the copy constructor):
+ // template <class T>
+ // class Vector {
+ // Vector(const Vector&);
+ // };
+ // In that case, have TypeInfo parse the list from the spelling.
+ // Finally, remove the list "<>" from the type name.
+ const bool parsed = addTemplateInstantiationsRecursion(type, t)
+ && !t->instantiations().isEmpty();
+ if (!parsed)
+ t->setInstantiations({});
+ const auto pos = parsed
+ ? parseTemplateArgumentList(*typeName, dummyTemplateArgumentHandler)
+ : t->parseTemplateArgumentList(*typeName);
+ if (pos.first != -1 && pos.second != -1 && pos.second > pos.first)
+ typeName->remove(pos.first, pos.second - pos.first);
+}
+
+TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type,
+ bool *cacheable) const
+{
+ if (type.kind == CXType_Pointer) { // Check for function pointers, first.
+ const CXType pointeeType = clang_getPointeeType(type);
+ const int argCount = clang_getNumArgTypes(pointeeType);
+ if (argCount >= 0) {
+ TypeInfo result = createTypeInfoUncached(clang_getResultType(pointeeType),
+ cacheable);
+ result.setFunctionPointer(true);
+ for (int a = 0; a < argCount; ++a)
+ result.addArgument(createTypeInfoUncached(clang_getArgType(pointeeType, unsigned(a)),
+ cacheable));
+ return result;
+ }
+ }
+
+ TypeInfo typeInfo;
+
+ CXType nestedType = type;
+ for (; isArrayType(nestedType.kind); nestedType = clang_getArrayElementType(nestedType)) {
+ const long long size = clang_getArraySize(nestedType);
+ typeInfo.addArrayElement(size >= 0 ? QString::number(size) : QString());
+ }
+
+ TypeInfo::Indirections indirections;
+ for (; isPointerType(nestedType.kind); nestedType = clang_getPointeeType(nestedType)) {
+ switch (nestedType.kind) {
+ case CXType_Pointer:
+ indirections.prepend(clang_isConstQualifiedType(nestedType) != 0
+ ? Indirection::ConstPointer : Indirection::Pointer);
+ break;
+ case CXType_LValueReference:
+ typeInfo.setReferenceType(LValueReference);
+ break;
+ case CXType_RValueReference:
+ typeInfo.setReferenceType(RValueReference);
+ break;
+ default:
+ break;
+ }
+ }
+ typeInfo.setIndirectionsV(indirections);
+
+ typeInfo.setConstant(clang_isConstQualifiedType(nestedType) != 0);
+ typeInfo.setVolatile(clang_isVolatileQualifiedType(nestedType) != 0);
+
+ QString typeName = getResolvedTypeName(nestedType);
+ while (TypeInfo::stripLeadingConst(&typeName)
+ || TypeInfo::stripLeadingVolatile(&typeName)) {
+ }
+
+ // For typedefs within templates or nested classes within templates (iterators):
+ // "template <class T> class QList { using Value=T; .."
+ // the typedef source is named "type-parameter-0-0". Convert it back to the
+ // template parameter name. The CXTypes are the same for all templates and
+ // must not be cached.
+ if (m_currentClass && typeName.startsWith(u"type-parameter-0-")) {
+ if (cacheable != nullptr)
+ *cacheable = false;
+ bool ok;
+ const int n = QStringView{typeName}.mid(17).toInt(&ok);
+ if (ok) {
+ auto currentTemplate = currentTemplateClass();
+ if (currentTemplate && n < currentTemplate->templateParameters().size())
+ typeName = currentTemplate->templateParameters().at(n)->name();
+ }
+ }
+
+ // Obtain template instantiations if the name has '<' (thus excluding
+ // typedefs like "std::string".
+ if (typeName.contains(u'<'))
+ addTemplateInstantiations(nestedType, &typeName, &typeInfo);
+
+ typeInfo.setQualifiedName(qualifiedName(typeName));
+ // 3320:CINDEX_LINKAGE int clang_getNumArgTypes(CXType T); function ptr types?
+ typeInfo.simplifyStdType();
+ return typeInfo;
+}
+
+TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const
+{
+ const auto it = m_typeInfoHash.constFind(type);
+ if (it != m_typeInfoHash.constEnd())
+ return it.value();
+ bool cacheable = true;
+ TypeInfo result = createTypeInfoUncached(type, &cacheable);
+ if (cacheable)
+ m_typeInfoHash.insert(type, result);
+ return result;
+}
+
+void BuilderPrivate::addTypeDef(const CXCursor &cursor, const CXType &cxType)
+{
+ const QString target = getCursorSpelling(cursor);
+ auto item = std::make_shared<_TypeDefModelItem>(m_model, target);
+ setFileName(cursor, item.get());
+ item->setType(createTypeInfo(cxType));
+ item->setScope(m_scope);
+ m_scopeStack.back()->addTypeDef(item);
+}
+
+ClassModelItem BuilderPrivate::currentTemplateClass() const
+{
+ for (auto i = m_scopeStack.size() - 1; i >= 0; --i) {
+ auto klass = std::dynamic_pointer_cast<_ClassModelItem>(m_scopeStack.at(i));
+ if (klass && klass->isTemplate())
+ return klass;
+ }
+ return {};
+}
+
+void BuilderPrivate::startTemplateTypeAlias(const CXCursor &cursor)
+{
+ const QString target = getCursorSpelling(cursor);
+ m_currentTemplateTypeAlias.reset(new _TemplateTypeAliasModelItem(m_model, target));
+ setFileName(cursor, m_currentTemplateTypeAlias.get());
+ m_currentTemplateTypeAlias->setScope(m_scope);
+}
+
+void BuilderPrivate::endTemplateTypeAlias(const CXCursor &typeAliasCursor)
+{
+ CXType type = clang_getTypedefDeclUnderlyingType(typeAliasCursor);
+ // Usually "<elaborated>std::list<T>" or "<unexposed>Container1<T>",
+ // as obtained with parser of PYSIDE-323
+ if (type.kind == CXType_Unexposed || type.kind == CXType_Elaborated) {
+ m_currentTemplateTypeAlias->setType(createTypeInfo(type));
+ m_scopeStack.back()->addTemplateTypeAlias(m_currentTemplateTypeAlias);
+ }
+ m_currentTemplateTypeAlias.reset();
+}
+
+// extract an expression from the cursor via source
+// CXCursor_EnumConstantDecl, ParmDecl (a = Flag1 | Flag2)
+QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor)
+{
+ const std::string_view snippet = bv->getCodeSnippet(cursor);
+ auto equalSign = snippet.find('=');
+ if (equalSign == std::string::npos)
+ return QString();
+ ++equalSign;
+ QString result = QString::fromLocal8Bit(snippet.data() + equalSign,
+ qsizetype(snippet.size() - equalSign));
+ // Fix a default expression as read from code. Simplify white space
+ result.remove(u'\r');
+ return result.contains(u'"') ? result.trimmed() : result.simplified();
+}
+
+// Resolve a type (loop over aliases/typedefs), for example for base classes
+// Note: TypeAliasTemplateDecl ("using QVector<T>=QList<T>") is automatically
+// resolved by clang_getTypeDeclaration(), but it stops at
+// TypeAliasDecl / TypedefDecl.
+
+struct TypeDeclaration
+{
+ CXType type;
+ CXCursor declaration;
+};
+
+static inline bool isTypeAliasDecl(const CXCursor &cursor)
+{
+ const auto kind = clang_getCursorKind(cursor);
+ return kind == CXCursor_TypeAliasDecl || kind == CXCursor_TypedefDecl;
+}
+
+static TypeDeclaration resolveBaseClassType(CXType type)
+{
+ CXCursor decl = clang_getTypeDeclaration(type);
+ auto resolvedType = clang_getCursorType(decl);
+ if (resolvedType.kind != CXType_Invalid && resolvedType.kind != type.kind)
+ type = resolvedType;
+ while (isTypeAliasDecl(decl)) {
+ type = clang_getTypedefDeclUnderlyingType(decl);
+ decl = clang_getTypeDeclaration(type);
+ }
+ return {type, decl};
+}
+
+// Note: Return the baseclass for cursors like CXCursor_CXXBaseSpecifier,
+// where the cursor spelling has "struct baseClass".
+std::pair<QString, ClassModelItem> BuilderPrivate::getBaseClass(CXType type) const
+{
+ const auto decl = resolveBaseClassType(type);
+ // Note: spelling has "struct baseClass", use type
+ QString baseClassName = getTypeName(decl.type);
+ if (baseClassName.startsWith(u"std::")) // Simplify "std::" types
+ baseClassName = createTypeInfo(decl.type).toString();
+
+ auto it = m_cursorClassHash.constFind(decl.declaration);
+ // Not found: Set unqualified name. This happens in cases like
+ // "class X : public std::list<...>", "template<class T> class Foo : public T"
+ // and standard types like true_type, false_type.
+ if (it == m_cursorClassHash.constEnd())
+ return {baseClassName, {}};
+
+ // Completely qualify the class name by looking it up and taking its scope
+ // plus the actual baseClass stripped off any scopes. Consider:
+ // namespace std {
+ // template <class T> class vector {};
+ // namespace n {
+ // class Foo : public vector<int> {};
+ // }
+ // }
+ // should have "std::vector<int>" as base class (whereas the type of the base class is
+ // "std::vector<T>").
+ const QStringList &baseScope = it.value()->scope();
+ if (!baseScope.isEmpty()) {
+ const int lastSep = baseClassName.lastIndexOf(u"::"_s);
+ if (lastSep >= 0)
+ baseClassName.remove(0, lastSep + u"::"_s.size());
+ baseClassName.prepend(u"::"_s);
+ baseClassName.prepend(baseScope.join(u"::"_s));
+ }
+ return {baseClassName, it.value()};
+}
+
+// Add a base class to the current class from CXCursor_CXXBaseSpecifier
+void BuilderPrivate::addBaseClass(const CXCursor &cursor)
+{
+ Q_ASSERT(clang_getCursorKind(cursor) == CXCursor_CXXBaseSpecifier);
+ const auto access = accessPolicy(clang_getCXXAccessSpecifier(cursor));
+ const auto baseClass = getBaseClass(clang_getCursorType(cursor));
+ m_currentClass->addBaseClass({baseClass.first, baseClass.second, access});
+}
+
+void BuilderPrivate::setFileName(const CXCursor &cursor, _CodeModelItem *item)
+{
+ const SourceRange range = getCursorRange(cursor);
+ QString file = m_baseVisitor->getFileName(range.first.file);
+ if (!file.isEmpty()) { // Has been observed to be 0 for invalid locations
+ item->setFileName(QDir::cleanPath(file));
+ item->setStartPosition(int(range.first.line), int(range.first.column));
+ item->setEndPosition(int(range.second.line), int(range.second.column));
+ }
+}
+
+Builder::Builder()
+{
+ d = new BuilderPrivate(this);
+}
+
+Builder::~Builder()
+{
+ delete d;
+}
+
+static QString baseName(QString path)
+{
+ qsizetype lastSlash = path.lastIndexOf(u'/');
+#ifdef Q_OS_WIN
+ if (lastSlash < 0)
+ lastSlash = path.lastIndexOf(u'\\');
+#endif
+ if (lastSlash > 0)
+ path.remove(0, lastSlash + 1);
+ return path;
+}
+
+const char * BuilderPrivate::specialSystemHeaderReason(BuilderPrivate::SpecialSystemHeader sh)
+{
+ static const QHash<SpecialSystemHeader, const char *> mapping {
+ {SpecialSystemHeader::OpenGL, "OpenGL"},
+ {SpecialSystemHeader::Types, "types"},
+ {SpecialSystemHeader::WhiteListed, "white listed"},
+ {SpecialSystemHeader::WhiteListedPath, "white listed path"}
+ };
+ return mapping.value(sh, "");
+}
+
+bool BuilderPrivate::visitHeader(const QString &fileName) const
+{
+ auto it = m_systemHeaders.find(fileName);
+ if (it == m_systemHeaders.end()) {
+ it = m_systemHeaders.insert(fileName, specialSystemHeader(fileName));
+ if (ReportHandler::isDebug(ReportHandler::MediumDebug)) {
+ const QString &name = QDir::toNativeSeparators(fileName);
+ if (it.value() == SpecialSystemHeader::None) {
+ qCInfo(lcShiboken, "Skipping system header %s", qPrintable(name));
+ } else {
+ qCInfo(lcShiboken, "Parsing system header %s (%s)",
+ qPrintable(name), specialSystemHeaderReason(it.value()));
+ }
+ }
+ }
+ return it.value() != SpecialSystemHeader::None;
+}
+
+BuilderPrivate::SpecialSystemHeader
+ BuilderPrivate::specialSystemHeader(const QString &fileName) const
+{
+ // Resolve OpenGL typedefs although the header is considered a system header.
+ const QString baseName = clang::baseName(fileName);
+ if (baseName == u"gl.h"
+ || baseName == u"gl2.h"
+ || baseName == u"gl3.h"
+ || baseName == u"gl31.h"
+ || baseName == u"gl32.h"
+ || baseName == u"stdint.h" // Windows: int32_t, uint32_t
+ || baseName == u"stddef.h") { // size_t`
+ return SpecialSystemHeader::OpenGL;
+ }
+
+ switch (clang::platform()) {
+ case Platform::Unix:
+ if (fileName == u"/usr/include/stdlib.h"
+ || baseName == u"types.h"
+ || baseName == u"stdint-intn.h" // int32_t
+ || baseName == u"stdint-uintn.h") { // uint32_t
+ return SpecialSystemHeader::Types;
+ }
+ break;
+ case Platform::macOS:
+ // Parse the following system headers to get the correct typdefs for types like
+ // int32_t, which are used in the macOS implementation of OpenGL framework.
+ // They are installed under /Applications/Xcode.app/Contents/Developer/Platforms...
+ if (baseName == u"gltypes.h"
+ || fileName.contains(u"/usr/include/_types")
+ || fileName.contains(u"/usr/include/sys/_types")) {
+ return SpecialSystemHeader::Types;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // When building against system Qt (as it happens with yocto / Boot2Qt), the Qt headers are
+ // considered system headers by clang_Location_isInSystemHeader, and shiboken will not
+ // process them. We need to explicitly process them by checking against the list of
+ // include paths that were passed to shiboken's --force-process-system-include-paths option
+ // or specified via the <system-include> xml tag.
+ if (m_forceProcessSystemIncludes.contains(baseName))
+ return SpecialSystemHeader::WhiteListed;
+
+ if (std::any_of(m_forceProcessSystemIncludePaths.cbegin(),
+ m_forceProcessSystemIncludePaths.cend(),
+ [fileName](const QString &p) { return fileName.startsWith(p); })) {
+ return SpecialSystemHeader::WhiteListedPath;
+ }
+
+ return SpecialSystemHeader::None;
+}
+
+bool Builder::visitLocation(const QString &fileName, LocationType locationType) const
+{
+ return locationType != LocationType::System || d->visitHeader(fileName);
+}
+
+void Builder::setForceProcessSystemIncludes(const QStringList &systemIncludes)
+{
+ for (const auto &i : systemIncludes) {
+ QFileInfo fi(i);
+ if (fi.exists() && fi.isDir())
+ d->m_forceProcessSystemIncludePaths.append(i);
+ else
+ d->m_forceProcessSystemIncludes.append(i);
+ }
+}
+
+FileModelItem Builder::dom() const
+{
+ Q_ASSERT(!d->m_scopeStack.isEmpty());
+ auto rootScope = d->m_scopeStack.constFirst();
+ rootScope->purgeClassDeclarations();
+ return std::dynamic_pointer_cast<_FileModelItem>(rootScope);
+}
+
+static QString msgOutOfOrder(const CXCursor &cursor, const char *expectedScope)
+{
+ return getCursorKindName(cursor.kind) + u' '
+ + getCursorSpelling(cursor) + u" encountered outside "_s
+ + QLatin1StringView(expectedScope) + u'.';
+}
+
+static CodeModel::ClassType codeModelClassTypeFromCursor(CXCursorKind kind)
+{
+ CodeModel::ClassType result = CodeModel::Class;
+ if (kind == CXCursor_UnionDecl)
+ result = CodeModel::Union;
+ else if (kind == CXCursor_StructDecl)
+ result = CodeModel::Struct;
+ return result;
+}
+
+static NamespaceType namespaceType(const CXCursor &cursor)
+{
+ if (clang_Cursor_isAnonymous(cursor))
+ return NamespaceType::Anonymous;
+#if CINDEX_VERSION_MAJOR > 0 || CINDEX_VERSION_MINOR >= 59
+ if (clang_Cursor_isInlineNamespace(cursor))
+ return NamespaceType::Inline;
+#endif
+ return NamespaceType::Default;
+}
+
+static QString enumType(const CXCursor &cursor)
+{
+ QString name = getCursorSpelling(cursor); // "enum Foo { v1, v2 };"
+ if (name.contains(u"unnamed enum")) // Clang 16.0
+ return {};
+ if (name.isEmpty()) {
+ // PYSIDE-1228: For "typedef enum { v1, v2 } Foo;", type will return
+ // "Foo" as expected. Care must be taken to exclude real anonymous enums.
+ name = getTypeName(clang_getCursorType(cursor));
+ if (name.contains(u"(unnamed") // Clang 12.0.1
+ || name.contains(u"(anonymous")) { // earlier
+ name.clear();
+ }
+ }
+ return name;
+}
+
+BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+{
+ switch (cursor.kind) {
+ case CXCursor_CXXAccessSpecifier:
+ d->m_currentFunctionType = CodeModel::Normal;
+ break;
+ case CXCursor_AnnotateAttr: {
+ const QString annotation = getCursorSpelling(cursor);
+ if (annotation == u"qt_slot")
+ d->m_currentFunctionType = CodeModel::Slot;
+ else if (annotation == u"qt_signal")
+ d->m_currentFunctionType = CodeModel::Signal;
+ else
+ d->m_currentFunctionType = CodeModel::Normal;
+ }
+ break;
+ case CXCursor_CXXBaseSpecifier:
+ if (!d->m_currentClass) {
+ const Diagnostic d(msgOutOfOrder(cursor, "class"), cursor, CXDiagnostic_Error);
+ qWarning() << d;
+ appendDiagnostic(d);
+ return Error;
+ }
+ d->addBaseClass(cursor);
+ break;
+ case CXCursor_ClassDecl:
+ case CXCursor_UnionDecl:
+ case CXCursor_StructDecl:
+ if (d->m_withinFriendDecl || clang_isCursorDefinition(cursor) == 0
+ || !d->addClass(cursor, codeModelClassTypeFromCursor(cursor.kind))) {
+ return Skip;
+ }
+ break;
+ case CXCursor_ClassTemplate:
+ case CXCursor_ClassTemplatePartialSpecialization:
+ if (d->m_withinFriendDecl || clang_isCursorDefinition(cursor) == 0
+ || !d->addClass(cursor, CodeModel::Class)) {
+ return Skip;
+ }
+ d->m_currentClass->setName(d->m_currentClass->name() + "<>"_L1);
+ d->m_scope.back() += "<>"_L1;
+ break;
+ case CXCursor_EnumDecl: {
+ QString name = enumType(cursor);
+ EnumKind kind = CEnum;
+ if (name.isEmpty()) {
+ kind = AnonymousEnum;
+ name = "enum_"_L1 + QString::number(++d->m_anonymousEnumCount);
+#if !CLANG_NO_ENUMDECL_ISSCOPED
+ } else if (clang_EnumDecl_isScoped(cursor) != 0) {
+#else
+ } else if (clang_EnumDecl_isScoped4(this, cursor) != 0) {
+#endif
+ kind = EnumClass;
+ }
+ d->m_currentEnum.reset(new _EnumModelItem(d->m_model, name));
+ d->setFileName(cursor, d->m_currentEnum.get());
+ d->m_currentEnum->setScope(d->m_scope);
+ d->m_currentEnum->setEnumKind(kind);
+ if (clang_getCursorAvailability(cursor) == CXAvailability_Deprecated)
+ d->m_currentEnum->setDeprecated(true);
+ const auto enumType = fullyResolveType(clang_getEnumDeclIntegerType(cursor));
+ d->m_currentEnum->setSigned(isSigned(enumType.kind));
+ d->m_currentEnum->setUnderlyingType(getTypeName(enumType));
+ if (std::dynamic_pointer_cast<_ClassModelItem>(d->m_scopeStack.back()))
+ d->m_currentEnum->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ }
+ break;
+ case CXCursor_EnumConstantDecl: {
+ const QString name = getCursorSpelling(cursor);
+ if (!d->m_currentEnum) {
+ const Diagnostic d(msgOutOfOrder(cursor, "enum"), cursor, CXDiagnostic_Error);
+ qWarning() << d;
+ appendDiagnostic(d);
+ return Error;
+ }
+ EnumValue enumValue;
+ if (d->m_currentEnum->isSigned())
+ enumValue.setValue(clang_getEnumConstantDeclValue(cursor));
+ else
+ enumValue.setUnsignedValue(clang_getEnumConstantDeclUnsignedValue(cursor));
+ auto enumConstant = std::make_shared<_EnumeratorModelItem>(d->m_model, name);
+ enumConstant->setStringValue(d->cursorValueExpression(this, cursor));
+ enumConstant->setValue(enumValue);
+ if (clang_getCursorAvailability(cursor) == CXAvailability_Deprecated)
+ enumConstant->setDeprecated(true);
+ d->m_currentEnum->addEnumerator(enumConstant);
+ }
+ break;
+ case CXCursor_VarDecl:
+ // static class members are seen as CXCursor_VarDecl
+ if (isClassOrNamespaceCursor(clang_getCursorSemanticParent(cursor))) {
+ d->addField(cursor);
+ d->m_currentField->setStatic(true);
+ }
+ break;
+ case CXCursor_FieldDecl:
+ d->addField(cursor);
+ break;
+ case CXCursor_FriendDecl:
+ d->m_withinFriendDecl = true;
+ break;
+ case CXCursor_CompoundStmt: // Function bodies
+ return Skip;
+ case CXCursor_Constructor:
+ case CXCursor_Destructor: // Note: Also use clang_CXXConstructor_is..Constructor?
+ case CXCursor_CXXMethod:
+ case CXCursor_ConversionFunction:
+ // Member functions of other classes can be declared to be friends.
+ // Skip inline member functions outside class, only go by declarations inside class
+ if (d->m_withinFriendDecl || !withinClassDeclaration(cursor))
+ return Skip;
+ d->m_currentFunction = d->createMemberFunction(cursor, false);
+ d->m_scopeStack.back()->addFunction(d->m_currentFunction);
+ break;
+ // Not fully supported, currently, seen as normal function
+ // Note: May appear inside class (member template) or outside (free template).
+ case CXCursor_FunctionTemplate: {
+ const CXCursor semParent = clang_getCursorSemanticParent(cursor);
+ if (isClassCursor(semParent)) {
+ if (semParent == clang_getCursorLexicalParent(cursor)) {
+ d->m_currentFunction = d->createMemberFunction(cursor, true);
+ d->m_scopeStack.back()->addFunction(d->m_currentFunction);
+ break;
+ }
+ return Skip; // inline member functions outside class
+ }
+ }
+ d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, true);
+ d->setFileName(cursor, d->m_currentFunction.get());
+ d->m_scopeStack.back()->addFunction(d->m_currentFunction);
+ break;
+ case CXCursor_FunctionDecl:
+ // Free functions or functions completely defined within "friend" (class
+ // operators). Note: CXTranslationUnit_SkipFunctionBodies must be off for
+ // clang_isCursorDefinition() to work here.
+ if (!d->m_withinFriendDecl || clang_isCursorDefinition(cursor) != 0) {
+ auto scope = d->m_scopeStack.size() - 1; // enclosing class
+ if (d->m_withinFriendDecl) {
+ // Friend declaration: go back to namespace or file scope.
+ for (--scope; d->m_scopeStack.at(scope)->kind() == _CodeModelItem::Kind_Class; --scope) {
+ }
+ }
+ d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, false);
+ d->m_currentFunction->setHiddenFriend(d->m_withinFriendDecl);
+ d->m_scopeStack.at(scope)->addFunction(d->m_currentFunction);
+ }
+ break;
+ case CXCursor_Namespace: {
+ const auto type = namespaceType(cursor);
+ if (type == NamespaceType::Anonymous)
+ return Skip;
+ const QString name = getCursorSpelling(cursor);
+ const auto parentNamespaceItem = std::dynamic_pointer_cast<_NamespaceModelItem>(d->m_scopeStack.back());
+ if (!parentNamespaceItem) {
+ const QString message = msgOutOfOrder(cursor, "namespace")
+ + u" (current scope: "_s + d->m_scopeStack.back()->name() + u')';
+ const Diagnostic d(message, cursor, CXDiagnostic_Error);
+ qWarning() << d;
+ appendDiagnostic(d);
+ return Error;
+ }
+ // Treat namespaces separately to allow for extending namespaces
+ // in subsequent modules.
+ NamespaceModelItem namespaceItem = parentNamespaceItem->findNamespace(name);
+ namespaceItem.reset(new _NamespaceModelItem(d->m_model, name));
+ d->setFileName(cursor, namespaceItem.get());
+ namespaceItem->setScope(d->m_scope);
+ namespaceItem->setType(type);
+ parentNamespaceItem->addNamespace(namespaceItem);
+ d->pushScope(namespaceItem);
+ }
+ break;
+ case CXCursor_ParmDecl:
+ // Skip in case of nested CXCursor_ParmDecls in case one parameter is a function pointer
+ // and function pointer typedefs.
+ if (!d->m_currentArgument && d->m_currentFunction) {
+ const QString name = getCursorSpelling(cursor);
+ d->m_currentArgument.reset(new _ArgumentModelItem(d->m_model, name));
+ const auto type = clang_getCursorType(cursor);
+ d->m_currentArgument->setScopeResolution(hasScopeResolution(type));
+ d->m_currentArgument->setType(d->createTypeInfo(type));
+ d->m_currentFunction->addArgument(d->m_currentArgument);
+ QString defaultValueExpression = d->cursorValueExpression(this, cursor);
+ if (!defaultValueExpression.isEmpty()) {
+ d->m_currentArgument->setDefaultValueExpression(defaultValueExpression);
+ d->m_currentArgument->setDefaultValue(true);
+ }
+ } else {
+ return Skip;
+ }
+ break;
+ case CXCursor_TemplateTypeParameter:
+ case CXCursor_NonTypeTemplateParameter: {
+ const TemplateParameterModelItem tItem = cursor.kind == CXCursor_TemplateTemplateParameter
+ ? d->createTemplateParameter(cursor) : d->createNonTypeTemplateParameter(cursor);
+ // Apply to function/member template?
+ if (d->m_currentFunction) {
+ d->m_currentFunction->setTemplateParameters(d->m_currentFunction->templateParameters() << tItem);
+ } else if (d->m_currentTemplateTypeAlias) {
+ d->m_currentTemplateTypeAlias->addTemplateParameter(tItem);
+ } else if (d->m_currentClass) { // Apply to class
+ const QString &tplParmName = tItem->name();
+ if (Q_UNLIKELY(!insertTemplateParameterIntoClassName(tplParmName, d->m_currentClass)
+ || !insertTemplateParameterIntoClassName(tplParmName, &d->m_scope.back()))) {
+ const QString message = "Error inserting template parameter \""_L1 + tplParmName
+ + "\" into "_L1 + d->m_currentClass->name();
+ const Diagnostic d(message, cursor, CXDiagnostic_Error);
+ qWarning() << d;
+ appendDiagnostic(d);
+ return Error;
+ }
+ d->m_currentClass->setTemplateParameters(d->m_currentClass->templateParameters() << tItem);
+ }
+ }
+ break;
+ case CXCursor_TypeAliasTemplateDecl:
+ d->startTemplateTypeAlias(cursor);
+ break;
+ case CXCursor_TypeAliasDecl: // May contain nested CXCursor_TemplateTypeParameter
+ if (!d->m_currentTemplateTypeAlias) {
+ const CXType type = clang_getCanonicalType(clang_getCursorType(cursor));
+ if (type.kind > CXType_Unexposed)
+ d->addTypeDef(cursor, type);
+ return Skip;
+ } else {
+ d->endTemplateTypeAlias(cursor);
+ }
+ break;
+ case CXCursor_TypedefDecl: {
+ auto underlyingType = clang_getTypedefDeclUnderlyingType(cursor);
+ d->addTypeDef(cursor, underlyingType);
+ // For "typedef enum/struct {} Foo;", skip the enum/struct
+ // definition nested into the typedef (PYSIDE-1228).
+ if (underlyingType.kind == CXType_Elaborated)
+ return Skip;
+ }
+ break;
+ // Using declarations look as follows:
+ // 1) Normal, non-template case ("using QObject::parent"): UsingDeclaration, TypeRef
+ // 2) Simple template case ("using QList::append()"): UsingDeclaration, TypeRef "QList<T>"
+ // 3) Template case with parameters ("using QList<T>::append()"):
+ // UsingDeclaration, TemplateRef "QList", TypeRef "T"
+ case CXCursor_TemplateRef:
+ if (d->m_withinUsingDeclaration && d->m_usingTypeRef.isEmpty())
+ d->m_usingTypeRef = getCursorSpelling(cursor);
+ break;
+ case CXCursor_TypeRef:
+ if (d->m_withinUsingDeclaration && d->m_usingTypeRef.isEmpty())
+ d->m_usingTypeRef = d->getBaseClass(clang_getCursorType(cursor)).first;
+ break;
+ case CXCursor_CXXFinalAttr:
+ if (d->m_currentFunction)
+ d->m_currentFunction->setAttribute(FunctionAttribute::Final);
+ else if (d->m_currentClass)
+ d->m_currentClass->setFinal(true);
+ break;
+ case CXCursor_CXXOverrideAttr:
+ if (d->m_currentFunction)
+ d->m_currentFunction->setAttribute(FunctionAttribute::Override);
+ break;
+ case CXCursor_StaticAssert:
+ // Check for Q_PROPERTY() (see PySide6/global.h.in for an explanation
+ // how it is defined, and qdoc).
+ if (clang_isDeclaration(cursor.kind) && d->m_currentClass) {
+ auto snippet = getCodeSnippet(cursor);
+ const auto length = snippet.size();
+ if (length > 12 && *snippet.rbegin() == ')'
+ && snippet.compare(0, 11, "Q_PROPERTY(") == 0) {
+ const QString qProperty = QString::fromUtf8(snippet.data() + 11, length - 12);
+ d->m_currentClass->addPropertyDeclaration(qProperty);
+ }
+ }
+ break;
+ // UsingDeclaration: consists of a TypeRef (base) and OverloadedDeclRef (member name)
+ case CXCursor_UsingDeclaration:
+ if (d->m_currentClass)
+ d->m_withinUsingDeclaration = true;
+ break;
+ case CXCursor_OverloadedDeclRef:
+ if (d->m_withinUsingDeclaration && !d->m_usingTypeRef.isEmpty()) {
+ QString member = getCursorSpelling(cursor);
+ if (member == d->m_currentClass->name())
+ member = d->m_usingTypeRef; // Overloaded member is Constructor, use base
+ const auto ap = accessPolicy(clang_getCXXAccessSpecifier(cursor));
+ d->m_currentClass->addUsingMember(d->m_usingTypeRef, member, ap);
+ }
+ break;
+ default:
+ break;
+ }
+ return BaseVisitor::Recurse;
+}
+
+bool Builder::endToken(const CXCursor &cursor)
+{
+ switch (cursor.kind) {
+ case CXCursor_UnionDecl:
+ case CXCursor_ClassDecl:
+ case CXCursor_StructDecl:
+ case CXCursor_ClassTemplate:
+ case CXCursor_ClassTemplatePartialSpecialization:
+ d->popScope();
+ // Continue in outer class after leaving inner class?
+ if (auto lastClass = std::dynamic_pointer_cast<_ClassModelItem>(d->m_scopeStack.back()))
+ d->m_currentClass = lastClass;
+ else
+ d->m_currentClass.reset();
+ d->m_currentFunctionType = CodeModel::Normal;
+ break;
+ case CXCursor_EnumDecl:
+ if (d->m_currentEnum)
+ d->m_scopeStack.back()->addEnum(d->m_currentEnum);
+ d->m_currentEnum.reset();
+ break;
+ case CXCursor_FriendDecl:
+ d->m_withinFriendDecl = false;
+ break;
+ case CXCursor_VarDecl:
+ case CXCursor_FieldDecl:
+ d->m_currentField.reset();
+ break;
+ case CXCursor_Constructor:
+ d->qualifyConstructor(cursor);
+ if (d->m_currentFunction) {
+ d->m_currentFunction->_determineType();
+ d->m_currentFunction.reset();
+ }
+ break;
+ case CXCursor_Destructor:
+ case CXCursor_CXXMethod:
+ case CXCursor_FunctionDecl:
+ case CXCursor_FunctionTemplate:
+ if (d->m_currentFunction) {
+ d->m_currentFunction->_determineType();
+ d->m_currentFunction.reset();
+ }
+ break;
+ case CXCursor_ConversionFunction:
+ if (d->m_currentFunction) {
+ d->m_currentFunction->setFunctionType(CodeModel::ConversionOperator);
+ d->m_currentFunction.reset();
+ }
+ break;
+ case CXCursor_Namespace:
+ d->popScope();
+ break;
+ case CXCursor_ParmDecl:
+ d->m_currentArgument.reset();
+ break;
+ case CXCursor_TypeAliasTemplateDecl:
+ d->m_currentTemplateTypeAlias.reset();
+ break;
+ case CXCursor_UsingDeclaration:
+ d->m_withinUsingDeclaration = false;
+ d->m_usingTypeRef.clear();
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+} // namespace clang
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.h b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.h
new file mode 100644
index 000000000..b2ec6d304
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CLANGBUILDER_H
+#define CLANGBUILDER_H
+
+#include "clangparser.h"
+
+#include <codemodel_fwd.h>
+
+namespace clang {
+
+class BuilderPrivate;
+
+class Builder : public BaseVisitor {
+public:
+ Q_DISABLE_COPY_MOVE(Builder)
+
+ Builder();
+ ~Builder();
+
+ void setForceProcessSystemIncludes(const QStringList &systemIncludes);
+
+ bool visitLocation(const QString &fileName, LocationType locationType) const override;
+
+ StartTokenResult startToken(const CXCursor &cursor) override;
+ bool endToken(const CXCursor &cursor) override;
+
+ FileModelItem dom() const;
+
+private:
+ BuilderPrivate *d;
+};
+
+} // namespace clang
+
+#endif // CLANGBUILDER_H
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.cpp
new file mode 100644
index 000000000..3c002da9c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.cpp
@@ -0,0 +1,175 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "clangdebugutils.h"
+#include "clangutils.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QString>
+
+#ifndef QT_NO_DEBUG_STREAM
+
+#ifdef Q_OS_WIN
+const char pathSep = '\\';
+#else
+const char pathSep = '/';
+#endif
+
+static const char *baseName(const char *fileName)
+{
+ const char *b = std::strrchr(fileName, pathSep);
+ return b ? b + 1 : fileName;
+}
+
+QDebug operator<<(QDebug s, const CXString &cs)
+{
+ s << clang_getCString(cs);
+ return s;
+}
+
+QDebug operator<<(QDebug s, CXCursorKind cursorKind) // Enum
+{
+ const CXString kindName = clang_getCursorKindSpelling(cursorKind);
+ s << kindName;
+ clang_disposeString(kindName);
+ return s;
+}
+
+static const char *accessSpecsStrings[]
+{
+ // CX_CXXInvalidAccessSpecifier, CX_CXXPublic, CX_CXXProtected, CX_CXXPrivate
+ "invalid", "public", "protected", "private"
+};
+
+QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac)
+{
+ s << accessSpecsStrings[ac];
+ return s;
+}
+
+struct formatCXTypeName
+{
+ explicit formatCXTypeName(const CXType &type) : m_type(type) {}
+
+ const CXType &m_type;
+};
+
+QDebug operator<<(QDebug debug, const formatCXTypeName &ft)
+{
+ CXString typeSpelling = clang_getTypeSpelling(ft.m_type);
+ debug << typeSpelling;
+ clang_disposeString(typeSpelling);
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const CXType &type)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug.noquote();
+ debug << "CXType(";
+ if (type.kind == CXType_Invalid) {
+ debug << "invalid)";
+ return debug;
+ }
+
+ debug << type.kind;
+ switch (type.kind) {
+ case CXType_Unexposed:
+ debug << " [unexposed]";
+ break;
+ case CXType_Elaborated:
+ debug << " [elaborated]";
+ break;
+ default:
+ break;
+ }
+ debug << ", " << formatCXTypeName(type) << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const CXCursor &cursor)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug.noquote();
+ const CXCursorKind kind = clang_getCursorKind(cursor);
+ debug << "CXCursor(";
+ if (kind >= CXCursor_FirstInvalid && kind <= CXCursor_LastInvalid) {
+ debug << "invalid)";
+ return debug;
+ }
+
+ const QString cursorSpelling = clang::getCursorSpelling(cursor);
+ debug << '"' << cursorSpelling << '"';
+ CXString cursorDisplay = clang_getCursorDisplayName(cursor);
+ if (const char *dpy = clang_getCString(cursorDisplay)) {
+ const QString display = QString::fromUtf8(dpy);
+ if (display != cursorSpelling)
+ debug << ", display=\"" << dpy << '"';
+ }
+ clang_disposeString(cursorDisplay);
+
+ debug << ", kind=" << kind;
+
+ const CXType type = clang_getCursorType(cursor);
+ switch (kind) {
+ case CXCursor_CXXAccessSpecifier:
+ debug << ", " << clang_getCXXAccessSpecifier(cursor);
+ break;
+ case CXCursor_CXXBaseSpecifier:
+ debug << ", inherits=\"" << clang::getCursorSpelling(clang_getTypeDeclaration(type)) << '"';
+ break;
+ case CXCursor_CXXMethod:
+ case CXCursor_FunctionDecl:
+ case CXCursor_ConversionFunction:
+ debug << ", result type=\""
+ << formatCXTypeName(clang_getCursorResultType(cursor)) << '"';
+ break;
+ case CXCursor_TypedefDecl:
+ debug << ", underlyingType=\""
+ << formatCXTypeName(clang_getTypedefDeclUnderlyingType(cursor)) << '"';
+ break;
+ default:
+ break;
+ }
+
+ debug << ", type=\"" << formatCXTypeName(type) << '"';
+ if (clang_Cursor_hasAttrs(cursor))
+ debug << ", [attrs]";
+
+ debug << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug s, const CXSourceLocation &location)
+{
+ QDebugStateSaver saver(s);
+ s.nospace();
+ CXFile file; // void *
+ unsigned line;
+ unsigned column;
+ unsigned offset;
+ clang_getExpansionLocation(location, &file, &line, &column, &offset);
+ const CXString cxFileName = clang_getFileName(file);
+ // Has been observed to be 0 for invalid locations
+ if (const char *cFileName = clang_getCString(cxFileName))
+ s << baseName(cFileName) << ':';
+ s << line << ':' << column;
+ clang_disposeString(cxFileName);
+ return s;
+}
+
+QDebug operator<<(QDebug s, const std::string_view &v)
+{
+ QDebugStateSaver saver(s);
+ s.nospace();
+ s.noquote();
+ s << '"';
+ for (auto c : v)
+ s << c;
+ s << '"';
+ return s;
+}
+
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.h b/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.h
new file mode 100644
index 000000000..7aac8a575
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CLANGDEBUGUTILS_H
+#define CLANGDEBUGUTILS_H
+
+#include <QtCore/qtclasshelpermacros.h>
+
+#include <clang-c/Index.h>
+
+#include <string_view>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+QT_FORWARD_DECLARE_CLASS(QString)
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug s, const CXString &cs);
+QDebug operator<<(QDebug s, CXCursorKind cursorKind);
+QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac);
+QDebug operator<<(QDebug s, const CXType &t);
+QDebug operator<<(QDebug s, const CXCursor &cursor);
+QDebug operator<<(QDebug s, const CXSourceLocation &location);
+QDebug operator<<(QDebug s, const std::string_view &v); // for code snippets
+#endif // !QT_NO_DEBUG_STREAM
+
+#endif // CLANGDEBUGUTILS_H
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp
new file mode 100644
index 000000000..6c0cf3ae2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp
@@ -0,0 +1,323 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "clangparser.h"
+#include "clangutils.h"
+#include "clangdebugutils.h"
+#include "compilersupport.h"
+
+#include <QtCore/QByteArrayList>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QScopedArrayPointer>
+#include <QtCore/QString>
+
+using namespace Qt::StringLiterals;
+
+namespace clang {
+
+QString SourceFileCache::getFileName(CXFile file)
+{
+ auto it = m_fileNameCache.find(file);
+ if (it == m_fileNameCache.end())
+ it = m_fileNameCache.insert(file, clang::getFileName(file));
+ return it.value();
+}
+
+std::string_view SourceFileCache::getCodeSnippet(const CXCursor &cursor,
+ QString *errorMessage)
+{
+ static const char empty[] = "";
+
+ if (errorMessage)
+ errorMessage->clear();
+
+ const SourceRange range = getCursorRange(cursor);
+ // Quick check for equal locations: Frequently happens if the code is
+ // the result of a macro expansion
+ if (range.first == range.second)
+ return std::string_view(empty, 0);
+
+ if (range.first.file != range.second.file) {
+ if (errorMessage)
+ *errorMessage = "Range spans several files"_L1;
+ return std::string_view(empty, 0);
+ }
+
+ auto it = m_fileBufferCache.find(range.first.file);
+ if (it == m_fileBufferCache.end()) {
+ const QString fileName = getFileName(range.first.file);
+ if (fileName.isEmpty()) {
+ if (errorMessage)
+ *errorMessage = "Range has no file"_L1;
+ return std::string_view(empty, 0);
+ }
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly)) {
+ if (errorMessage) {
+ QTextStream str(errorMessage);
+ str << "Cannot open \"" << QDir::toNativeSeparators(fileName)
+ << "\": " << file.errorString();
+ }
+ return std::string_view(empty, 0);
+ }
+ it = m_fileBufferCache.insert(range.first.file, file.readAll());
+ }
+
+ const unsigned pos = range.first.offset;
+ const unsigned end = range.second.offset;
+ Q_ASSERT(end > pos);
+ const QByteArray &contents = it.value();
+ if (end >= unsigned(contents.size())) {
+ if (errorMessage) {
+ QTextStream str(errorMessage);
+ str << "Range end " << end << " is above size of \""
+ << QDir::toNativeSeparators(getFileName(range.first.file))
+ << "\" (" << contents.size() << ')';
+ }
+ return std::string_view(empty, 0);
+ }
+
+ return std::string_view(contents.constData() + pos, end - pos);
+}
+
+BaseVisitor::BaseVisitor() = default;
+BaseVisitor::~BaseVisitor() = default;
+
+bool BaseVisitor::visitLocation(const QString &, LocationType locationType) const
+{
+ return locationType != LocationType::System;
+}
+
+BaseVisitor::StartTokenResult BaseVisitor::cbHandleStartToken(const CXCursor &cursor)
+{
+ switch (cursor.kind) {
+ default:
+ break;
+ }
+
+ return startToken(cursor);
+}
+
+bool BaseVisitor::cbHandleEndToken(const CXCursor &cursor, StartTokenResult startResult)
+{
+ const bool result = startResult != Recurse || endToken(cursor);
+ switch (cursor.kind) {
+ default:
+ break;
+ }
+
+ return result;
+}
+
+std::string_view BaseVisitor::getCodeSnippet(const CXCursor &cursor)
+{
+ QString errorMessage;
+ const std::string_view result = m_fileCache.getCodeSnippet(cursor, &errorMessage);
+ if (result.empty() && !errorMessage.isEmpty()) {
+ QString message;
+ QTextStream str(&message);
+ str << "Unable to retrieve code snippet \"" << getCursorSpelling(cursor)
+ << "\": " << errorMessage;
+ appendDiagnostic(Diagnostic(message, cursor, CXDiagnostic_Error));
+ }
+ return result;
+}
+
+bool BaseVisitor::_handleVisitLocation(const CXSourceLocation &location)
+{
+ CXFile cxFile; // void *
+ unsigned line;
+ unsigned column;
+ unsigned offset;
+ clang_getExpansionLocation(location, &cxFile, &line, &column, &offset);
+
+ if (cxFile == m_currentCxFile) // Same file?
+ return m_visitCurrent;
+
+ const QString fileName = getFileName(cxFile);
+
+ LocationType locationType = LocationType::Unknown;
+ if (!fileName.isEmpty()) {
+ if (clang_Location_isFromMainFile(location) != 0)
+ locationType = LocationType::Main;
+ else if (clang_Location_isInSystemHeader(location) != 0)
+ locationType = LocationType::System;
+ else
+ locationType = LocationType::Other;
+ }
+
+ m_currentCxFile = cxFile;
+ m_visitCurrent = visitLocation(fileName, locationType);
+ return m_visitCurrent;
+}
+
+QString BaseVisitor::getCodeSnippetString(const CXCursor &cursor)
+{
+ const std::string_view result = getCodeSnippet(cursor);
+ return result.empty()
+ ? QString()
+ : QString::fromUtf8(result.data(), qsizetype(result.size()));
+}
+
+static CXChildVisitResult
+ visitorCallback(CXCursor cursor, CXCursor /* parent */, CXClientData clientData)
+{
+ auto *bv = reinterpret_cast<BaseVisitor *>(clientData);
+
+ const CXSourceLocation location = clang_getCursorLocation(cursor);
+ if (!bv->_handleVisitLocation(location))
+ return CXChildVisit_Continue;
+
+ const BaseVisitor::StartTokenResult startResult = bv->cbHandleStartToken(cursor);
+ switch (startResult) {
+ case clang::BaseVisitor::Error:
+ return CXChildVisit_Break;
+ case clang::BaseVisitor::Skip:
+ break;
+ case clang::BaseVisitor::Recurse:
+ clang_visitChildren(cursor, visitorCallback, clientData);
+ break;
+ }
+
+ if (!bv->cbHandleEndToken(cursor, startResult))
+ return CXChildVisit_Break;
+
+ return CXChildVisit_Continue;
+}
+
+BaseVisitor::Diagnostics BaseVisitor::diagnostics() const
+{
+ return m_diagnostics;
+}
+
+void BaseVisitor::setDiagnostics(const Diagnostics &d)
+{
+ m_diagnostics = d;
+}
+
+void BaseVisitor::appendDiagnostic(const Diagnostic &d)
+{
+ m_diagnostics.append(d);
+}
+
+static inline const char **byteArrayListToFlatArgV(const QByteArrayList &bl)
+{
+ const char **result = new const char *[bl.size() + 1];
+ result[bl.size()] = nullptr;
+ std::transform(bl.cbegin(), bl.cend(), result,
+ [] (const QByteArray &a) { return a.constData(); });
+ return result;
+}
+
+static QByteArray msgCreateTranslationUnit(const QByteArrayList &clangArgs, unsigned flags)
+{
+ QByteArray result = "clang_parseTranslationUnit2(0x";
+ result += QByteArray::number(flags, 16);
+ const auto count = clangArgs.size();
+ result += ", cmd[" + QByteArray::number(count) + "]=";
+ for (qsizetype i = 0; i < count; ++i) {
+ const QByteArray &arg = clangArgs.at(i);
+ if (i)
+ result += ' ';
+ const bool quote = arg.contains(' ') || arg.contains('(');
+ if (quote)
+ result += '"';
+ result += arg;
+ if (quote)
+ result += '"';
+ }
+ result += ')';
+ return result;
+}
+
+static CXTranslationUnit createTranslationUnit(CXIndex index,
+ const QByteArrayList &args,
+ bool addCompilerSupportArguments,
+ LanguageLevel level,
+ unsigned flags = 0)
+{
+ // courtesy qdoc
+ const unsigned defaultFlags = CXTranslationUnit_Incomplete;
+
+ static const QByteArrayList defaultArgs = {
+#ifndef Q_OS_WIN
+ "-fPIC",
+#endif
+#ifdef Q_OS_MACOS
+ "-Wno-expansion-to-defined", // Workaround for warnings in Darwin stdlib, see
+ // https://github.com/darlinghq/darling/issues/204
+#endif
+ "-Wno-constant-logical-operand",
+ "-x",
+ "c++" // Treat .h as C++, not C
+ };
+
+ QByteArrayList clangArgs;
+ if (addCompilerSupportArguments) {
+ clangArgs += emulatedCompilerOptions(level);
+ clangArgs += defaultArgs;
+ }
+ clangArgs += detectVulkan();
+ clangArgs += args;
+ QScopedArrayPointer<const char *> argv(byteArrayListToFlatArgV(clangArgs));
+ qDebug().noquote().nospace() << msgCreateTranslationUnit(clangArgs, flags);
+
+ CXTranslationUnit tu;
+ CXErrorCode err = clang_parseTranslationUnit2(index, nullptr, argv.data(),
+ clangArgs.size(), nullptr, 0,
+ defaultFlags | flags, &tu);
+ if (err || !tu) {
+ qWarning().noquote().nospace() << "Could not parse "
+ << clangArgs.constLast().constData() << ", error code: " << err;
+ return nullptr;
+ }
+ return tu;
+}
+
+/* clangFlags are flags to clang_parseTranslationUnit2() such as
+ * CXTranslationUnit_KeepGoing (from CINDEX_VERSION_MAJOR/CINDEX_VERSION_MINOR 0.35)
+ */
+
+bool parse(const QByteArrayList &clangArgs, bool addCompilerSupportArguments,
+ LanguageLevel level, unsigned clangFlags, BaseVisitor &bv)
+{
+ CXIndex index = clang_createIndex(0 /* excludeDeclarationsFromPCH */,
+ 1 /* displayDiagnostics */);
+ if (!index) {
+ qWarning() << "clang_createIndex() failed!";
+ return false;
+ }
+
+ CXTranslationUnit translationUnit =
+ createTranslationUnit(index, clangArgs, addCompilerSupportArguments,
+ level, clangFlags);
+ if (!translationUnit)
+ return false;
+
+ CXCursor rootCursor = clang_getTranslationUnitCursor(translationUnit);
+
+ clang_visitChildren(rootCursor, visitorCallback, reinterpret_cast<CXClientData>(&bv));
+
+ QList<Diagnostic> diagnostics = getDiagnostics(translationUnit);
+ diagnostics.append(bv.diagnostics());
+ bv.setDiagnostics(diagnostics);
+
+ const bool ok = maxSeverity(diagnostics) < CXDiagnostic_Error;
+ if (!ok) {
+ QDebug debug = qWarning();
+ debug.noquote();
+ debug.nospace();
+ debug << "Errors in "
+ << QDir::toNativeSeparators(QFile::decodeName(clangArgs.constLast())) << ":\n";
+ for (const Diagnostic &diagnostic : std::as_const(diagnostics))
+ debug << diagnostic << '\n';
+ }
+
+ clang_disposeTranslationUnit(translationUnit);
+ clang_disposeIndex(index);
+ return ok;
+}
+
+} // namespace clang
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangparser.h b/sources/shiboken6/ApiExtractor/clangparser/clangparser.h
new file mode 100644
index 000000000..22e0a50cd
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangparser.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CLANGPARSER_H
+#define CLANGPARSER_H
+
+#include <clang-c/Index.h>
+
+#include <QtCore/QByteArrayList>
+#include <QtCore/QHash>
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+#include <string_view>
+#include <utility>
+
+enum class LanguageLevel;
+
+namespace clang {
+
+struct Diagnostic;
+
+class SourceFileCache {
+public:
+ std::string_view getCodeSnippet(const CXCursor &cursor, QString *errorMessage = nullptr);
+ QString getFileName(CXFile file);
+
+private:
+ using FileBufferCache = QHash<CXFile, QByteArray>;
+ using FileNameCache = QHash<CXFile, QString>;
+
+ FileBufferCache m_fileBufferCache;
+ FileNameCache m_fileNameCache;
+};
+
+enum class LocationType
+{
+ Main, // Main header parsed for bindings
+ Other, // A header parsed for bindings
+ System, // A system header
+ Unknown // Clang internal
+};
+
+class BaseVisitor {
+ Q_DISABLE_COPY_MOVE(BaseVisitor)
+public:
+ using Diagnostics = QList<Diagnostic>;
+
+ enum StartTokenResult { Error, Skip, Recurse };
+
+ BaseVisitor();
+ virtual ~BaseVisitor();
+
+ // Whether location should be visited.
+ // defaults to clang_Location_isFromMainFile()
+ virtual bool visitLocation(const QString &fileName, LocationType locationType) const;
+
+ virtual StartTokenResult startToken(const CXCursor &cursor) = 0;
+ virtual bool endToken(const CXCursor &cursor) = 0;
+
+ StartTokenResult cbHandleStartToken(const CXCursor &cursor);
+ bool cbHandleEndToken(const CXCursor &cursor, StartTokenResult startResult);
+
+ QString getFileName(CXFile file) { return m_fileCache.getFileName(file); }
+ std::string_view getCodeSnippet(const CXCursor &cursor);
+ QString getCodeSnippetString(const CXCursor &cursor);
+
+ Diagnostics diagnostics() const;
+ void setDiagnostics(const Diagnostics &d);
+ void appendDiagnostic(const Diagnostic &d);
+
+ // For usage by the parser
+ bool _handleVisitLocation( const CXSourceLocation &location);
+
+private:
+ SourceFileCache m_fileCache;
+ Diagnostics m_diagnostics;
+ CXFile m_currentCxFile{};
+ bool m_visitCurrent = true;
+};
+
+bool parse(const QByteArrayList &clangArgs,
+ bool addCompilerSupportArguments,
+ LanguageLevel level, unsigned clangFlags, BaseVisitor &ctx);
+
+} // namespace clang
+
+#endif // !CLANGPARSER_H
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangutils.cpp
new file mode 100644
index 000000000..1651e09ec
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangutils.cpp
@@ -0,0 +1,320 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "clangutils.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QHashFunctions>
+#include <QtCore/QProcess>
+
+#include <string_view>
+
+bool operator==(const CXCursor &c1, const CXCursor &c2) noexcept
+{
+ return c1.kind == c2.kind
+ && c1.xdata == c2.xdata
+ && std::equal(c1.data, c1.data + sizeof(c1.data) / sizeof(c1.data[0]), c2.data);
+}
+
+size_t qHash(const CXCursor &c, size_t seed) noexcept
+{
+ return qHashMulti(seed, c.kind, c.xdata, c.data[0], c.data[1], c.data[2]);
+}
+
+bool operator==(const CXType &t1, const CXType &t2) noexcept
+{
+ return t1.kind == t2.kind && t1.data[0] == t2.data[0]
+ && t1.data[1] == t2.data[1];
+}
+
+size_t qHash(const CXType &ct, size_t seed) noexcept
+{
+ return qHashMulti(seed, ct.kind, ct.data[0], ct.data[1]);
+}
+
+namespace clang {
+
+SourceLocation getExpansionLocation(const CXSourceLocation &location)
+{
+ SourceLocation result;
+ clang_getExpansionLocation(location, &result.file, &result.line, &result.column, &result.offset);
+ return result;
+}
+
+QString getFileName(CXFile file)
+{
+ QString result;
+ const CXString cxFileName = clang_getFileName(file);
+ // Has been observed to be 0 for invalid locations
+ if (const char *cFileName = clang_getCString(cxFileName))
+ result = QString::fromUtf8(cFileName);
+ clang_disposeString(cxFileName);
+ return result;
+}
+
+SourceLocation getCursorLocation(const CXCursor &cursor)
+{
+ const CXSourceRange extent = clang_getCursorExtent(cursor);
+ return getExpansionLocation(clang_getRangeStart(extent));
+}
+
+CXString getFileNameFromLocation(const CXSourceLocation &location)
+{
+ CXFile file;
+ unsigned line;
+ unsigned column;
+ unsigned offset;
+ clang_getExpansionLocation(location, &file, &line, &column, &offset);
+ return clang_getFileName(file);
+}
+
+SourceRange getCursorRange(const CXCursor &cursor)
+{
+ const CXSourceRange extent = clang_getCursorExtent(cursor);
+ return std::make_pair(getExpansionLocation(clang_getRangeStart(extent)),
+ getExpansionLocation(clang_getRangeEnd(extent)));
+}
+
+QString getCursorKindName(CXCursorKind cursorKind)
+{
+ CXString kindName = clang_getCursorKindSpelling(cursorKind);
+ const QString result = QString::fromUtf8(clang_getCString(kindName));
+ clang_disposeString(kindName);
+ return result;
+}
+
+QString getCursorSpelling(const CXCursor &cursor)
+{
+ CXString cursorSpelling = clang_getCursorSpelling(cursor);
+ const QString result = QString::fromUtf8(clang_getCString(cursorSpelling));
+ clang_disposeString(cursorSpelling);
+ return result;
+}
+
+QString getCursorDisplayName(const CXCursor &cursor)
+{
+ CXString displayName = clang_getCursorDisplayName(cursor);
+ const QString result = QString::fromUtf8(clang_getCString(displayName));
+ clang_disposeString(displayName);
+ return result;
+}
+
+static inline bool isBuiltinType(CXTypeKind kind)
+{
+ return kind >= CXType_FirstBuiltin && kind <= CXType_LastBuiltin;
+}
+
+// Resolve elaborated types occurring with clang 16
+static CXType resolveElaboratedType(const CXType &type)
+{
+ if (!isBuiltinType(type.kind)) {
+ CXCursor decl = clang_getTypeDeclaration(type);
+ auto resolvedType = clang_getCursorType(decl);
+ if (resolvedType.kind != CXType_Invalid && resolvedType.kind != type.kind)
+ return resolvedType;
+ }
+ return type;
+}
+
+// Resolve typedefs
+static CXType resolveTypedef(const CXType &type)
+{
+ auto result = type;
+ while (result.kind == CXType_Typedef) {
+ auto decl = clang_getTypeDeclaration(result);
+ auto resolved = clang_getTypedefDeclUnderlyingType(decl);
+ if (resolved.kind == CXType_Invalid)
+ break;
+ result = resolved;
+ }
+ return result;
+}
+
+// Fully resolve a type from elaborated & typedefs
+CXType fullyResolveType(const CXType &type)
+{
+ return resolveTypedef(resolveElaboratedType(type));
+}
+
+QString getTypeName(const CXType &type)
+{
+ CXString typeSpelling = clang_getTypeSpelling(type);
+ const QString result = QString::fromUtf8(clang_getCString(typeSpelling));
+ clang_disposeString(typeSpelling);
+ return result;
+}
+
+// Quick check for "::Type"
+bool hasScopeResolution(const CXType &type)
+{
+ CXString typeSpelling = clang_getTypeSpelling(type);
+ std::string_view spelling = clang_getCString(typeSpelling);
+ const bool result = spelling.compare(0, 2, "::") == 0
+ || spelling.find(" ::") != std::string::npos;
+ clang_disposeString(typeSpelling);
+ return result;
+}
+
+// Resolve elaborated types occurring with clang 16
+QString getResolvedTypeName(const CXType &type)
+{
+ return getTypeName(resolveElaboratedType(type));
+}
+
+Diagnostic::Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s)
+ : message(m), source(Other), severity(s)
+{
+ setLocation(getCursorLocation(c));
+}
+
+Diagnostic Diagnostic::fromCXDiagnostic(CXDiagnostic cd)
+{
+ Diagnostic result;
+ result.source = Clang;
+ CXString spelling = clang_getDiagnosticSpelling(cd);
+ result.message = QString::fromUtf8(clang_getCString(spelling));
+ clang_disposeString(spelling);
+ result.severity = clang_getDiagnosticSeverity(cd);
+ result.setLocation(getExpansionLocation(clang_getDiagnosticLocation(cd)));
+
+ CXDiagnosticSet childDiagnostics = clang_getChildDiagnostics(cd);
+ if (const unsigned childCount = clang_getNumDiagnosticsInSet(childDiagnostics)) {
+ result.childMessages.reserve(int(childCount));
+ const unsigned format = clang_defaultDiagnosticDisplayOptions();
+ for (unsigned i = 0; i < childCount; ++i) {
+ CXDiagnostic childDiagnostic = clang_getDiagnosticInSet(childDiagnostics, i);
+ CXString cdm = clang_formatDiagnostic(childDiagnostic, format);
+ result.childMessages.append(QString::fromUtf8(clang_getCString(cdm)));
+ clang_disposeString(cdm);
+ clang_disposeDiagnostic(childDiagnostic);
+ }
+ }
+
+ return result;
+}
+
+void Diagnostic::setLocation(const SourceLocation &sourceLocation)
+{
+ file = getFileName(sourceLocation.file);
+ line = sourceLocation.line;
+ column = sourceLocation.column;
+ offset = sourceLocation.offset;
+}
+
+QList<Diagnostic> getDiagnostics(CXTranslationUnit tu)
+{
+ QList<Diagnostic> result;
+ const unsigned count = clang_getNumDiagnostics(tu);
+ result.reserve(int(count));
+ for (unsigned i = 0; i < count; ++i) {
+ const CXDiagnostic d = clang_getDiagnostic(tu, i);
+ result.append(Diagnostic::fromCXDiagnostic(d));
+ clang_disposeDiagnostic(d);
+ }
+ return result;
+}
+
+std::pair<qsizetype, qsizetype>
+ parseTemplateArgumentList(const QString &l,
+ const TemplateArgumentHandler &handler,
+ qsizetype from)
+{
+ const auto ltPos = l.indexOf(u'<', from);
+ if (ltPos == - 1)
+ return std::make_pair(-1, -1);
+ auto startPos = ltPos + 1;
+ int level = 1;
+ for (qsizetype p = startPos, end = l.size(); p < end; ) {
+ const char c = l.at(p).toLatin1();
+ switch (c) {
+ case ',':
+ case '>':
+ handler(level, QStringView{l}.mid(startPos, p - startPos).trimmed());
+ ++p;
+ if (c == '>') {
+ if (--level == 0)
+ return std::make_pair(ltPos, p);
+ // Skip over next ',': "a<b<c,d>,e>"
+ for (; p < end && (l.at(p).isSpace() || l.at(p) == u','); ++p) {}
+ }
+ startPos = p;
+ break;
+ case '<':
+ handler(level, QStringView{l}.mid(startPos, p - startPos).trimmed());
+ ++level;
+ startPos = ++p;
+ break;
+ default:
+ ++p;
+ break;
+ }
+ }
+ return std::make_pair(-1, -1);
+}
+
+CXDiagnosticSeverity maxSeverity(const QList<Diagnostic> &ds)
+{
+ CXDiagnosticSeverity result = CXDiagnostic_Ignored;
+ for (const Diagnostic& d : ds) {
+ if (d.severity > result)
+ result = d.severity;
+ }
+ return result;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug s, const SourceLocation &l)
+{
+ QDebugStateSaver saver(s);
+ s.nospace();
+ s.noquote();
+ s << QDir::toNativeSeparators(clang::getFileName(l.file)) << ':' << l.line;
+ if (l.column)
+ s << ':' << l.column;
+ return s;
+}
+
+// Roughly follow g++ format:
+// file.cpp:214:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
+QDebug operator<<(QDebug s, const Diagnostic &d)
+{
+ QDebugStateSaver saver(s);
+ s.nospace();
+ s.noquote();
+ s << d.file << ':'<< d.line << ':' << d.column << ": ";
+ switch (d.severity) {
+ case CXDiagnostic_Ignored:
+ s << "ignored";
+ break;
+ case CXDiagnostic_Note:
+ s << "note";
+ break;
+ case CXDiagnostic_Warning:
+ s << "warning";
+ break;
+ case CXDiagnostic_Error:
+ s << "error";
+ break;
+ case CXDiagnostic_Fatal:
+ s << "fatal";
+ break;
+ }
+ s << ": " << d.message;
+
+ if (d.source != Diagnostic::Clang)
+ s << " [other]";
+
+ if (const auto childMessagesCount = d.childMessages.size()) {
+ s << '\n';
+ for (qsizetype i = 0; i < childMessagesCount; ++i)
+ s << " " << d.childMessages.at(i) << '\n';
+ }
+
+ return s;
+}
+
+#endif // QT_NO_DEBUG_STREAM
+
+} // namespace clang
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangutils.h b/sources/shiboken6/ApiExtractor/clangparser/clangutils.h
new file mode 100644
index 000000000..fbbf95f1b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangutils.h
@@ -0,0 +1,108 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CLANGUTILS_H
+#define CLANGUTILS_H
+
+#include <clang-c/Index.h>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QtCompare>
+#include <QtCore/QList>
+
+#include <functional>
+#include <utility>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+bool operator==(const CXCursor &c1, const CXCursor &c2) noexcept;
+size_t qHash(const CXCursor &c, size_t seed = 0) noexcept;
+
+bool operator==(const CXType &t1, const CXType &t2) noexcept;
+size_t qHash(const CXType &ct, size_t seed = 0) noexcept;
+
+namespace clang {
+
+QString getCursorKindName(CXCursorKind cursorKind);
+QString getCursorSpelling(const CXCursor &cursor);
+QString getCursorDisplayName(const CXCursor &cursor);
+QString getTypeName(const CXType &type);
+bool hasScopeResolution(const CXType &type);
+CXType fullyResolveType(const CXType &type);
+QString getResolvedTypeName(const CXType &type);
+inline QString getCursorTypeName(const CXCursor &cursor)
+ { return getTypeName(clang_getCursorType(cursor)); }
+inline QString getCursorResultTypeName(const CXCursor &cursor)
+ { return getTypeName(clang_getCursorResultType(cursor)); }
+
+inline bool isCursorValid(const CXCursor &c)
+{
+ return c.kind < CXCursor_FirstInvalid || c.kind > CXCursor_LastInvalid;
+}
+
+QString getFileName(CXFile file); // Uncached,see BaseVisitor for a cached version
+
+struct SourceLocation
+{
+ bool equals(const SourceLocation &rhs) const;
+
+ CXFile file = nullptr;
+ unsigned line = 0;
+ unsigned column = 0;
+ unsigned offset = 0;
+
+ friend constexpr bool comparesEqual(const SourceLocation &lhs,
+ const SourceLocation &rhs) noexcept
+ {
+ return lhs.file == rhs.file && lhs.offset == rhs.offset;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(SourceLocation)
+};
+
+SourceLocation getExpansionLocation(const CXSourceLocation &location);
+
+using SourceRange = std::pair<SourceLocation, SourceLocation>;
+
+SourceLocation getCursorLocation(const CXCursor &cursor);
+CXString getFileNameFromLocation(const CXSourceLocation &location);
+SourceRange getCursorRange(const CXCursor &cursor);
+
+struct Diagnostic {
+ enum Source { Clang, Other };
+
+ Diagnostic() = default;
+ // Clang
+ static Diagnostic fromCXDiagnostic(CXDiagnostic cd);
+ // Other
+ explicit Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s = CXDiagnostic_Warning);
+ void setLocation(const SourceLocation &);
+
+ QString message;
+ QStringList childMessages;
+ QString file;
+ unsigned line = 0;
+ unsigned column = 0;
+ unsigned offset = 0;
+ Source source = Clang;
+ CXDiagnosticSeverity severity = CXDiagnostic_Warning;
+};
+
+QList<Diagnostic> getDiagnostics(CXTranslationUnit tu);
+CXDiagnosticSeverity maxSeverity(const QList<Diagnostic> &ds);
+
+// Parse a template argument list "a<b<c,d>,e>" and invoke a handler
+// with each match (level and string). Return begin and end of the list.
+using TemplateArgumentHandler = std::function<void (int, QStringView)>;
+
+std::pair<qsizetype, qsizetype>
+ parseTemplateArgumentList(const QString &l,
+ const TemplateArgumentHandler &handler,
+ qsizetype from = 0);
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug, const SourceLocation &);
+QDebug operator<<(QDebug, const Diagnostic &);
+#endif // QT_NO_DEBUG_STREAM
+} // namespace clang
+
+#endif // CLANGUTILS_H
diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
new file mode 100644
index 000000000..20224020b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
@@ -0,0 +1,456 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "compilersupport.h"
+#include "header_paths.h"
+#include "clangutils.h"
+
+#include <reporthandler.h>
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QProcess>
+#include <QtCore/QStandardPaths>
+#include <QtCore/QStringList>
+#include <QtCore/QVersionNumber>
+
+#include <clang-c/Index.h>
+
+#include <algorithm>
+#include <iterator>
+
+using namespace Qt::StringLiterals;
+
+namespace clang {
+
+QVersionNumber libClangVersion()
+{
+ return QVersionNumber(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR);
+}
+
+static Compiler _compiler =
+#if defined (Q_CC_CLANG)
+ Compiler::Clang;
+#elif defined (Q_CC_MSVC)
+ Compiler::Msvc;
+#else
+ Compiler::Gpp;
+#endif
+
+Compiler compiler() { return _compiler; }
+
+bool setCompiler(const QString &name)
+{
+ bool result = true;
+ if (name == u"msvc")
+ _compiler = Compiler::Msvc;
+ else if (name == u"g++")
+ _compiler = Compiler::Gpp;
+ else if (name == u"clang")
+ _compiler = Compiler::Clang;
+ else
+ result = false;
+ return result;
+}
+
+QString _compilerPath; // Pre-defined compiler path (from command line)
+
+const QString &compilerPath()
+{
+ return _compilerPath;
+}
+
+void setCompilerPath(const QString &name)
+{
+ _compilerPath = name;
+}
+
+static Platform _platform =
+#if defined (Q_OS_DARWIN)
+ Platform::macOS;
+#elif defined (Q_OS_WIN)
+ Platform::Windows;
+#else
+ Platform::Unix;
+#endif
+
+Platform platform() { return _platform; }
+
+bool setPlatform(const QString &name)
+{
+ bool result = true;
+ if (name == u"windows")
+ _platform = Platform::Windows;
+ else if (name == u"darwin")
+ _platform = Platform::macOS;
+ else if (name == u"unix")
+ _platform = Platform::Unix;
+ else
+ result = false;
+ return result;
+}
+
+// 3/2024: Use a recent MSVC2022 for libclang 18.X
+static QByteArray msvcCompatVersion()
+{
+ return libClangVersion() >= QVersionNumber(0, 64) ? "19.39"_ba : "19.26"_ba;
+}
+
+static bool runProcess(const QString &program, const QStringList &arguments,
+ QByteArray *stdOutIn = nullptr, QByteArray *stdErrIn = nullptr)
+{
+ QProcess process;
+ process.start(program, arguments, QProcess::ReadWrite);
+ if (!process.waitForStarted()) {
+ qCWarning(lcShiboken).noquote().nospace() << "Unable to start "
+ << process.program() << ": " << process.errorString();
+ return false;
+ }
+ process.closeWriteChannel();
+ const bool finished = process.waitForFinished();
+ const QByteArray stdErr = process.readAllStandardError();
+ if (stdErrIn)
+ *stdErrIn = stdErr;
+ if (stdOutIn)
+ *stdOutIn = process.readAllStandardOutput();
+
+ if (!finished) {
+ qCWarning(lcShiboken).noquote().nospace() << process.program() << " timed out: " << stdErr;
+ process.kill();
+ return false;
+ }
+
+ if (process.exitStatus() != QProcess::NormalExit) {
+ qCWarning(lcShiboken).noquote().nospace() << process.program() << " crashed: " << stdErr;
+ return false;
+ }
+
+ if (process.exitCode() != 0) {
+ qCWarning(lcShiboken).noquote().nospace() << process.program() << " exited "
+ << process.exitCode() << ": " << stdErr;
+ return false;
+ }
+
+ return true;
+}
+
+static QByteArray frameworkPath() { return QByteArrayLiteral(" (framework directory)"); }
+
+static void filterHomebrewHeaderPaths(HeaderPaths &headerPaths)
+{
+ QByteArray homebrewPrefix = qgetenv("HOMEBREW_OPT");
+
+ // If HOMEBREW_OPT is found we assume that the build is happening
+ // inside a brew environment, which means we need to filter out
+ // the -isystem flags added by the brew clang shim. This is needed
+ // because brew passes the Qt include paths as system include paths
+ // and because our parser ignores system headers, Qt classes won't
+ // be found and thus compilation errors will occur.
+ if (homebrewPrefix.isEmpty())
+ return;
+
+ qCInfo(lcShiboken) << "Found HOMEBREW_OPT with value:" << homebrewPrefix
+ << "Assuming homebrew build environment.";
+
+ HeaderPaths::iterator it = headerPaths.begin();
+ while (it != headerPaths.end()) {
+ if (it->path.startsWith(homebrewPrefix)) {
+ qCInfo(lcShiboken) << "Filtering out homebrew include path: "
+ << it->path;
+ it = headerPaths.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+// Determine g++'s internal include paths from the output of
+// g++ -E -x c++ - -v </dev/null
+// Output looks like:
+// #include <...> search starts here:
+// /usr/local/include
+// /System/Library/Frameworks (framework directory)
+// End of search list.
+static HeaderPaths gppInternalIncludePaths(const QString &compiler)
+{
+ HeaderPaths result;
+ QStringList arguments{u"-E"_s, u"-x"_s, u"c++"_s, u"-"_s, u"-v"_s};
+ QByteArray stdOut;
+ QByteArray stdErr;
+ if (!runProcess(compiler, arguments, &stdOut, &stdErr))
+ return result;
+ const QByteArrayList stdErrLines = stdErr.split('\n');
+ bool isIncludeDir = false;
+
+ if (ReportHandler::isDebug(ReportHandler::MediumDebug))
+ qCInfo(lcShiboken()).noquote().nospace()
+ << "gppInternalIncludePaths:\n compiler: " << compiler
+ << "\n stdOut: " << stdOut
+ << "\n stdErr: " << stdErr;
+
+ for (const QByteArray &line : stdErrLines) {
+ if (isIncludeDir) {
+ if (line.startsWith(QByteArrayLiteral("End of search list"))) {
+ isIncludeDir = false;
+ } else {
+ HeaderPath headerPath{line.trimmed(), HeaderType::System};
+ if (headerPath.path.endsWith(frameworkPath())) {
+ headerPath.type = HeaderType::FrameworkSystem;
+ headerPath.path.truncate(headerPath.path.size() - frameworkPath().size());
+ }
+ result.append(headerPath);
+ }
+ } else if (line.startsWith(QByteArrayLiteral("#include <...> search starts here"))) {
+ isIncludeDir = true;
+ }
+ }
+
+ if (platform() == Platform::macOS)
+ filterHomebrewHeaderPaths(result);
+
+ return result;
+}
+
+// Detect Vulkan as supported from Qt 5.10 by checking the environment variables.
+QByteArrayList detectVulkan()
+{
+ static const char *vulkanVariables[] = {"VULKAN_SDK", "VK_SDK_PATH"};
+ for (const char *vulkanVariable : vulkanVariables) {
+ if (qEnvironmentVariableIsSet(vulkanVariable)) {
+ const auto option = QByteArrayLiteral("-isystem")
+ + qgetenv(vulkanVariable)
+ + QByteArrayLiteral("/include");
+ return {option};
+ }
+ }
+ return {};
+}
+
+// For MSVC, we set the MS compatibility version and let Clang figure out its own
+// options and include paths.
+// For the others, we pass "-nostdinc" since libclang tries to add it's own system
+// include paths, which together with the clang compiler paths causes some clash
+// which causes std types not being found and construct -I/-F options from the
+// include paths of the host compiler.
+
+static QByteArray noStandardIncludeOption() { return QByteArrayLiteral("-nostdinc"); }
+
+// The clang builtin includes directory is used to find the definitions for
+// intrinsic functions and builtin types. It is necessary to use the clang
+// includes to prevent redefinition errors. The default toolchain includes
+// should be picked up automatically by clang without specifying
+// them implicitly.
+
+// Besides g++/Linux, as of MSVC 19.28.29334, MSVC needs clang includes
+// due to PYSIDE-1433, LLVM-47099
+
+static bool needsClangBuiltinIncludes()
+{
+ return platform() != Platform::macOS;
+}
+
+static QString queryLlvmConfigDir(const QString &arg)
+{
+ static const QString llvmConfig = QStandardPaths::findExecutable(u"llvm-config"_s);
+ if (llvmConfig.isEmpty())
+ return {};
+ QByteArray stdOut;
+ if (!runProcess(llvmConfig, QStringList{arg}, &stdOut))
+ return {};
+ const QString path = QFile::decodeName(stdOut.trimmed());
+ if (!QFileInfo::exists(path)) {
+ qCWarning(lcShiboken, R"(%s: "%s" as returned by llvm-config "%s" does not exist.)",
+ __FUNCTION__, qPrintable(QDir::toNativeSeparators(path)), qPrintable(arg));
+ return {};
+ }
+ return path;
+}
+
+static QString findClangLibDir()
+{
+ for (const char *envVar : {"LLVM_INSTALL_DIR", "CLANG_INSTALL_DIR"}) {
+ if (qEnvironmentVariableIsSet(envVar)) {
+ const QString path = QFile::decodeName(qgetenv(envVar)) + u"/lib"_s;
+ if (QFileInfo::exists(path))
+ return path;
+ qCWarning(lcShiboken, "%s: %s as pointed to by %s does not exist.",
+ __FUNCTION__, qPrintable(path), envVar);
+ }
+ }
+ return queryLlvmConfigDir(u"--libdir"_s);
+}
+
+static QString findClangBuiltInIncludesDir()
+{
+ // Find the include directory of the highest version.
+ 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);
+ QDir clangDir(clangDirName);
+ const QFileInfoList versionDirs =
+ clangDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
+ if (versionDirs.isEmpty())
+ 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()) {
+ const QVersionNumber versionNumber = QVersionNumber::fromString(fileName);
+ if (!versionNumber.isNull() && versionNumber > lastVersionNumber) {
+ candidate = fi.absoluteFilePath();
+ lastVersionNumber = versionNumber;
+ }
+ }
+ }
+ if (!candidate.isEmpty())
+ return candidate + "/include"_L1;
+ }
+ return queryLlvmConfigDir(u"--includedir"_s);
+}
+
+QString compilerFromCMake()
+{
+#ifdef CMAKE_CXX_COMPILER
+ return QString::fromLocal8Bit(CMAKE_CXX_COMPILER);
+#else
+ return {};
+#endif
+}
+
+// Return a compiler suitable for determining the internal include paths
+static QString compilerFromCMake(const QString &defaultCompiler)
+{
+ if (!compilerPath().isEmpty())
+ return compilerPath();
+ // Exclude macOS since cmakeCompiler returns the full path instead of the
+ // /usr/bin/clang shim, which results in the default SDK sysroot path
+ // missing (PYSIDE-1032)
+ if (platform() == Platform::macOS)
+ return defaultCompiler;
+ QString cmakeCompiler = compilerFromCMake();
+ if (cmakeCompiler.isEmpty())
+ return defaultCompiler;
+ QFileInfo fi(cmakeCompiler);
+ // Should be absolute by default, but a user may specify -DCMAKE_CXX_COMPILER=cl.exe
+ if (fi.isRelative())
+ return cmakeCompiler;
+ if (fi.exists())
+ return fi.absoluteFilePath();
+ // The compiler may not exist in case something like icecream or
+ // a non-standard-path was used on the build machine. Check
+ // the executable.
+ cmakeCompiler = QStandardPaths::findExecutable(fi.fileName());
+ return cmakeCompiler.isEmpty() ? defaultCompiler : cmakeCompiler;
+}
+
+static void appendClangBuiltinIncludes(HeaderPaths *p)
+{
+ const QString clangBuiltinIncludesDir =
+ QDir::toNativeSeparators(findClangBuiltInIncludesDir());
+ if (clangBuiltinIncludesDir.isEmpty()) {
+ qCWarning(lcShiboken, "Unable to locate Clang's built-in include directory "
+ "(neither by checking the environment variables LLVM_INSTALL_DIR, CLANG_INSTALL_DIR "
+ " nor running llvm-config). This may lead to parse errors.");
+ } else {
+ qCInfo(lcShiboken, "CLANG v%d.%d, builtins includes directory: %s",
+ CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR,
+ qPrintable(clangBuiltinIncludesDir));
+ p->append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir),
+ HeaderType::System});
+ }
+}
+
+// Returns clang options needed for emulating the host compiler
+QByteArrayList emulatedCompilerOptions(LanguageLevel level)
+{
+ QByteArrayList result;
+ HeaderPaths headerPaths;
+ switch (compiler()) {
+ case Compiler::Msvc:
+ result.append("-fms-compatibility-version="_ba + msvcCompatVersion());
+ 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)
+ result.append(QByteArrayLiteral("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH"));
+ if (needsClangBuiltinIncludes())
+ appendClangBuiltinIncludes(&headerPaths);
+ break;
+ case Compiler::Clang:
+ headerPaths.append(gppInternalIncludePaths(compilerFromCMake(u"clang++"_s)));
+ result.append(noStandardIncludeOption());
+ break;
+ case Compiler::Gpp:
+ if (needsClangBuiltinIncludes())
+ appendClangBuiltinIncludes(&headerPaths);
+
+ // Append the c++ include paths since Clang is unable to find
+ // <type_traits> etc (g++ 11.3).
+ const HeaderPaths gppPaths = gppInternalIncludePaths(compilerFromCMake(u"g++"_s));
+ for (const HeaderPath &h : gppPaths) {
+ if (h.path.contains("c++") || h.path.contains("sysroot"))
+ headerPaths.append(h);
+ }
+ break;
+ }
+
+ std::transform(headerPaths.cbegin(), headerPaths.cend(),
+ std::back_inserter(result), HeaderPath::includeOption);
+ return result;
+}
+
+LanguageLevel emulatedCompilerLanguageLevel()
+{
+ return LanguageLevel::Cpp17;
+}
+
+struct LanguageLevelMapping
+{
+ const char *option;
+ LanguageLevel level;
+};
+
+static const LanguageLevelMapping languageLevelMapping[] =
+{
+ {"c++11", LanguageLevel::Cpp11},
+ {"c++14", LanguageLevel::Cpp14},
+ {"c++17", LanguageLevel::Cpp17},
+ {"c++20", LanguageLevel::Cpp20},
+ {"c++1z", LanguageLevel::Cpp1Z}
+};
+
+const char *languageLevelOption(LanguageLevel l)
+{
+ for (const LanguageLevelMapping &m : languageLevelMapping) {
+ if (m.level == l)
+ return m.option;
+ }
+ return nullptr;
+}
+
+LanguageLevel languageLevelFromOption(const char *o)
+{
+ for (const LanguageLevelMapping &m : languageLevelMapping) {
+ if (!strcmp(m.option, o))
+ return m.level;
+ }
+ return LanguageLevel::Default;
+}
+
+} // namespace clang
diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h
new file mode 100644
index 000000000..f1d63b7c3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef COMPILERSUPPORT_H
+#define COMPILERSUPPORT_H
+
+#include <QtCore/QByteArrayList>
+
+QT_FORWARD_DECLARE_CLASS(QVersionNumber)
+QT_FORWARD_DECLARE_CLASS(QString)
+
+enum class LanguageLevel {
+ Default,
+ Cpp11,
+ Cpp14,
+ Cpp17,
+ Cpp20,
+ Cpp1Z
+};
+
+enum class Compiler {
+ Msvc,
+ Gpp,
+ Clang
+};
+
+enum class Platform {
+ Unix,
+ Windows,
+ macOS
+};
+
+namespace clang {
+QVersionNumber libClangVersion();
+
+QByteArrayList emulatedCompilerOptions(LanguageLevel level);
+LanguageLevel emulatedCompilerLanguageLevel();
+
+const char *languageLevelOption(LanguageLevel l);
+LanguageLevel languageLevelFromOption(const char *);
+
+QByteArrayList detectVulkan();
+
+Compiler compiler();
+bool setCompiler(const QString &name);
+
+QString compilerFromCMake();
+
+const QString &compilerPath();
+void setCompilerPath(const QString &name);
+
+Platform platform();
+bool setPlatform(const QString &name);
+} // namespace clang
+
+#endif // COMPILERSUPPORT_H
diff --git a/sources/shiboken6/ApiExtractor/classdocumentation.cpp b/sources/shiboken6/ApiExtractor/classdocumentation.cpp
new file mode 100644
index 000000000..637e4a422
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/classdocumentation.cpp
@@ -0,0 +1,381 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "classdocumentation.h"
+#include "messages.h"
+#include "debughelpers_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QBuffer>
+#include <QtCore/QFile>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QXmlStreamAttributes>
+#include <QtCore/QXmlStreamWriter>
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+// Sort functions by name and argument count
+static bool functionDocumentationLessThan(const FunctionDocumentation &f1,
+ const FunctionDocumentation &f2)
+{
+ const int nc = f1.name.compare(f2.name);
+ if (nc != 0)
+ return nc < 0;
+ return f1.parameters.size() < f2.parameters.size();
+}
+
+static void sortDocumentation(ClassDocumentation *cd)
+{
+ std::stable_sort(cd->enums.begin(), cd->enums.end(),
+ [] (const EnumDocumentation &e1, const EnumDocumentation &e2) {
+ return e1.name < e2.name; });
+ std::stable_sort(cd->properties.begin(), cd->properties.end(),
+ [] (const PropertyDocumentation &p1, const PropertyDocumentation &p2) {
+ return p1.name < p2.name; });
+ std::stable_sort(cd->functions.begin(), cd->functions.end(),
+ functionDocumentationLessThan);
+}
+
+qsizetype ClassDocumentation::indexOfEnum(const QString &name) const
+{
+ for (qsizetype i = 0, size = enums.size(); i < size; ++i) {
+ if (enums.at(i).name == name)
+ return i;
+ }
+ return -1;
+}
+
+FunctionDocumentationList ClassDocumentation::findFunctionCandidates(const QString &name,
+ bool constant) const
+{
+ FunctionDocumentationList result;
+ std::copy_if(functions.cbegin(), functions.cend(),
+ std::back_inserter(result),
+ [name, constant](const FunctionDocumentation &fd) {
+ return fd.constant == constant && fd.name == name;
+ });
+ return result;
+}
+
+static bool matches(const FunctionDocumentation &fd, const FunctionDocumentationQuery &q)
+{
+ return fd.name == q.name && fd.constant == q.constant && fd.parameters == q.parameters;
+}
+
+qsizetype ClassDocumentation::indexOfFunction(const FunctionDocumentationList &fl,
+ const FunctionDocumentationQuery &q)
+{
+ for (qsizetype i = 0, size = fl.size(); i < size; ++i) {
+ if (matches(fl.at(i), q))
+ return i;
+ }
+ return -1;
+}
+
+qsizetype ClassDocumentation::indexOfProperty(const QString &name) const
+{
+ for (qsizetype i = 0, size = properties.size(); i < size; ++i) {
+ if (properties.at(i).name == name)
+ return i;
+ }
+ return -1;
+}
+
+enum class WebXmlCodeTag
+{
+ Class, Description, Enum, Function, Header, Parameter, Property, Typedef, Other
+};
+
+static WebXmlCodeTag tag(QStringView name)
+{
+ if (name == u"class" || name == u"namespace")
+ return WebXmlCodeTag::Class;
+ if (name == u"enum")
+ return WebXmlCodeTag::Enum;
+ if (name == u"function")
+ return WebXmlCodeTag::Function;
+ if (name == u"description")
+ return WebXmlCodeTag::Description;
+ if (name == u"header")
+ return WebXmlCodeTag::Header;
+ if (name == u"parameter")
+ return WebXmlCodeTag::Parameter;
+ if (name == u"property")
+ return WebXmlCodeTag::Property;
+ if (name == u"typedef")
+ return WebXmlCodeTag::Typedef;
+ return WebXmlCodeTag::Other;
+}
+
+static void parseWebXmlElement(WebXmlCodeTag tag, const QXmlStreamAttributes &attributes,
+ ClassDocumentation *cd)
+{
+ switch (tag) {
+ case WebXmlCodeTag::Class:
+ cd->name = attributes.value(u"name"_s).toString();
+ cd->type = ClassDocumentation::Class;
+ break;
+ case WebXmlCodeTag::Header:
+ cd->name = attributes.value(u"name"_s).toString();
+ cd->type = ClassDocumentation::Header;
+ break;
+ case WebXmlCodeTag::Enum: {
+ EnumDocumentation ed;
+ ed.name = attributes.value(u"name"_s).toString();
+ cd->enums.append(ed);
+ }
+ break;
+ case WebXmlCodeTag::Function: {
+ FunctionDocumentation fd;
+ fd.name = attributes.value(u"name"_s).toString();
+ fd.signature = attributes.value(u"signature"_s).toString();
+ fd.returnType = attributes.value(u"type"_s).toString();
+ fd.constant = attributes.value(u"const"_s) == u"true";
+ cd->functions.append(fd);
+ }
+ break;
+ case WebXmlCodeTag::Parameter:
+ Q_ASSERT(!cd->functions.isEmpty());
+ cd->functions.last().parameters.append(attributes.value(u"type"_s).toString());
+ break;
+ case WebXmlCodeTag::Property: {
+ PropertyDocumentation pd;
+ pd.name = attributes.value(u"name"_s).toString();
+ pd.brief = attributes.value(u"brief"_s).toString();
+ cd->properties.append(pd);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+// Retrieve the contents of <description>
+static QString extractWebXmlDescription(QXmlStreamReader &reader)
+{
+ QBuffer buffer;
+ buffer.open(QIODeviceBase::WriteOnly);
+ QXmlStreamWriter writer(&buffer);
+
+ do {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ writer.writeStartElement(reader.name().toString());
+ writer.writeAttributes(reader.attributes());
+ break;
+ case QXmlStreamReader::Characters:
+ writer.writeCharacters(reader.text().toString());
+ break;
+ case QXmlStreamReader::EndElement:
+ writer.writeEndElement();
+ if (reader.name() == u"description") {
+ buffer.close();
+ return QString::fromUtf8(buffer.buffer()).trimmed();
+ }
+ break;
+ default:
+ break;
+ }
+ reader.readNext();
+ } while (!reader.atEnd());
+
+ return {};
+}
+
+static QString msgXmlError(const QString &fileName, const QXmlStreamReader &reader)
+{
+ QString result;
+ QTextStream(&result) << fileName << ':' << reader.lineNumber() << ':'
+ << reader.columnNumber() << ':' << reader.errorString();
+ return result;
+}
+
+std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString *errorMessage)
+{
+ ClassDocumentation result;
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ *errorMessage = msgCannotOpenForReading(file);
+ return std::nullopt;
+ }
+
+ WebXmlCodeTag lastTag = WebXmlCodeTag::Other;
+ QXmlStreamReader reader(&file);
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::StartElement: {
+ const auto currentTag = tag(reader.name());
+ parseWebXmlElement(currentTag, reader.attributes(), &result);
+ switch (currentTag) { // Store relevant tags in lastTag
+ case WebXmlCodeTag::Class:
+ case WebXmlCodeTag::Function:
+ case WebXmlCodeTag::Enum:
+ case WebXmlCodeTag::Header:
+ case WebXmlCodeTag::Property:
+ case WebXmlCodeTag::Typedef:
+ lastTag = currentTag;
+ break;
+ case WebXmlCodeTag::Description: { // Append the description to the element
+ QString *target = nullptr;
+ switch (lastTag) {
+ case WebXmlCodeTag::Class:
+ target = &result.description;
+ break;
+ case WebXmlCodeTag::Function:
+ target = &result.functions.last().description;
+ break;
+ case WebXmlCodeTag::Enum:
+ target = &result.enums.last().description;
+ break;
+ case WebXmlCodeTag::Property:
+ target = &result.properties.last().description;
+ default:
+ break;
+ }
+ if (target != nullptr && target->isEmpty())
+ *target = extractWebXmlDescription(reader);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ default:
+ break;
+ }
+ }
+
+ if (reader.error() != QXmlStreamReader::NoError) {
+ *errorMessage= msgXmlError(fileName, reader);
+ return std::nullopt;
+ }
+
+ sortDocumentation(&result);
+ return result;
+}
+
+QString webXmlModuleDescription(const QString &fileName, QString *errorMessage)
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ *errorMessage = msgCannotOpenForReading(file);
+ return {};
+ }
+
+ QString result;
+ QXmlStreamReader reader(&file);
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == u"description")
+ result = extractWebXmlDescription(reader);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (reader.error() != QXmlStreamReader::NoError) {
+ *errorMessage= msgXmlError(fileName, reader);
+ return {};
+ }
+
+ return result;
+}
+
+static void formatDescription(QDebug &debug, const QString &desc)
+{
+ debug << "description=";
+ if (desc.isEmpty()) {
+ debug << "<empty>";
+ return;
+ }
+ if (debug.verbosity() < 3)
+ debug << desc.size() << " chars";
+ else
+ debug << '"' << desc << '"';
+}
+
+QDebug operator<<(QDebug debug, const EnumDocumentation &e)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Enum(";
+ if (e.name.isEmpty()) {
+ debug << "invalid";
+ } else {
+ debug << e.name << ", ";
+ formatDescription(debug, e.description);
+ }
+ debug << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const PropertyDocumentation &p)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Property(";
+ if (p.name.isEmpty()) {
+ debug << "invalid";
+ } else {
+ debug << p.name << ", ";
+ formatDescription(debug, p.description);
+ }
+ debug << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const FunctionDocumentation &f)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Function(";
+ if (f.name.isEmpty()) {
+ debug << "invalid";
+ } else {
+ debug << f.name;
+ if (!f.returnType.isEmpty())
+ debug << ", returns " << f.returnType;
+ if (f.constant)
+ debug << ", const";
+ formatList(debug, ", parameters", f.parameters, ", ");
+ debug << ", signature=\"" << f.signature << "\", ";
+ formatDescription(debug, f.description);
+ }
+ debug << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const FunctionDocumentationQuery &q)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "FunctionQuery(" << q.name;
+ if (q.constant)
+ debug << ", const";
+ formatList(debug, ", parameters", q.parameters);
+ debug << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const ClassDocumentation &c)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Class(" << c.name << ", ";
+ formatDescription(debug, c.description);
+ formatList(debug, ", enums", c.enums);
+ formatList(debug, ", properties", c.properties);
+ formatList(debug, ", functions", c.functions);
+ debug << ')';
+ return debug;
+}
diff --git a/sources/shiboken6/ApiExtractor/classdocumentation.h b/sources/shiboken6/ApiExtractor/classdocumentation.h
new file mode 100644
index 000000000..d47101389
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/classdocumentation.h
@@ -0,0 +1,82 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CLASSDOCUMENTATION_H
+#define CLASSDOCUMENTATION_H
+
+#include <QtCore/QStringList>
+
+#include <optional>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+/// An enumeration in a WebXML/doxygen document
+struct EnumDocumentation
+{
+ QString name;
+ QString description;
+};
+
+/// A QObject property in a WebXML/doxygen document
+struct PropertyDocumentation
+{
+ QString name;
+ QString brief;
+ QString description;
+};
+
+/// Helper struct for querying a function in a WebXML/doxygen document
+struct FunctionDocumentationQuery
+{
+ QString name;
+ QStringList parameters;
+ bool constant = false;
+};
+
+/// A function in a WebXML/doxygen document
+struct FunctionDocumentation : public FunctionDocumentationQuery
+{
+ QString signature;
+ QString returnType;
+ QString description;
+};
+
+using FunctionDocumentationList = QList<FunctionDocumentation>;
+
+/// A WebXML/doxygen document
+struct ClassDocumentation
+{
+ enum Type {
+ Class, // <class>, class/namespace
+ Header // <header>, grouped global functions/enums
+ };
+
+ qsizetype indexOfEnum(const QString &name) const;
+ FunctionDocumentationList findFunctionCandidates(const QString &name,
+ bool constant) const;
+ static qsizetype indexOfFunction(const FunctionDocumentationList &fl,
+ const FunctionDocumentationQuery &q);
+ qsizetype indexOfProperty(const QString &name) const;
+
+ Type type = Type::Class;
+ QString name;
+ QString description;
+
+ QList<EnumDocumentation> enums;
+ QList<PropertyDocumentation> properties;
+ FunctionDocumentationList functions;
+};
+
+/// Parse a WebXML class/namespace document
+std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString *errorMessage);
+
+/// Extract the module description from a WebXML module document
+QString webXmlModuleDescription(const QString &fileName, QString *errorMessage);
+
+QDebug operator<<(QDebug debug, const EnumDocumentation &e);
+QDebug operator<<(QDebug debug, const PropertyDocumentation &p);
+QDebug operator<<(QDebug debug, const FunctionDocumentationQuery &q);
+QDebug operator<<(QDebug debug, const FunctionDocumentation &f);
+QDebug operator<<(QDebug debug, const ClassDocumentation &c);
+
+#endif // CLASSDOCUMENTATION_H
diff --git a/sources/shiboken6/ApiExtractor/cmake_uninstall.cmake b/sources/shiboken6/ApiExtractor/cmake_uninstall.cmake
new file mode 100644
index 000000000..4031b4e1a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/cmake_uninstall.cmake
@@ -0,0 +1,24 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+FOREACH(file ${files})
+ MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+ IF(EXISTS "$ENV{DESTDIR}${file}")
+ EXEC_PROGRAM(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ IF(NOT "${rm_retval}" STREQUAL 0)
+ MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+ ENDIF(NOT "${rm_retval}" STREQUAL 0)
+ ELSE(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
+ ENDIF(EXISTS "$ENV{DESTDIR}${file}")
+ENDFOREACH(file)
diff --git a/sources/shiboken6/ApiExtractor/codesnip.cpp b/sources/shiboken6/ApiExtractor/codesnip.cpp
new file mode 100644
index 000000000..e2cd5eb35
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/codesnip.cpp
@@ -0,0 +1,78 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "codesnip.h"
+
+#include "qtcompat.h"
+#include "exception.h"
+#include "typedatabase.h"
+
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+QString TemplateInstance::expandCode() const
+{
+ const auto templateEntry = TypeDatabase::instance()->findTemplate(m_name);
+ if (!templateEntry) {
+ const QString m = u"<insert-template> referring to non-existing template '"_s
+ + m_name + u"'."_s;
+ throw Exception(m);
+ }
+
+ QString code = templateEntry->code();
+ for (auto it = replaceRules.cbegin(), end = replaceRules.cend(); it != end; ++it)
+ code.replace(it.key(), it.value());
+ while (!code.isEmpty() && code.at(code.size() - 1).isSpace())
+ code.chop(1);
+ QString result = u"// TEMPLATE - "_s + m_name + u" - START"_s;
+ if (!code.startsWith(u'\n'))
+ result += u'\n';
+ result += code;
+ result += u"\n// TEMPLATE - "_s + m_name + u" - END\n"_s;
+ return result;
+}
+
+// ---------------------- CodeSnipFragment
+QString CodeSnipFragment::code() const
+{
+ return m_instance ? m_instance->expandCode() : m_code;
+}
+
+// ---------------------- CodeSnipAbstract
+QString CodeSnipAbstract::code() const
+{
+ QString res;
+ for (const CodeSnipFragment &codeFrag : codeList)
+ res.append(codeFrag.code());
+
+ return res;
+}
+
+void CodeSnipAbstract::addCode(const QString &code)
+{
+ codeList.append(CodeSnipFragment(fixSpaces(code)));
+}
+
+void CodeSnipAbstract::purgeEmptyFragments()
+{
+ auto end = std::remove_if(codeList.begin(), codeList.end(),
+ [](const CodeSnipFragment &f) { return f.isEmpty(); });
+ codeList.erase(end, codeList.end());
+}
+
+QRegularExpression CodeSnipAbstract::placeHolderRegex(int index)
+{
+ return QRegularExpression(u'%' + QString::number(index) + "\\b"_L1);
+}
+
+void purgeEmptyCodeSnips(QList<CodeSnip> *list)
+{
+ for (auto it = list->begin(); it != list->end(); ) {
+ it->purgeEmptyFragments();
+ if (it->isEmpty())
+ it = list->erase(it);
+ else
+ ++it;
+ }
+}
diff --git a/sources/shiboken6/ApiExtractor/codesnip.h b/sources/shiboken6/ApiExtractor/codesnip.h
new file mode 100644
index 000000000..86834a1db
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/codesnip.h
@@ -0,0 +1,107 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CODESNIP_H
+#define CODESNIP_H
+
+#include "codesniphelpers.h"
+#include "typesystem_enums.h"
+
+#include <QtCore/QList>
+#include <QtCore/QHash>
+#include <QtCore/QString>
+
+#include <memory>
+
+class TemplateInstance
+{
+public:
+ explicit TemplateInstance(const QString &name) : m_name(name) {}
+
+ void addReplaceRule(const QString &name, const QString &value)
+ {
+ replaceRules[name] = value;
+ }
+
+ QString expandCode() const;
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+private:
+ const QString m_name;
+ QHash<QString, QString> replaceRules;
+};
+
+using TemplateInstancePtr = std::shared_ptr<TemplateInstance>;
+
+class CodeSnipFragment
+{
+public:
+ CodeSnipFragment() = default;
+ explicit CodeSnipFragment(const QString &code) : m_code(code) {}
+ explicit CodeSnipFragment(const TemplateInstancePtr &instance) : m_instance(instance) {}
+
+ bool isEmpty() const { return m_code.isEmpty() && !m_instance; }
+
+ QString code() const;
+
+ TemplateInstancePtr instance() const { return m_instance; }
+
+private:
+ QString m_code;
+ std::shared_ptr<TemplateInstance> m_instance;
+};
+
+class CodeSnipAbstract : public CodeSnipHelpers
+{
+public:
+ QString code() const;
+
+ void addCode(const QString &code);
+ void addCode(QStringView code) { addCode(code.toString()); }
+
+ void addTemplateInstance(const TemplateInstancePtr &ti)
+ {
+ codeList.append(CodeSnipFragment(ti));
+ }
+
+ bool isEmpty() const { return codeList.isEmpty(); }
+ void purgeEmptyFragments();
+
+ QList<CodeSnipFragment> codeList;
+
+ static QRegularExpression placeHolderRegex(int index);
+};
+
+class TemplateEntry : public CodeSnipAbstract
+{
+public:
+ explicit TemplateEntry(const QString &name) : m_name(name) {}
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+private:
+ QString m_name;
+};
+
+class CodeSnip : public CodeSnipAbstract
+{
+public:
+ CodeSnip() = default;
+ explicit CodeSnip(TypeSystem::Language lang) : language(lang) {}
+
+ TypeSystem::Language language = TypeSystem::TargetLangCode;
+ TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny;
+};
+
+/// Purge empty fragments and snippets caused by new line characters in
+/// conjunction with <insert-template>.
+void purgeEmptyCodeSnips(QList<CodeSnip> *list);
+
+#endif // CODESNIP_H
diff --git a/sources/shiboken6/ApiExtractor/codesniphelpers.cpp b/sources/shiboken6/ApiExtractor/codesniphelpers.cpp
new file mode 100644
index 000000000..775cf10af
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/codesniphelpers.cpp
@@ -0,0 +1,77 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "codesniphelpers.h"
+
+#include <QtCore/QStringList>
+
+#include <algorithm>
+
+static inline int firstNonBlank(QStringView s)
+{
+ const auto it = std::find_if(s.cbegin(), s.cend(),
+ [] (QChar c) { return !c.isSpace(); });
+ return int(it - s.cbegin());
+}
+
+static inline bool isEmpty(QStringView s)
+{
+ return s.isEmpty()
+ || std::all_of(s.cbegin(), s.cend(),
+ [] (QChar c) { return c.isSpace(); });
+}
+
+QString CodeSnipHelpers::dedent(const QString &code)
+{
+ if (code.isEmpty())
+ return code;
+ // Right trim if indent=0, or trim if single line
+ if (!code.at(0).isSpace() || !code.contains(u'\n'))
+ return code.trimmed();
+ const auto lines = QStringView{code}.split(u'\n');
+ int spacesToRemove = std::numeric_limits<int>::max();
+ for (const auto &line : lines) {
+ if (!isEmpty(line)) {
+ const int nonSpacePos = firstNonBlank(line);
+ if (nonSpacePos < spacesToRemove)
+ spacesToRemove = nonSpacePos;
+ if (spacesToRemove == 0)
+ return code;
+ }
+ }
+ QString result;
+ for (const auto &line : lines) {
+ if (!isEmpty(line) && spacesToRemove < line.size())
+ result += line.mid(spacesToRemove).toString();
+ result += u'\n';
+ }
+ return result;
+}
+
+QString CodeSnipHelpers::fixSpaces(QString code)
+{
+ code.remove(u'\r');
+ // Check for XML <tag>\n<space>bla...
+ if (code.startsWith(u"\n "))
+ code.remove(0, 1);
+ while (!code.isEmpty() && code.back().isSpace())
+ code.chop(1);
+ code = dedent(code);
+ if (!code.isEmpty() && !code.endsWith(u'\n'))
+ code.append(u'\n');
+ return code;
+}
+
+// Prepend a line to the code, observing indentation
+void CodeSnipHelpers::prependCode(QString *code, QString firstLine)
+{
+ while (!code->isEmpty() && code->front() == u'\n')
+ code->remove(0, 1);
+ if (!code->isEmpty() && code->front().isSpace()) {
+ const int indent = firstNonBlank(*code);
+ firstLine.prepend(QString(indent, u' '));
+ }
+ if (!firstLine.endsWith(u'\n'))
+ firstLine += u'\n';
+ code->prepend(firstLine);
+}
diff --git a/sources/shiboken6/ApiExtractor/codesniphelpers.h b/sources/shiboken6/ApiExtractor/codesniphelpers.h
new file mode 100644
index 000000000..e7a7545da
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/codesniphelpers.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CODESNIPHELPERS_H
+#define CODESNIPHELPERS_H
+
+#include <QtCore/QString>
+
+class CodeSnipHelpers
+{
+public:
+ static QString fixSpaces(QString code);
+ static QString dedent(const QString &code);
+ static void prependCode(QString *code, QString firstLine);
+};
+
+#endif // CODESNIPHELPERS_H
diff --git a/sources/shiboken6/ApiExtractor/complextypeentry.h b/sources/shiboken6/ApiExtractor/complextypeentry.h
new file mode 100644
index 000000000..5b884f2cc
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/complextypeentry.h
@@ -0,0 +1,179 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef COMPLEXTYPEENTRY_H
+#define COMPLEXTYPEENTRY_H
+
+#include "configurabletypeentry.h"
+#include "typesystem_enums.h"
+#include "modifications_typedefs.h"
+#include "pymethoddefentry.h"
+
+#include <QtCore/QSet>
+
+class ComplexTypeEntryPrivate;
+
+struct TypeSystemPyMethodDefEntry : public PyMethodDefEntry
+{
+ QStringList signatures;
+};
+
+struct TypeSystemProperty
+{
+ bool isValid() const { return !name.isEmpty() && !read.isEmpty() && !type.isEmpty(); }
+
+ QString type;
+ QString name;
+ QString read;
+ QString write;
+ QString reset;
+ QString designable;
+ QString notify; // Q_PROPERTY/C++ only
+ // Indicates whether actual code is generated instead of relying on libpyside.
+ bool generateGetSetDef = false;
+};
+
+class ComplexTypeEntry : public ConfigurableTypeEntry
+{
+public:
+ enum TypeFlag {
+ DisableWrapper = 0x1,
+ Deprecated = 0x4,
+ ForceAbstract = 0x8,
+ // Indicates that the instances are used to create hierarchies
+ // like widgets; parent ownership heuristics are enabled for them.
+ ParentManagement = 0x10,
+ DisableQtMetaObjectFunctions = 0x20,
+ Typedef = 0x40 // Result of a <typedef-type>
+ };
+ Q_DECLARE_FLAGS(TypeFlags, TypeFlag)
+
+ enum CopyableFlag {
+ CopyableSet,
+ NonCopyableSet,
+ Unknown
+ };
+
+ explicit ComplexTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ bool isComplex() const override;
+
+ TypeFlags typeFlags() const;
+ void setTypeFlags(TypeFlags flags);
+
+ // Override command line options to generate nb_bool from
+ // operator bool or method isNull().
+ TypeSystem::BoolCast operatorBoolMode() const;
+ void setOperatorBoolMode(TypeSystem::BoolCast b);
+ TypeSystem::BoolCast isNullMode() const;
+ void setIsNullMode(TypeSystem::BoolCast b);
+
+ FunctionModificationList functionModifications() const;
+ void setFunctionModifications(const FunctionModificationList &functionModifications);
+ void addFunctionModification(const FunctionModification &functionModification);
+ FunctionModificationList functionModifications(const QStringList &signatures) const;
+
+ const CodeSnipList &codeSnips() const;
+ CodeSnipList &codeSnips();
+ void setCodeSnips(const CodeSnipList &codeSnips);
+ void addCodeSnip(const CodeSnip &codeSnip);
+
+ void setDocModification(const DocModificationList& docMods);
+ /// Class documentation modifications
+ DocModificationList docModifications() const;
+ /// Function documentation modifications (matching signature)
+ DocModificationList functionDocModifications() const;
+
+ /// Extra includes for function arguments determined by the meta builder.
+ const IncludeList &argumentIncludes() const;
+ void addArgumentInclude(const Include &newInclude);
+
+ AddedFunctionList addedFunctions() const;
+ void setAddedFunctions(const AddedFunctionList &addedFunctions);
+ void addNewFunction(const AddedFunctionPtr &addedFunction);
+
+ const QList<TypeSystemPyMethodDefEntry> &addedPyMethodDefEntrys() const;
+ void addPyMethodDef(const TypeSystemPyMethodDefEntry &p);
+
+ // Functions specified in the "generate-functions" attribute
+ const QSet<QString> &generateFunctions() const;
+ void setGenerateFunctions(const QSet<QString> &f);
+
+ void setFieldModifications(const FieldModificationList &mods);
+ FieldModificationList fieldModifications() const;
+
+ const QList<TypeSystemProperty> &properties() const;
+ void addProperty(const TypeSystemProperty &p);
+
+ QString defaultSuperclass() const;
+ void setDefaultSuperclass(const QString &sc);
+
+ QString qualifiedCppName() const override;
+
+ void setIsPolymorphicBase(bool on);
+ bool isPolymorphicBase() const;
+
+ void setPolymorphicIdValue(const QString &value);
+ QString polymorphicIdValue() const;
+
+ QString polymorphicNameFunction() const;
+ void setPolymorphicNameFunction(const QString &n);
+
+ QString targetType() const;
+ void setTargetType(const QString &code);
+
+ bool isGenericClass() const;
+ void setGenericClass(bool isGeneric);
+
+ bool deleteInMainThread() const;
+ void setDeleteInMainThread(bool d);
+
+ CopyableFlag copyable() const;
+ void setCopyable(CopyableFlag flag);
+
+ TypeSystem::QtMetaTypeRegistration qtMetaTypeRegistration() const;
+ void setQtMetaTypeRegistration(TypeSystem::QtMetaTypeRegistration r);
+
+ QString hashFunction() const;
+ void setHashFunction(const QString &hashFunction);
+
+ void setBaseContainerType(const ComplexTypeEntryCPtr &baseContainer);
+
+ ComplexTypeEntryCPtr baseContainerType() const;
+
+ TypeSystem::ExceptionHandling exceptionHandling() const;
+ void setExceptionHandling(TypeSystem::ExceptionHandling e);
+
+ TypeSystem::AllowThread allowThread() const;
+ void setAllowThread(TypeSystem::AllowThread allowThread);
+
+ QString defaultConstructor() const;
+ void setDefaultConstructor(const QString& defaultConstructor);
+ bool hasDefaultConstructor() const;
+
+ TypeEntry *clone() const override;
+
+ void useAsTypedef(const ComplexTypeEntryCPtr &source);
+
+ TypeSystem::SnakeCase snakeCase() const;
+ void setSnakeCase(TypeSystem::SnakeCase sc);
+
+ // Determined by AbstractMetaBuilder from the code model.
+ bool isValueTypeWithCopyConstructorOnly() const;
+ void setValueTypeWithCopyConstructorOnly(bool v);
+
+ // FIXME PYSIDE 7: Remove this
+ static bool isParentManagementEnabled();
+ static void setParentManagementEnabled(bool e);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &debug) const override;
+#endif
+protected:
+ explicit ComplexTypeEntry(ComplexTypeEntryPrivate *d);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(ComplexTypeEntry::TypeFlags)
+
+#endif // COMPLEXTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp b/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp
new file mode 100644
index 000000000..b6eda651c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp
@@ -0,0 +1,211 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "conditionalstreamreader.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QHash>
+
+using namespace Qt::StringLiterals;
+
+// ProxyEntityResolver proxies a QXmlStreamEntityResolver set by the user
+// on ConditionalStreamReader and stores entity definitions from the
+// <?entity name value?> processing instruction in a cache
+// (which is also used for the proxied resolver).
+class ProxyEntityResolver : public QXmlStreamEntityResolver
+{
+public:
+ QString resolveEntity(const QString& publicId,
+ const QString& systemId) override;
+ QString resolveUndeclaredEntity(const QString &name) override;
+
+ QXmlStreamEntityResolver *source() const { return m_source; }
+ void setSource(QXmlStreamEntityResolver *s) { m_source = s; }
+
+ void defineEntity(const QString &name, const QString &value)
+ {
+ m_undeclaredEntityCache.insert(name, value);
+ }
+
+private:
+ QHash<QString, QString> m_undeclaredEntityCache;
+ QXmlStreamEntityResolver *m_source = nullptr;
+};
+
+QString ProxyEntityResolver::resolveEntity(const QString &publicId, const QString &systemId)
+{
+ QString result;
+ if (m_source != nullptr)
+ result = m_source->resolveEntity(publicId, systemId);
+ if (result.isEmpty())
+ result = QXmlStreamEntityResolver::resolveEntity(publicId, systemId);
+ return result;
+}
+
+QString ProxyEntityResolver::resolveUndeclaredEntity(const QString &name)
+{
+ const auto it = m_undeclaredEntityCache.constFind(name);
+ if (it != m_undeclaredEntityCache.constEnd())
+ return it.value();
+ if (m_source == nullptr)
+ return {};
+ const QString result = m_source->resolveUndeclaredEntity(name);
+ if (!result.isEmpty())
+ defineEntity(name, result);
+ return result;
+}
+
+ConditionalStreamReader::ConditionalStreamReader(QIODevice *iod) :
+ m_reader(iod)
+{
+ init();
+}
+
+ConditionalStreamReader::ConditionalStreamReader(const QString &s) :
+ m_reader(s)
+{
+ init();
+}
+
+void ConditionalStreamReader::init()
+{
+ m_proxyEntityResolver = new ProxyEntityResolver;
+ m_reader.setEntityResolver(m_proxyEntityResolver);
+}
+
+ConditionalStreamReader::~ConditionalStreamReader()
+{
+ m_reader.setEntityResolver(nullptr);
+ delete m_proxyEntityResolver;
+}
+
+void ConditionalStreamReader::setEntityResolver(QXmlStreamEntityResolver *resolver)
+{
+ m_proxyEntityResolver->setSource(resolver);
+}
+
+QXmlStreamEntityResolver *ConditionalStreamReader::entityResolver() const
+{
+ return m_proxyEntityResolver->source();
+}
+
+QXmlStreamReader::TokenType ConditionalStreamReader::readNext()
+{
+ auto exToken = readNextInternal();
+
+ if (exToken.second == PiTokens::EntityDefinition)
+ return readEntityDefinitonPi() ? exToken.first : QXmlStreamReader::Invalid;
+
+ if (exToken.second != PiTokens::If || conditionMatches())
+ return exToken.first;
+
+ // Condition does not match - search for endif
+ int nestingLevel = 1;
+ while (true) {
+ exToken = readNextInternal();
+ if (exToken.first == QXmlStreamReader::NoToken
+ || exToken.first == QXmlStreamReader::Invalid
+ || exToken.first == QXmlStreamReader::EndDocument) {
+ break;
+ }
+
+ if (exToken.second == PiTokens::If)
+ ++nestingLevel;
+ else if (exToken.second == PiTokens::Endif && --nestingLevel == 0)
+ break;
+ }
+ return exToken.first;
+}
+
+void ConditionalStreamReader::defineEntity(const QString &name, const QString &value)
+{
+ m_proxyEntityResolver->defineEntity(name, value);
+}
+
+// Read an entity definition: "<?entity name value?>:
+bool ConditionalStreamReader::readEntityDefinitonPi()
+{
+ const auto data = m_reader.processingInstructionData();
+ const auto separator = data.indexOf(u' ');
+ if (separator <= 0 || separator == data.size() - 1) {
+ m_reader.raiseError(u"Malformed entity definition: "_s + data.toString());
+ return false;
+ }
+ defineEntity(data.left(separator).toString(),
+ data.right(data.size() - separator - 1).toString());
+ return true;
+}
+
+bool ConditionalStreamReader::conditionMatches() const
+{
+ const auto keywords = m_reader.processingInstructionData().split(u' ', Qt::SkipEmptyParts);
+ if (keywords.isEmpty())
+ return false;
+
+ bool matches = false;
+ bool exclusionOnly = true;
+ for (const auto &keyword : keywords) {
+ if (keyword.startsWith(u'!')) { // exclusion '!windows' takes preference
+ if (m_conditions.contains(keyword.mid(1)))
+ return false;
+ } else {
+ exclusionOnly = false;
+ matches |= m_conditions.contains(keyword);
+ }
+ }
+ return exclusionOnly || matches;
+}
+
+void ConditionalStreamReader::setConditions(const QStringList &newConditions)
+{
+ m_conditions = newConditions + platformConditions();
+}
+
+QStringList ConditionalStreamReader::platformConditions()
+{
+ QStringList result;
+#if defined (Q_OS_UNIX)
+ result << "unix"_L1;
+#endif
+
+#if defined (Q_OS_LINUX)
+ result << "linux"_L1;
+#elif defined (Q_OS_MACOS)
+ result << "darwin"_L1;
+#elif defined (Q_OS_WINDOWS)
+ result << "windows"_L1;
+#endif
+ return result;
+}
+
+ConditionalStreamReader::ExtendedToken ConditionalStreamReader::readNextInternal()
+{
+ const auto token = m_reader.readNext();
+ PiTokens piToken = PiTokens::None;
+ if (token == QXmlStreamReader::ProcessingInstruction) {
+ const auto target = m_reader.processingInstructionTarget();
+ if (target == u"if")
+ piToken = PiTokens::If;
+ else if (target == u"endif")
+ piToken = PiTokens::Endif;
+ else if (target == u"entity")
+ piToken = PiTokens::EntityDefinition;
+ }
+ return {token, piToken};
+}
+
+QDebug operator<<(QDebug dbg, const QXmlStreamAttributes &attrs)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.noquote();
+ dbg.nospace();
+ dbg << "QXmlStreamAttributes(";
+ for (qsizetype i = 0, size = attrs.size(); i < size; ++i ) {
+ if (i)
+ dbg << ", ";
+ dbg << attrs.at(i).name() << "=\"" << attrs.at(i).value() << '"';
+ }
+ dbg << ')';
+ return dbg;
+}
+
diff --git a/sources/shiboken6/ApiExtractor/conditionalstreamreader.h b/sources/shiboken6/ApiExtractor/conditionalstreamreader.h
new file mode 100644
index 000000000..730697525
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/conditionalstreamreader.h
@@ -0,0 +1,90 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CONDITIONALSTREAMREADER_H
+#define CONDITIONALSTREAMREADER_H
+
+#include <QtCore/QXmlStreamReader>
+
+#include <utility>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class ProxyEntityResolver;
+
+/// ConditionalStreamReader encapsulates QXmlStreamReader, offering the same
+/// API (except readNextStartElement() and similar conveniences) and internally
+/// uses Processing Instructions like:
+/// <?if keyword1 !keyword2?> ... <?endif?>
+/// to exclude/include sections depending on a list of condition keywords,
+/// containing for example the OS.
+/// It should be possible to use it as a drop-in replacement for
+/// QXmlStreamReader for any parsing code based on readNext().
+/// It also allows for specifying entities using a Processing Instruction:
+/// <?entity name value?>
+/// which can be used in conjunction with conditional processing.
+class ConditionalStreamReader
+{
+public:
+ Q_DISABLE_COPY_MOVE(ConditionalStreamReader)
+
+ using TokenType = QXmlStreamReader::TokenType;
+ explicit ConditionalStreamReader(QIODevice *iod);
+ explicit ConditionalStreamReader(const QString &s);
+ ~ConditionalStreamReader();
+
+ QIODevice *device() const { return m_reader.device(); }
+
+ // Note: Caching of entity values is done internally by
+ // ConditionalStreamReader.
+ void setEntityResolver(QXmlStreamEntityResolver *resolver);
+ QXmlStreamEntityResolver *entityResolver() const;
+
+ bool atEnd() const { return m_reader.atEnd(); }
+ TokenType readNext();
+
+ TokenType tokenType() const { return m_reader.tokenType(); }
+
+ qint64 lineNumber() const { return m_reader.lineNumber(); }
+ qint64 columnNumber() const { return m_reader.columnNumber(); }
+
+ QXmlStreamAttributes attributes() const { return m_reader.attributes(); }
+
+ QString readElementText(QXmlStreamReader::ReadElementTextBehaviour behaviour = QXmlStreamReader::ErrorOnUnexpectedElement)
+ { return m_reader.readElementText(behaviour); }
+
+ QStringView name() const { return m_reader.name(); }
+ QStringView qualifiedName() const { return m_reader.qualifiedName(); }
+
+ QStringView text() const { return m_reader.text(); }
+
+ QString errorString() const { return m_reader.errorString(); }
+ QXmlStreamReader::Error error() const { return m_reader.error(); }
+
+ bool hasError() const { return m_reader.hasError(); }
+
+ // Additional functions (not delegating to QXmlStreamReader)
+ void defineEntity(const QString &name, const QString &value);
+
+ const QStringList &conditions() const { return m_conditions; }
+ void setConditions(const QStringList &newConditions);
+
+ static QStringList platformConditions();
+
+private:
+ enum class PiTokens { None, If, Endif, EntityDefinition };
+
+ using ExtendedToken = std::pair<TokenType, PiTokens>;
+ ExtendedToken readNextInternal();
+ void init();
+ bool conditionMatches() const;
+ bool readEntityDefinitonPi();
+
+ QXmlStreamReader m_reader;
+ ProxyEntityResolver *m_proxyEntityResolver = nullptr;
+ QStringList m_conditions = ConditionalStreamReader::platformConditions();
+};
+
+QDebug operator<<(QDebug dbg, const QXmlStreamAttributes &a);
+
+#endif // CONDITIONALSTREAMREADER_H
diff --git a/sources/shiboken6/ApiExtractor/configurabletypeentry.h b/sources/shiboken6/ApiExtractor/configurabletypeentry.h
new file mode 100644
index 000000000..59522e16c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/configurabletypeentry.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CONFIGURABLETYPEENTRY_H
+#define CONFIGURABLETYPEENTRY_H
+
+#include "typesystem.h"
+
+class ConfigurableTypeEntryPrivate;
+
+class ConfigurableTypeEntry : public TypeEntry
+{
+public:
+ explicit ConfigurableTypeEntry(const QString &entryName, Type t,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ TypeEntry *clone() const override;
+
+ QString configCondition() const;
+ void setConfigCondition(const QString &c);
+ bool hasConfigCondition() const;
+
+protected:
+ explicit ConfigurableTypeEntry(ConfigurableTypeEntryPrivate *d);
+};
+
+#endif // CONFIGURABLETYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/constantvaluetypeentry.h b/sources/shiboken6/ApiExtractor/constantvaluetypeentry.h
new file mode 100644
index 000000000..a16a7ad12
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/constantvaluetypeentry.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CONSTANTVALUETYPEENTRY_H
+#define CONSTANTVALUETYPEENTRY_H
+
+#include "typesystem.h"
+
+// For primitive values, typically to provide a dummy type for
+// example the '2' in non-type template 'Array<2>'.
+class ConstantValueTypeEntry : public TypeEntry
+{
+public:
+ explicit ConstantValueTypeEntry(const QString& name,
+ const TypeEntryCPtr &parent);
+
+ TypeEntry *clone() const override;
+
+protected:
+ explicit ConstantValueTypeEntry(TypeEntryPrivate *d);
+};
+
+#endif // CONSTANTVALUETYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/containertypeentry.h b/sources/shiboken6/ApiExtractor/containertypeentry.h
new file mode 100644
index 000000000..b2003816b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/containertypeentry.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CONTAINERTYPEENTRY_H
+#define CONTAINERTYPEENTRY_H
+
+#include "complextypeentry.h"
+#include "customconversion_typedefs.h"
+
+class ContainerTypeEntryPrivate;
+
+struct OpaqueContainer // Generate an opaque container for an instantiation under name
+{
+ QStringList instantiations;
+ QString name;
+
+ QString templateParameters() const;
+};
+
+using OpaqueContainers = QList<OpaqueContainer>;
+
+class ContainerTypeEntry : public ComplexTypeEntry
+{
+public:
+
+ enum ContainerKind {
+ ListContainer,
+ SetContainer,
+ MapContainer,
+ MultiMapContainer,
+ PairContainer,
+ SpanContainer, // Fixed size
+ };
+
+ explicit ContainerTypeEntry(const QString &entryName, ContainerKind containerKind,
+ const QVersionNumber &vr, const TypeEntryCPtr &parent);
+
+ ContainerKind containerKind() const;
+
+ /// Number of template parameters (except allocators)
+ qsizetype templateParameterCount() const;
+
+ const OpaqueContainers &opaqueContainers() const;
+ void appendOpaqueContainers(const OpaqueContainers &l);
+ bool generateOpaqueContainer(const QStringList &instantiations) const;
+ QString opaqueContainerName(const QStringList &instantiations) const;
+
+ bool hasCustomConversion() const;
+ void setCustomConversion(const CustomConversionPtr &customConversion);
+ CustomConversionPtr customConversion() const;
+
+ TypeEntry *clone() const override;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ explicit ContainerTypeEntry(ContainerTypeEntryPrivate *d);
+};
+
+QDebug operator<<(QDebug d, const OpaqueContainer &oc);
+
+#endif // CONTAINERTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/customconversion.cpp b/sources/shiboken6/ApiExtractor/customconversion.cpp
new file mode 100644
index 000000000..4cfd1b974
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/customconversion.cpp
@@ -0,0 +1,197 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "customconversion.h"
+#include "containertypeentry.h"
+#include "customtypenentry.h"
+#include "primitivetypeentry.h"
+#include "valuetypeentry.h"
+
+#include <QtCore/qdebug.h>
+
+using namespace Qt::StringLiterals;
+
+CustomConversion::CustomConversion(const TypeEntryCPtr &ownerType) :
+ m_ownerType(ownerType)
+{
+}
+
+TypeEntryCPtr CustomConversion::ownerType() const
+{
+ return m_ownerType;
+}
+
+QString CustomConversion::nativeToTargetConversion() const
+{
+ return m_nativeToTargetConversion;
+}
+
+void CustomConversion::setNativeToTargetConversion(const QString &nativeToTargetConversion)
+{
+ m_nativeToTargetConversion = nativeToTargetConversion;
+}
+
+bool CustomConversion::replaceOriginalTargetToNativeConversions() const
+{
+ return m_replaceOriginalTargetToNativeConversions;
+}
+
+void CustomConversion::setReplaceOriginalTargetToNativeConversions(bool r)
+{
+ m_replaceOriginalTargetToNativeConversions = r;
+}
+
+bool CustomConversion::hasTargetToNativeConversions() const
+{
+ return !(m_targetToNativeConversions.isEmpty());
+}
+
+TargetToNativeConversions &CustomConversion::targetToNativeConversions()
+{
+ return m_targetToNativeConversions;
+}
+
+const TargetToNativeConversions &CustomConversion::targetToNativeConversions() const
+{
+ return m_targetToNativeConversions;
+}
+
+void CustomConversion::addTargetToNativeConversion(const QString &sourceTypeName,
+ const QString &sourceTypeCheck,
+ const QString &conversion)
+{
+ m_targetToNativeConversions.append(TargetToNativeConversion(sourceTypeName,
+ sourceTypeCheck,
+ conversion));
+}
+
+TargetToNativeConversion::TargetToNativeConversion(const QString &sourceTypeName,
+ const QString &sourceTypeCheck,
+ const QString &conversion) :
+ m_sourceTypeName(sourceTypeName), m_sourceTypeCheck(sourceTypeCheck),
+ m_conversion(conversion)
+{
+}
+
+TypeEntryCPtr TargetToNativeConversion::sourceType() const
+{
+ return m_sourceType;
+}
+
+void TargetToNativeConversion::setSourceType(const TypeEntryCPtr &sourceType)
+{
+ m_sourceType = sourceType;
+}
+
+bool TargetToNativeConversion::isCustomType() const
+{
+ return m_sourceType == nullptr;
+}
+
+QString TargetToNativeConversion::sourceTypeName() const
+{
+ return m_sourceTypeName;
+}
+
+QString TargetToNativeConversion::sourceTypeCheck() const
+{
+ if (!m_sourceTypeCheck.isEmpty())
+ return m_sourceTypeCheck;
+
+ if (m_sourceType != nullptr && m_sourceType->isCustom()) {
+ const auto cte = std::static_pointer_cast<const CustomTypeEntry>(m_sourceType);
+ if (cte->hasCheckFunction()) {
+ QString result = cte->checkFunction();
+ if (result != u"true") // For PyObject, which is always true
+ result += u"(%in)"_s;
+ return result;
+ }
+ }
+
+ return {};
+}
+
+QString TargetToNativeConversion::conversion() const
+{
+ return m_conversion;
+}
+
+void TargetToNativeConversion::setConversion(const QString &conversion)
+{
+ m_conversion = conversion;
+}
+
+void TargetToNativeConversion::formatDebug(QDebug &debug) const
+{
+ debug << "(source=\"" << m_sourceTypeName << '"';
+ if (debug.verbosity() > 2)
+ debug << ", conversion=\"" << m_conversion << '"';
+ if (isCustomType())
+ debug << ", [custom]";
+ debug << ')';
+}
+
+CustomConversionPtr CustomConversion::getCustomConversion(const TypeEntryCPtr &type)
+{
+ if (type->isPrimitive())
+ return std::static_pointer_cast<const PrimitiveTypeEntry>(type)->customConversion();
+ if (type->isContainer())
+ return std::static_pointer_cast<const ContainerTypeEntry>(type)->customConversion();
+ if (type->isValue())
+ return std::static_pointer_cast<const ValueTypeEntry>(type)->customConversion();
+ return {};
+}
+
+void CustomConversion::formatDebug(QDebug &debug) const
+{
+ debug << "(owner=\"" << m_ownerType->qualifiedCppName() << '"';
+ if (!m_nativeToTargetConversion.isEmpty())
+ debug << ", nativeToTargetConversion=\"" << m_nativeToTargetConversion << '"';
+ if (!m_targetToNativeConversions.isEmpty()) {
+ debug << ", targetToNativeConversions=[";
+ for (qsizetype i = 0, size = m_targetToNativeConversions.size(); i < size; ++i) {
+ if (i)
+ debug << ", ";
+ debug << m_targetToNativeConversions.at(i);
+
+ }
+ debug << ']';
+ }
+ if (m_replaceOriginalTargetToNativeConversions)
+ debug << ", [replaceOriginalTargetToNativeConversions]";
+ debug << ')';
+}
+
+QDebug operator<<(QDebug debug, const TargetToNativeConversion &t)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "TargetToNativeConversion";
+ t.formatDebug(debug);
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const CustomConversion &c)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "CustomConversion";
+ c.formatDebug(debug);
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const CustomConversionPtr &cptr)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "CustomConversionPtr";
+ if (auto *c = cptr.get()) {
+ c->formatDebug(debug);
+ } else {
+ debug << "(0)";
+ }
+ return debug;
+}
diff --git a/sources/shiboken6/ApiExtractor/customconversion.h b/sources/shiboken6/ApiExtractor/customconversion.h
new file mode 100644
index 000000000..fd0a67759
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/customconversion.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CUSTOMCONVERSION_H
+#define CUSTOMCONVERSION_H
+
+#include "customconversion_typedefs.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class TypeEntry;
+
+class TargetToNativeConversion
+{
+public:
+ explicit TargetToNativeConversion(const QString &sourceTypeName,
+ const QString &sourceTypeCheck,
+ const QString &conversion = {});
+
+ TypeEntryCPtr sourceType() const;
+ void setSourceType(const TypeEntryCPtr &sourceType);
+ bool isCustomType() const;
+ QString sourceTypeName() const;
+ QString sourceTypeCheck() const;
+ QString conversion() const;
+ void setConversion(const QString &conversion);
+
+ void formatDebug(QDebug &d) const;
+
+private:
+ TypeEntryCPtr m_sourceType;
+ QString m_sourceTypeName;
+ QString m_sourceTypeCheck;
+ QString m_conversion;
+};
+
+using TargetToNativeConversions = QList<TargetToNativeConversion>;
+
+class CustomConversion
+{
+public:
+ explicit CustomConversion(const TypeEntryCPtr &ownerType);
+
+ TypeEntryCPtr ownerType() const;
+ QString nativeToTargetConversion() const;
+ void setNativeToTargetConversion(const QString &nativeToTargetConversion);
+
+ /// Returns true if the target to C++ custom conversions should
+ /// replace the original existing ones, and false if the custom
+ /// conversions should be added to the original.
+ bool replaceOriginalTargetToNativeConversions() const;
+ void setReplaceOriginalTargetToNativeConversions(bool r);
+
+ bool hasTargetToNativeConversions() const;
+ TargetToNativeConversions &targetToNativeConversions();
+ const TargetToNativeConversions &targetToNativeConversions() const;
+ void addTargetToNativeConversion(const QString &sourceTypeName,
+ const QString &sourceTypeCheck,
+ const QString &conversion = QString());
+
+ /// Return the custom conversion of a type; helper for type system parser
+ static CustomConversionPtr getCustomConversion(const TypeEntryCPtr &type);
+
+ void formatDebug(QDebug &debug) const;
+
+private:
+ TypeEntryCPtr m_ownerType;
+ QString m_nativeToTargetConversion;
+ TargetToNativeConversions m_targetToNativeConversions;
+ bool m_replaceOriginalTargetToNativeConversions = false;
+};
+
+QDebug operator<<(QDebug debug, const TargetToNativeConversion &t);
+QDebug operator<<(QDebug debug, const CustomConversion &c);
+QDebug operator<<(QDebug debug, const CustomConversionPtr &cptr);
+
+#endif // CUSTOMCONVERSION_H
diff --git a/sources/shiboken6/ApiExtractor/customconversion_typedefs.h b/sources/shiboken6/ApiExtractor/customconversion_typedefs.h
new file mode 100644
index 000000000..6528f7d7b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/customconversion_typedefs.h
@@ -0,0 +1,14 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CUSTOMCONVERSION_TYPEDEFS_H
+#define CUSTOMCONVERSION_TYPEDEFS_H
+
+#include <QtCore/QList>
+
+#include <memory>
+
+class CustomConversion;
+using CustomConversionPtr = std::shared_ptr<CustomConversion>;
+
+#endif // CUSTOMCONVERSION_TYPEDEFS_H
diff --git a/sources/shiboken6/ApiExtractor/customtypenentry.h b/sources/shiboken6/ApiExtractor/customtypenentry.h
new file mode 100644
index 000000000..a57bb858f
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/customtypenentry.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CUSTOMTYPENENTRY_H
+#define CUSTOMTYPENENTRY_H
+
+#include "typesystem.h"
+
+class CustomTypeEntry : public TypeEntry
+{
+public:
+ explicit CustomTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ TypeEntry *clone() const override;
+
+ bool hasCheckFunction() const;
+ QString checkFunction() const;
+ void setCheckFunction(const QString &f);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+protected:
+ explicit CustomTypeEntry(TypeEntryPrivate *d);
+};
+
+
+#endif // CUSTOMTYPENENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/debughelpers_p.h b/sources/shiboken6/ApiExtractor/debughelpers_p.h
new file mode 100644
index 000000000..81ebbb3b9
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/debughelpers_p.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DEBUGHELPERS_P_H
+#define DEBUGHELPERS_P_H
+
+#include <QtCore/QDebug>
+#include <memory>
+
+template <class T>
+inline QDebug operator<<(QDebug debug, const std::shared_ptr<T> &ptr)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "std::shared_ptr(" << ptr.get() << ")";
+ return debug;
+}
+
+template <class It>
+inline void formatSequence(QDebug &d, It i1, It i2,
+ const char *separator=", ")
+{
+ for (It i = i1; i != i2; ++i) {
+ if (i != i1)
+ d << separator;
+ d << *i;
+ }
+}
+
+template <class It>
+inline static void formatPtrSequence(QDebug &d, It i1, It i2,
+ const char *separator=", ")
+{
+ for (It i = i1; i != i2; ++i) {
+ if (i != i1)
+ d << separator;
+ d << i->get();
+ }
+}
+
+template <class Container>
+static void formatList(QDebug &d, const char *name, const Container &c,
+ const char *separator=", ")
+{
+ if (const auto size = c.size()) {
+ d << ", " << name << '[' << size << "]=(";
+ for (qsizetype i = 0; i < size; ++i) {
+ if (i)
+ d << separator;
+ d << c.at(i);
+ }
+ d << ')';
+ }
+}
+
+#endif // DEBUGHELPERS_P_H
diff --git a/sources/shiboken6/ApiExtractor/dependency.h b/sources/shiboken6/ApiExtractor/dependency.h
new file mode 100644
index 000000000..aa280de03
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/dependency.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DEPENDENCY_H
+#define DEPENDENCY_H
+
+#include <QtCore/QList>
+
+#include <utility>
+
+// Dependencies for topologically sorting classes
+
+class AbstractMetaClass;
+
+struct Dependency {
+ AbstractMetaClassPtr parent;
+ AbstractMetaClassPtr child;
+};
+
+using Dependencies = QList<Dependency>;
+
+#endif // DEPENDENCY_H
diff --git a/sources/shiboken6/ApiExtractor/docparser.cpp b/sources/shiboken6/ApiExtractor/docparser.cpp
new file mode 100644
index 000000000..468fe1098
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/docparser.cpp
@@ -0,0 +1,232 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "docparser.h"
+#include "abstractmetaargument.h"
+#include "abstractmetaenum.h"
+#include "abstractmetafunction.h"
+#include "abstractmetalang.h"
+#include "abstractmetatype.h"
+#include "messages.h"
+#include "modifications.h"
+#include "reporthandler.h"
+#include "enumtypeentry.h"
+#include "complextypeentry.h"
+#include "xmlutils.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+
+#include "qtcompat.h"
+
+#include <cstdlib>
+#ifdef HAVE_LIBXSLT
+# include <libxslt/xsltutils.h>
+# include <libxslt/transform.h>
+#endif
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+static inline bool isXpathDocModification(const DocModification &mod)
+{
+ return mod.mode() == TypeSystem::DocModificationXPathReplace;
+}
+
+static inline bool isNotXpathDocModification(const DocModification &mod)
+{
+ return mod.mode() != TypeSystem::DocModificationXPathReplace;
+}
+
+static void removeXpathDocModifications(DocModificationList *l)
+{
+ l->erase(std::remove_if(l->begin(), l->end(), isXpathDocModification), l->end());
+}
+
+static void removeNonXpathDocModifications(DocModificationList *l)
+{
+ l->erase(std::remove_if(l->begin(), l->end(), isNotXpathDocModification), l->end());
+}
+
+DocParser::DocParser() = default;
+DocParser::~DocParser() = default;
+
+void DocParser::fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &)
+{
+}
+
+void DocParser::fillGlobalEnumDocumentation(AbstractMetaEnum &)
+{
+}
+
+QString DocParser::getDocumentation(const XQueryPtr &xquery, const QString& query,
+ const DocModificationList& mods)
+{
+ QString doc = execXQuery(xquery, query);
+ return applyDocModifications(mods, doc.trimmed());
+}
+
+QString DocParser::execXQuery(const XQueryPtr &xquery, const QString& query)
+{
+ QString errorMessage;
+ const QString result = xquery->evaluate(query, &errorMessage);
+ if (!errorMessage.isEmpty())
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ return result;
+}
+
+static bool usesRValueReference(const AbstractMetaArgument &a)
+{
+ return a.type().referenceType() == RValueReference;
+}
+
+bool DocParser::skipForQuery(const AbstractMetaFunctionCPtr &func)
+{
+ // Skip private functions and copies created by AbstractMetaClass::fixFunctions()
+ // Note: Functions inherited from templates will cause warnings about missing
+ // documentation, but they should at least be listed.
+ if (!func || func->isPrivate()
+ || func->attributes().testFlag(AbstractMetaFunction::AddedMethod)
+ || func->isModifiedRemoved()
+ || func->declaringClass() != func->ownerClass()
+ || func->isConversionOperator()) {
+ return true;
+ }
+ switch (func->functionType()) {
+ case AbstractMetaFunction::MoveConstructorFunction:
+ case AbstractMetaFunction::AssignmentOperatorFunction:
+ case AbstractMetaFunction::MoveAssignmentOperatorFunction:
+ return true;
+ default:
+ break;
+ }
+
+ return std::any_of(func->arguments().cbegin(), func->arguments().cend(),
+ usesRValueReference);
+}
+
+DocModificationList DocParser::getDocModifications(const AbstractMetaClassCPtr &cppClass)
+
+{
+ auto result = cppClass->typeEntry()->docModifications();
+ removeXpathDocModifications(&result);
+ return result;
+}
+
+static void filterBySignature(const AbstractMetaFunctionCPtr &func, DocModificationList *l)
+{
+ if (!l->isEmpty()) {
+ const QString minimalSignature = func->minimalSignature();
+ const auto filter = [&minimalSignature](const DocModification &mod) {
+ return mod.signature() != minimalSignature;
+ };
+ l->erase(std::remove_if(l->begin(), l->end(), filter), l->end());
+ }
+}
+
+DocModificationList DocParser::getDocModifications(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaClassCPtr &cppClass)
+{
+ DocModificationList result;
+ if (func->isUserAdded()) {
+ result = func->addedFunctionDocModifications();
+ removeXpathDocModifications(&result);
+ } else if (cppClass != nullptr) {
+ result = cppClass->typeEntry()->functionDocModifications();
+ removeXpathDocModifications(&result);
+ filterBySignature(func, &result);
+ }
+ return result;
+}
+
+DocModificationList DocParser::getXpathDocModifications(const AbstractMetaClassCPtr &cppClass)
+{
+ auto result = cppClass->typeEntry()->docModifications();
+ removeNonXpathDocModifications(&result);
+ return result;
+}
+
+DocModificationList DocParser::getXpathDocModifications(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaClassCPtr &cppClass)
+{
+ DocModificationList result;
+ if (func->isUserAdded()) {
+ result = func->addedFunctionDocModifications();
+ removeNonXpathDocModifications(&result);
+ } else if (cppClass != nullptr) {
+ result = cppClass->typeEntry()->functionDocModifications();
+ removeNonXpathDocModifications(&result);
+ filterBySignature(func, &result);
+ }
+ return result;
+}
+
+QString DocParser::enumBaseClass(const AbstractMetaEnum &e)
+{
+ switch (e.typeEntry()->pythonEnumType()) {
+ case TypeSystem::PythonEnumType::IntEnum:
+ return u"IntEnum"_s;
+ case TypeSystem::PythonEnumType::Flag:
+ return u"Flag"_s;
+ case TypeSystem::PythonEnumType::IntFlag:
+ return u"IntFlag"_s;
+ default:
+ break;
+ }
+ return e.typeEntry()->flags() != nullptr ? u"Flag"_s : u"Enum"_s;
+}
+
+AbstractMetaFunctionCList DocParser::documentableFunctions(const AbstractMetaClassCPtr &metaClass)
+{
+ auto result = metaClass->functionsInTargetLang();
+ for (auto i = result.size() - 1; i >= 0; --i) {
+ if (DocParser::skipForQuery(result.at(i)) || result.at(i)->isUserAdded())
+ result.removeAt(i);
+ }
+ result.append(metaClass->cppSignalFunctions());
+ return result;
+}
+
+QString DocParser::applyDocModifications(const DocModificationList& xpathMods,
+ const QString& xml)
+{
+ const char xslPrefix[] =
+R"(<xsl:template match="/">
+ <xsl:apply-templates />
+</xsl:template>
+<xsl:template match="*">
+<xsl:copy>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates/>
+</xsl:copy>
+</xsl:template>
+)";
+
+ if (xpathMods.isEmpty() || xml.isEmpty())
+ return xml;
+
+ QString xsl = QLatin1StringView(xslPrefix);
+ for (const DocModification &mod : xpathMods) {
+ Q_ASSERT(isXpathDocModification(mod));
+ QString xpath = mod.xpath();
+ xpath.replace(u'"', u"&quot;"_s);
+ xsl += "<xsl:template match=\""_L1 + xpath + "\">"_L1
+ + mod.code() + "</xsl:template>\n"_L1;
+ }
+
+ QString errorMessage;
+ const QString result = xsl_transform(xml, xsl, &errorMessage);
+ if (!errorMessage.isEmpty())
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgXpathDocModificationError(xpathMods, errorMessage)));
+ if (result == xml) {
+ const QString message = u"Query did not result in any modifications to \""_s
+ + xml + u'"';
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgXpathDocModificationError(xpathMods, message)));
+ }
+ return result;
+}
diff --git a/sources/shiboken6/ApiExtractor/docparser.h b/sources/shiboken6/ApiExtractor/docparser.h
new file mode 100644
index 000000000..6d458b25a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/docparser.h
@@ -0,0 +1,125 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#ifndef DOCPARSER_H
+#define DOCPARSER_H
+
+#include "abstractmetalang_typedefs.h"
+#include "modifications_typedefs.h"
+
+#include <QtCore/QString>
+
+#include <memory>
+
+class AbstractMetaClass;
+class DocModification;
+class Documentation;
+
+class XQuery;
+
+struct FunctionDocumentation;
+
+class DocParser
+{
+public:
+ Q_DISABLE_COPY_MOVE(DocParser)
+
+ using XQueryPtr = std::shared_ptr<XQuery>;
+
+ DocParser();
+ virtual ~DocParser();
+ virtual void fillDocumentation(const AbstractMetaClassPtr &metaClass) = 0;
+ virtual void fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f);
+ virtual void fillGlobalEnumDocumentation(AbstractMetaEnum &e);
+
+ /**
+ * Process and retrieves documentation concerning the entire
+ * module or library.
+ * \return object containing module/library documentation information
+ */
+ virtual Documentation retrieveModuleDocumentation() = 0;
+
+ void setDocumentationDataDirectory(const QString& dir)
+ {
+ m_docDataDir = dir;
+ }
+
+ /**
+ * Informs the location of the XML data generated by the tool
+ * (e.g.: DoxyGen, qdoc) used to extract the library's documentation
+ * comment.
+ * \return the path for the directory containing the XML data created
+ * from the library's documentation beign parsed.
+ */
+ QString documentationDataDirectory() const
+ {
+ return m_docDataDir;
+ }
+
+ void setLibrarySourceDirectory(const QString& dir)
+ {
+ m_libSourceDir = dir;
+ }
+ /**
+ * Informs the location of the library being parsed. The library
+ * source code is parsed for the documentation comments.
+ * \return the path for the directory containing the source code of
+ * the library beign parsed.
+ */
+ QString librarySourceDirectory() const
+ {
+ return m_libSourceDir;
+ }
+
+ void setPackageName(const QString& packageName)
+ {
+ m_packageName = packageName;
+ }
+ /**
+ * Retrieves the name of the package (or module or library) being parsed.
+ * \return the name of the package (module/library) being parsed
+ */
+ QString packageName() const
+ {
+ return m_packageName;
+ }
+
+ /**
+ * Process and retrieves documentation concerning the entire
+ * module or library.
+ * \param name module name
+ * \return object containing module/library documentation information
+ * \todo Merge with retrieveModuleDocumentation() on next ABI change.
+ */
+ virtual Documentation retrieveModuleDocumentation(const QString& name) = 0;
+
+ static bool skipForQuery(const AbstractMetaFunctionCPtr &func);
+
+ /// Helper to return the documentation modifications for a class
+ /// or a member function.
+ static DocModificationList getDocModifications(const AbstractMetaClassCPtr &cppClass);
+ static DocModificationList getDocModifications(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaClassCPtr &cppClass = {});
+ static DocModificationList getXpathDocModifications(const AbstractMetaClassCPtr &cppClass);
+ static DocModificationList getXpathDocModifications(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaClassCPtr &cppClass = {});
+
+ static QString enumBaseClass(const AbstractMetaEnum &e);
+
+protected:
+ static QString getDocumentation(const XQueryPtr &xquery,
+ const QString &query,
+ const DocModificationList &mods);
+
+ static AbstractMetaFunctionCList documentableFunctions(const AbstractMetaClassCPtr &metaClass);
+
+ static QString applyDocModifications(const DocModificationList &xpathMods, const QString &xml);
+
+private:
+ QString m_packageName;
+ QString m_docDataDir;
+ QString m_libSourceDir;
+
+ static QString execXQuery(const XQueryPtr &xquery, const QString &query) ;
+};
+
+#endif // DOCPARSER_H
diff --git a/sources/shiboken6/ApiExtractor/documentation.cpp b/sources/shiboken6/ApiExtractor/documentation.cpp
new file mode 100644
index 000000000..33cf0e9fb
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/documentation.cpp
@@ -0,0 +1,65 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "documentation.h"
+
+#include <QtCore/QDebug>
+
+Documentation::Documentation(const QString &detailed,
+ const QString &brief,
+ Format fmt) :
+ m_detailed(detailed.trimmed()), m_brief(brief.trimmed()), m_format(fmt)
+{
+}
+
+bool Documentation::isEmpty() const
+{
+ return m_detailed.isEmpty() && m_brief.isEmpty();
+}
+
+Documentation::Format Documentation::format() const
+{
+ return m_format;
+}
+
+void Documentation::setValue(const QString &value, Documentation::Type t)
+{
+ if (t == Brief)
+ setBrief(value);
+ else
+ setDetailed(value);
+}
+
+void Documentation::setFormat(Documentation::Format f)
+{
+ m_format = f;
+}
+
+void Documentation::setDetailed(const QString &detailed)
+{
+ m_detailed = detailed.trimmed();
+}
+
+void Documentation::setBrief(const QString &brief)
+{
+ m_brief = brief.trimmed();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const Documentation &d)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Documentation(";
+ if (!d.isEmpty()) {
+ debug << "format=" << d.format();
+ if (!d.brief().isEmpty())
+ debug << ", brief=\"" << d.brief() << '"';
+ if (!d.detailed().isEmpty())
+ debug << ", detailed=\"" << d.detailed() << '"';
+ }
+ debug << ')';
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/documentation.h b/sources/shiboken6/ApiExtractor/documentation.h
new file mode 100644
index 000000000..df9d5d614
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/documentation.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DOCUMENTATION_H
+#define DOCUMENTATION_H
+
+#include <QtCore/QString>
+#include <QtCore/QtCompare>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class Documentation
+{
+public:
+ enum Format {
+ Native, // XML
+ Target // RST
+ };
+
+ enum Type {
+ Detailed,
+ Brief,
+ Last
+ };
+
+ Documentation() = default;
+ explicit Documentation(const QString &detailed,
+ const QString &brief,
+ Format fmt = Documentation::Native);
+
+ bool isEmpty() const;
+
+ void setValue(const QString& value, Type t = Documentation::Detailed);
+
+ Documentation::Format format() const;
+ void setFormat(Format f);
+
+ bool equals(const Documentation &rhs) const;
+
+ const QString &detailed() const { return m_detailed; }
+ void setDetailed(const QString &detailed);
+
+ bool hasBrief() const { return !m_brief.isEmpty(); }
+ const QString &brief() const { return m_brief; }
+ void setBrief(const QString &brief);
+
+private:
+ friend bool comparesEqual(const Documentation &lhs,
+ const Documentation &rhs) noexcept
+ {
+ return lhs.m_format == rhs.m_format && lhs.m_detailed == rhs.m_detailed
+ && lhs.m_brief == rhs.m_brief;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(Documentation)
+
+ QString m_detailed;
+ QString m_brief;
+ Format m_format = Documentation::Native;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const Documentation &);
+#endif
+
+#endif // DOCUMENTATION_H
diff --git a/sources/shiboken6/ApiExtractor/dotview.cpp b/sources/shiboken6/ApiExtractor/dotview.cpp
new file mode 100644
index 000000000..0bd192257
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/dotview.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "dotview.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QProcess>
+#include <QtCore/QTemporaryFile>
+
+using namespace Qt::StringLiterals;
+
+bool showDotGraph(const QString &name, const QString &graph)
+{
+ constexpr auto imageType = "jpg"_L1;
+
+ // Write out the graph to a temporary file
+ QTemporaryFile dotFile(QDir::tempPath() + u'/' + name + u"_XXXXXX.dot"_s);
+ if (!dotFile.open()) {
+ qWarning("Cannot open temporary file: %s", qPrintable(dotFile.errorString()));
+ return false;
+ }
+ const QString tempDotFile = dotFile.fileName();
+ dotFile.write(graph.toUtf8());
+ dotFile.close();
+
+ // Convert to image using "dot"
+ const QString imageFile = tempDotFile.left(tempDotFile.size() - 3) + imageType;
+ QProcess process;
+ process.start(u"dot"_s, {u"-T"_s + imageType, u"-o"_s + imageFile, tempDotFile});
+ if (!process.waitForStarted() || !process.waitForFinished()) {
+ qWarning("Image conversion failed: %s", qPrintable(process.errorString()));
+ return false;
+ }
+ if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) {
+ qWarning("Image conversion failed (%d): %s",
+ process.exitCode(),
+ process.readAllStandardError().constData());
+ return false;
+ }
+
+ // Launch image. Should use QDesktopServices::openUrl(),
+ // but we don't link against QtGui
+#ifdef Q_OS_UNIX
+ constexpr auto imageViewer = "gwenview"_L1;
+#else
+ constexpr auto imageViewer = "mspaint"_L1;
+#endif
+ if (!QProcess::startDetached(imageViewer, {imageFile})) {
+ qWarning("Failed to launch viewer: %s", qPrintable(imageViewer));
+ return false;
+ }
+ qInfo().noquote().nospace() << "Viewing: "
+ << QDir::toNativeSeparators(tempDotFile)
+ << ' ' << QDir::toNativeSeparators(imageFile);
+ return true;
+}
diff --git a/sources/shiboken6/ApiExtractor/dotview.h b/sources/shiboken6/ApiExtractor/dotview.h
new file mode 100644
index 000000000..87fb7db65
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/dotview.h
@@ -0,0 +1,14 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DOTVIEW_H
+#define DOTVIEW_H
+
+#include <QtCore/QString>
+
+/// Show a dot digraph in an image viewer
+/// \param name base name for files
+/// \param graph graph
+bool showDotGraph(const QString &name, const QString &graph);
+
+#endif // DOTVIEW_H
diff --git a/sources/shiboken6/ApiExtractor/doxygenparser.cpp b/sources/shiboken6/ApiExtractor/doxygenparser.cpp
new file mode 100644
index 000000000..da790015f
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/doxygenparser.cpp
@@ -0,0 +1,224 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "doxygenparser.h"
+#include "abstractmetaargument.h"
+#include "abstractmetalang.h"
+#include "abstractmetafield.h"
+#include "abstractmetafunction.h"
+#include "abstractmetaenum.h"
+#include "abstractmetatype.h"
+#include "documentation.h"
+#include "messages.h"
+#include "modifications.h"
+#include "propertyspec.h"
+#include "reporthandler.h"
+#include "complextypeentry.h"
+#include "xmlutils.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+
+using namespace Qt::StringLiterals;
+
+static QString getSectionKindAttr(const AbstractMetaFunctionCPtr &func)
+{
+ if (func->isSignal())
+ return u"signal"_s;
+ QString kind = func->isPublic()
+ ? u"public"_s : u"protected"_s;
+ if (func->isStatic())
+ kind += u"-static"_s;
+ else if (func->isSlot())
+ kind += u"-slot"_s;
+ return kind;
+}
+
+Documentation DoxygenParser::retrieveModuleDocumentation()
+{
+ return retrieveModuleDocumentation(packageName());
+}
+
+void DoxygenParser::fillDocumentation(const AbstractMetaClassPtr &metaClass)
+{
+ if (!metaClass)
+ return;
+
+ QString doxyFileSuffix;
+ if (metaClass->enclosingClass()) {
+ doxyFileSuffix += metaClass->enclosingClass()->name();
+ doxyFileSuffix += u"_1_1"_s; // FIXME: Check why _1_1!!
+ }
+ doxyFileSuffix += metaClass->name();
+ doxyFileSuffix += u".xml"_s;
+
+ static constexpr QLatin1StringView prefixes[] = { "class"_L1, "struct"_L1, "namespace"_L1 };
+ bool isProperty = false;
+
+ QString doxyFilePath;
+ for (const auto &prefix : prefixes) {
+ doxyFilePath = documentationDataDirectory() + u'/' + prefix + doxyFileSuffix;
+ if (QFile::exists(doxyFilePath))
+ break;
+ doxyFilePath.clear();
+ }
+
+ if (doxyFilePath.isEmpty()) {
+ qCWarning(lcShibokenDoc).noquote().nospace()
+ << "Can't find doxygen file for class " << metaClass->name() << ", tried: "
+ << QDir::toNativeSeparators(documentationDataDirectory())
+ << "/{struct|class|namespace}"<< doxyFileSuffix;
+ return;
+ }
+
+ QString errorMessage;
+ XQueryPtr xquery = XQuery::create(doxyFilePath, &errorMessage);
+ if (!xquery) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ return;
+ }
+
+ static const QList<std::pair<Documentation::Type, QString>> docTags = {
+ { Documentation::Brief, u"briefdescription"_s },
+ { Documentation::Detailed, u"detaileddescription"_s }
+ };
+ // Get class documentation
+ Documentation classDoc;
+
+ for (const auto &tag : docTags) {
+ const QString classQuery = u"/doxygen/compounddef/"_s + tag.second;
+ QString doc = getDocumentation(xquery, classQuery,
+ metaClass->typeEntry()->docModifications());
+ if (doc.isEmpty())
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(doxyFilePath, "class", metaClass->name(),
+ classQuery)));
+ else
+ classDoc.setValue(doc, tag.first);
+ }
+ metaClass->setDocumentation(classDoc);
+
+ //Functions Documentation
+ const auto &funcs = DocParser::documentableFunctions(metaClass);
+ for (const auto &func : funcs) {
+ QString query = u"/doxygen/compounddef/sectiondef"_s;
+ // properties
+ if (func->isPropertyReader() || func->isPropertyWriter()
+ || func->isPropertyResetter()) {
+ const auto prop = metaClass->propertySpecs().at(func->propertySpecIndex());
+ query += u"[@kind=\"property\"]/memberdef/name[text()=\""_s
+ + prop.name() + u"\"]"_s;
+ isProperty = true;
+ } else { // normal methods
+ QString kind = getSectionKindAttr(func);
+ query += u"[@kind=\""_s + kind
+ + u"-func\"]/memberdef/name[text()=\""_s
+ + func->originalName() + u"\"]"_s;
+
+ if (func->arguments().isEmpty()) {
+ QString args = func->isConstant() ? u"() const"_s : u"()"_s;
+ query += u"/../argsstring[text()=\""_s + args + u"\"]"_s;
+ } else {
+ int i = 1;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument &arg : arguments) {
+ if (!arg.type().isPrimitive()) {
+ query += u"/../param["_s + QString::number(i)
+ + u"]/type/ref[text()=\""_s
+ + arg.type().cppSignature().toHtmlEscaped()
+ + u"\"]/../.."_s;
+ } else {
+ query += u"/../param["_s + QString::number(i)
+ + u"]/type[text(), \""_s
+ + arg.type().cppSignature().toHtmlEscaped()
+ + u"\"]/.."_s;
+ }
+ ++i;
+ }
+ }
+ }
+ Documentation funcDoc;
+ for (const auto &tag : docTags) {
+ QString funcQuery(query);
+ if (!isProperty) {
+ funcQuery += u"/../"_s + tag.second;
+ } else {
+ funcQuery = u'(' + funcQuery;
+ funcQuery += u"/../"_s + tag.second + u")[1]"_s;
+ }
+
+ QString doc = getDocumentation(xquery, funcQuery,
+ DocParser::getXpathDocModifications(func, metaClass));
+ if (doc.isEmpty()) {
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(doxyFilePath, func.get(),
+ funcQuery)));
+ } else {
+ funcDoc.setValue(doc, tag.first);
+ }
+ }
+ std::const_pointer_cast<AbstractMetaFunction>(func)->setDocumentation(funcDoc);
+ isProperty = false;
+ }
+
+ //Fields
+ for (AbstractMetaField &field : metaClass->fields()) {
+ if (field.isPrivate())
+ return;
+
+ Documentation fieldDoc;
+ for (const auto &tag : docTags) {
+ QString query = u"/doxygen/compounddef/sectiondef/memberdef/name[text()=\""_s
+ + field.name() + u"\"]/../"_s + tag.second;
+ QString doc = getDocumentation(xquery, query, DocModificationList());
+ if (doc.isEmpty()) {
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(doxyFilePath, metaClass, field,
+ query)));
+ } else {
+ fieldDoc.setValue(doc, tag.first);
+ }
+ }
+ field.setDocumentation(fieldDoc);
+ }
+
+ //Enums
+ for (AbstractMetaEnum &meta_enum : metaClass->enums()) {
+ QString query = u"/doxygen/compounddef/sectiondef/memberdef[@kind=\"enum\"]/name[text()=\""_s
+ + meta_enum.name() + u"\"]/.."_s;
+ QString doc = getDocumentation(xquery, query, DocModificationList());
+ if (doc.isEmpty()) {
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(doxyFilePath, metaClass, meta_enum, query)));
+ }
+ meta_enum.setDocumentation(Documentation(doc, {}));
+ }
+
+}
+
+Documentation DoxygenParser::retrieveModuleDocumentation(const QString& name){
+
+ QString sourceFile = documentationDataDirectory() + u"/indexpage.xml"_s;
+
+ if (!QFile::exists(sourceFile)) {
+ qCWarning(lcShibokenDoc).noquote().nospace()
+ << "Can't find doxygen XML file for module " << name << ", tried: "
+ << QDir::toNativeSeparators(sourceFile);
+ return {};
+ }
+
+ QString errorMessage;
+ XQueryPtr xquery = XQuery::create(sourceFile, &errorMessage);
+ if (!xquery) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ return {};
+ }
+
+ // Module documentation
+ QString query = u"/doxygen/compounddef/detaileddescription"_s;
+ const QString doc = getDocumentation(xquery, query, DocModificationList());
+ return Documentation(doc, {});
+}
+
diff --git a/sources/shiboken6/ApiExtractor/doxygenparser.h b/sources/shiboken6/ApiExtractor/doxygenparser.h
new file mode 100644
index 000000000..4f6a9e53c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/doxygenparser.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DOXYGENPARSER_H
+#define DOXYGENPARSER_H
+
+#include "docparser.h"
+
+class DoxygenParser : public DocParser
+{
+public:
+ DoxygenParser() = default;
+ void fillDocumentation(const AbstractMetaClassPtr &metaClass) override;
+ Documentation retrieveModuleDocumentation() override;
+ Documentation retrieveModuleDocumentation(const QString& name) override;
+};
+
+#endif // DOXYGENPARSER_H
diff --git a/sources/shiboken6/ApiExtractor/enclosingclassmixin.cpp b/sources/shiboken6/ApiExtractor/enclosingclassmixin.cpp
new file mode 100644
index 000000000..2421ae527
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/enclosingclassmixin.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "enclosingclassmixin.h"
+#include "abstractmetalang.h"
+#include "namespacetypeentry.h"
+
+AbstractMetaClassCPtr EnclosingClassMixin::targetLangEnclosingClass() const
+{
+ auto result = m_enclosingClass.lock();
+ while (result && !NamespaceTypeEntry::isVisibleScope(result->typeEntry()))
+ result = result->enclosingClass();
+ return result;
+}
diff --git a/sources/shiboken6/ApiExtractor/enclosingclassmixin.h b/sources/shiboken6/ApiExtractor/enclosingclassmixin.h
new file mode 100644
index 000000000..8d735d5ec
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/enclosingclassmixin.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ENCLOSINGCLASSMIXIN_H
+#define ENCLOSINGCLASSMIXIN_H
+
+#include "abstractmetalang_typedefs.h"
+
+class AbstractMetaClass;
+
+class EnclosingClassMixin {
+public:
+
+ const AbstractMetaClassCPtr enclosingClass() const
+ { return m_enclosingClass.lock(); }
+ void setEnclosingClass(const AbstractMetaClassCPtr &cls)
+ { m_enclosingClass = cls; }
+ AbstractMetaClassCPtr targetLangEnclosingClass() const;
+
+private:
+ std::weak_ptr<const AbstractMetaClass> m_enclosingClass;
+};
+
+#endif // ENCLOSINGCLASSMIXIN_H
diff --git a/sources/shiboken6/ApiExtractor/enumtypeentry.h b/sources/shiboken6/ApiExtractor/enumtypeentry.h
new file mode 100644
index 000000000..3360d7db5
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/enumtypeentry.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ENUMTYPEENTRY_H
+#define ENUMTYPEENTRY_H
+
+#include "configurabletypeentry.h"
+#include "typesystem_enums.h"
+
+class EnumTypeEntryPrivate;
+
+// EnumTypeEntry is configurable for global enums only
+class EnumTypeEntry : public ConfigurableTypeEntry
+{
+public:
+ explicit EnumTypeEntry(const QString &entryName,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ TypeSystem::PythonEnumType pythonEnumType() const;
+ void setPythonEnumType(TypeSystem::PythonEnumType t);
+
+ QString targetLangQualifier() const;
+
+ QString qualifier() const;
+
+ EnumValueTypeEntryCPtr nullValue() const;
+ void setNullValue(const EnumValueTypeEntryCPtr &n);
+
+ void setFlags(const FlagsTypeEntryPtr &flags);
+ FlagsTypeEntryPtr flags() const;
+
+ QString cppType() const;
+ void setCppType(const QString &t);
+
+ bool isEnumValueRejected(const QString &name) const;
+ void addEnumValueRejection(const QString &name);
+ QStringList enumValueRejections() const;
+
+ QString docFile() const;
+ void setDocFile(const QString &df);
+
+ TypeEntry *clone() const override;
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ explicit EnumTypeEntry(EnumTypeEntryPrivate *d);
+};
+
+#endif // ENUMTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/enumvaluetypeentry.h b/sources/shiboken6/ApiExtractor/enumvaluetypeentry.h
new file mode 100644
index 000000000..006b84e0a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/enumvaluetypeentry.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ENUMVALUETYPEENTRY_H
+#define ENUMVALUETYPEENTRY_H
+
+#include "typesystem.h"
+
+class EnumTypeEntry;
+class EnumValueTypeEntryPrivate;
+
+// EnumValueTypeEntry is used for resolving integer type templates
+// like array<EnumValue>. Note: Dummy entries for integer values will
+// be created for non-type template parameters, where m_enclosingEnum==nullptr.
+class EnumValueTypeEntry : public TypeEntry
+{
+public:
+ explicit EnumValueTypeEntry(const QString& name, const QString& value,
+ const EnumTypeEntryCPtr &enclosingEnum,
+ bool isScopedEnum, const QVersionNumber &vr);
+
+ QString value() const;
+ EnumTypeEntryCPtr enclosingEnum() const;
+
+ TypeEntry *clone() const override;
+
+protected:
+ explicit EnumValueTypeEntry(EnumValueTypeEntryPrivate *d);
+};
+
+#endif // ENUMVALUETYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/exception.h b/sources/shiboken6/ApiExtractor/exception.h
new file mode 100644
index 000000000..396b56f5d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/exception.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef EXCEPTION_H
+#define EXCEPTION_H
+
+#include <QtCore/QString>
+
+#include <string>
+#include <exception>
+
+class Exception : public std::exception
+{
+public:
+ explicit Exception(const QString &message) : m_message(message.toUtf8()) {}
+ explicit Exception(const char *message) : m_message(message) {}
+
+ const char *what() const noexcept override
+ {
+ return m_message.c_str();
+ }
+
+private:
+ const std::string m_message;
+};
+
+#endif // EXCEPTION
diff --git a/sources/shiboken6/ApiExtractor/fileout.cpp b/sources/shiboken6/ApiExtractor/fileout.cpp
new file mode 100644
index 000000000..6f9ec4d8a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/fileout.cpp
@@ -0,0 +1,198 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "fileout.h"
+#include "messages.h"
+#include "reporthandler.h"
+#include "exception.h"
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+#include <cstdio>
+
+bool FileOut::m_dryRun = false;
+bool FileOut::m_diff = false;
+
+#ifdef Q_OS_LINUX
+static const char colorDelete[] = "\033[31m";
+static const char colorAdd[] = "\033[32m";
+static const char colorInfo[] = "\033[36m";
+static const char colorReset[] = "\033[0m";
+#else
+static const char colorDelete[] = "";
+static const char colorAdd[] = "";
+static const char colorInfo[] = "";
+static const char colorReset[] = "";
+#endif
+
+FileOut::FileOut(QString n) :
+ stream(&m_buffer),
+ m_name(std::move(n)),
+ m_isDone(false)
+{
+}
+
+FileOut::~FileOut()
+{
+ if (!m_isDone) {
+ qCWarning(lcShiboken).noquote().nospace() << __FUNCTION__
+ << " file " << m_name << " not written.";
+ }
+}
+
+static QList<qsizetype> lcsLength(const QByteArrayList &a, const QByteArrayList &b)
+{
+ const auto height = a.size() + 1;
+ const auto width = b.size() + 1;
+
+ QList<qsizetype> res(width * height, 0);
+
+ for (qsizetype row = 1; row < height; row++) {
+ for (qsizetype col = 1; col < width; col++) {
+ if (a.at(row - 1) == b.at(col - 1))
+ res[width * row + col] = res[width * (row - 1) + col - 1] + 1;
+ else
+ res[width * row + col] = qMax(res[width * row + col - 1],
+ res[width * (row - 1) + col]);
+ }
+ }
+ return res;
+}
+
+enum Type {
+ Add,
+ Delete,
+ Unchanged
+};
+
+struct Unit
+{
+ Type type;
+ qsizetype start;
+ qsizetype end;
+
+ void print(const QByteArrayList &a, const QByteArrayList &b) const;
+};
+
+void Unit::print(const QByteArrayList &a, const QByteArrayList &b) const
+{
+ switch (type) {
+ case Unchanged:
+ if ((end - start) > 9) {
+ for (auto i = start; i <= start + 2; ++i)
+ std::printf(" %s\n", a.at(i).constData());
+ std::printf("%s=\n= %d more lines\n=%s\n",
+ colorInfo, int(end - start - 6), colorReset);
+ for (auto i = end - 2; i <= end; ++i)
+ std::printf(" %s\n", a.at(i).constData());
+ } else {
+ for (auto i = start; i <= end; ++i)
+ std::printf(" %s\n", a.at(i).constData());
+ }
+ break;
+ case Add:
+ std::fputs(colorAdd, stdout);
+ for (auto i = start; i <= end; ++i)
+ std::printf("+ %s\n", b.at(i).constData());
+ std::fputs(colorReset, stdout);
+ break;
+ case Delete:
+ std::fputs(colorDelete, stdout);
+ for (auto i = start; i <= end; ++i)
+ std::printf("- %s\n", a.at(i).constData());
+ std::fputs(colorReset, stdout);
+ break;
+ }
+}
+
+static void unitAppend(Type type, qsizetype pos, QList<Unit> *units)
+{
+ if (!units->isEmpty() && units->last().type == type)
+ units->last().end = pos;
+ else
+ units->append(Unit{type, pos, pos});
+}
+
+static QList<Unit> diffHelper(const QList<qsizetype> &lcs,
+ const QByteArrayList &a, const QByteArrayList &b,
+ qsizetype row, qsizetype col)
+{
+ if (row > 0 && col > 0 && a.at(row - 1) == b.at(col - 1)) {
+ QList<Unit> result = diffHelper(lcs, a, b, row - 1, col - 1);
+ unitAppend(Unchanged, row - 1, &result);
+ return result;
+ }
+
+ const auto width = b.size() + 1;
+ if (col > 0
+ && (row == 0 || lcs.at(width * row + col -1 ) >= lcs.at(width * (row - 1) + col))) {
+ QList<Unit> result = diffHelper(lcs, a, b, row, col - 1);
+ unitAppend(Add, col - 1, &result);
+ return result;
+ }
+ if (row > 0
+ && (col == 0 || lcs.at(width * row + col-1) < lcs.at(width * (row - 1) + col))) {
+ QList<Unit> result = diffHelper(lcs, a, b, row - 1, col);
+ unitAppend(Delete, row - 1, &result);
+ return result;
+ }
+ return {};
+}
+
+static void diff(const QByteArrayList &a, const QByteArrayList &b)
+{
+ const QList<Unit> res = diffHelper(lcsLength(a, b), a, b, a.size(), b.size());
+ for (const Unit &unit : res)
+ unit.print(a, b);
+}
+
+FileOut::State FileOut::done()
+{
+ if (m_isDone)
+ return Success;
+
+ bool fileEqual = false;
+ QFile fileRead(m_name);
+ QFileInfo info(fileRead);
+ stream.flush();
+ QByteArray original;
+ if (info.exists() && (m_diff || (info.size() == m_buffer.size()))) {
+ if (!fileRead.open(QIODevice::ReadOnly))
+ throw Exception(msgCannotOpenForReading(fileRead));
+
+ original = fileRead.readAll();
+ fileRead.close();
+ fileEqual = (original == m_buffer);
+ }
+
+ if (fileEqual) {
+ m_isDone = true;
+ return Unchanged;
+ }
+
+ if (!FileOut::m_dryRun) {
+ QDir dir(info.absolutePath());
+ if (!dir.mkpath(dir.absolutePath())) {
+ const QString message = QString::fromLatin1("Unable to create directory '%1'")
+ .arg(QDir::toNativeSeparators(dir.absolutePath()));
+ throw Exception(message);
+ }
+
+ QFile fileWrite(m_name);
+ if (!fileWrite.open(QIODevice::WriteOnly))
+ throw Exception(msgCannotOpenForWriting(fileWrite));
+ if (fileWrite.write(m_buffer) == -1 || !fileWrite.flush())
+ throw Exception(msgWriteFailed(fileWrite, m_buffer.size()));
+ }
+ if (m_diff) {
+ std::printf("%sFile: %s%s\n", colorInfo, qPrintable(m_name), colorReset);
+ ::diff(original.split('\n'), m_buffer.split('\n'));
+ std::printf("\n");
+ }
+
+ m_isDone = true;
+
+ return Success;
+}
diff --git a/sources/shiboken6/ApiExtractor/fileout.h b/sources/shiboken6/ApiExtractor/fileout.h
new file mode 100644
index 000000000..b11ad1e20
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/fileout.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef FILEOUT_H
+#define FILEOUT_H
+
+#include "textstream.h"
+
+class Exception;
+
+QT_FORWARD_DECLARE_CLASS(QFile)
+
+class FileOut
+{
+ QByteArray m_buffer;
+public:
+ Q_DISABLE_COPY_MOVE(FileOut)
+
+ enum State { Unchanged, Success };
+
+ explicit FileOut(QString name);
+ ~FileOut();
+
+ QString filePath() const { return m_name; }
+
+ State done() noexcept(false);
+
+ TextStream stream;
+
+ static bool diff() { return m_diff; }
+ static void setDiff(bool diff) { m_diff = diff; }
+
+ static bool dryRun() { return m_dryRun; }
+ static void setDryRun(bool dryRun) { m_dryRun = dryRun; }
+
+private:
+ QString m_name;
+ bool m_isDone;
+ static bool m_dryRun;
+ static bool m_diff;
+};
+
+#endif // FILEOUT_H
diff --git a/sources/shiboken6/ApiExtractor/flagstypeentry.h b/sources/shiboken6/ApiExtractor/flagstypeentry.h
new file mode 100644
index 000000000..6eddcd12b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/flagstypeentry.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef FLAGSTYPEENTRY_H
+#define FLAGSTYPEENTRY_H
+
+#include "typesystem.h"
+
+class EnumTypeEntry;
+class FlagsTypeEntryPrivate;
+
+// FlagsTypeEntry is configurable for global flags only
+class FlagsTypeEntry : public TypeEntry
+{
+public:
+ explicit FlagsTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ QString originalName() const;
+ void setOriginalName(const QString &s);
+
+ QString flagsName() const;
+ void setFlagsName(const QString &name);
+
+ EnumTypeEntryPtr originator() const;
+ void setOriginator(const EnumTypeEntryPtr &e);
+
+ TypeEntry *clone() const override;
+
+protected:
+ explicit FlagsTypeEntry(FlagsTypeEntryPrivate *d);
+
+ QString buildTargetLangName() const override;
+};
+
+#endif // FLAGSTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/functiontypeentry.h b/sources/shiboken6/ApiExtractor/functiontypeentry.h
new file mode 100644
index 000000000..53aa1fad6
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/functiontypeentry.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef FUNCTIONTYPEENTRY_H
+#define FUNCTIONTYPEENTRY_H
+
+#include "typesystem.h"
+
+class FunctionTypeEntryPrivate;
+
+class FunctionTypeEntry : public TypeEntry
+{
+public:
+ explicit FunctionTypeEntry(const QString& name, const QString& signature,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ const QStringList &signatures() const;
+ bool hasSignature(const QString& signature) const;
+ void addSignature(const QString& signature);
+
+ QString docFile() const;
+ void setDocFile(const QString &df);
+
+ TypeEntry *clone() const override;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+protected:
+ explicit FunctionTypeEntry(FunctionTypeEntryPrivate *d);
+};
+
+#endif // FUNCTIONTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/graph.h b/sources/shiboken6/ApiExtractor/graph.h
new file mode 100644
index 000000000..447a26da0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/graph.h
@@ -0,0 +1,321 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef GRAPH_H
+#define GRAPH_H
+
+#include "dotview.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QFile>
+#include <QtCore/QHash>
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QTextStream>
+
+#include <algorithm>
+
+/// Result of topologically sorting of a graph (list of nodes in order
+/// or list of nodes that have cyclic dependencies).
+template <class Node>
+struct GraphSortResult
+{
+ using NodeList = QList<Node>;
+
+ bool isValid() const { return !result.isEmpty() && cyclic.isEmpty(); }
+ void format(QDebug &debug) const;
+
+ NodeList result;
+ NodeList cyclic;
+};
+
+/// A graph that can have its nodes topologically sorted. The nodes need to
+/// have operator==().
+template <class Node>
+class Graph
+{
+public:
+ using NodeList = QList<Node>;
+
+ Graph() = default;
+
+ // Construct from a sequence of nodes
+ template<class It>
+ explicit Graph(It i1, It i2) { setNodes(i1, i2); }
+
+ template<class It>
+ void setNodes(It i1, It i2)
+ {
+ for (; i1 != i2; ++i1)
+ addNode(*i1);
+ }
+
+ bool addNode(Node n);
+
+ /// Returns whether node was registered
+ bool hasNode(Node node) { return indexOfNode(node) != -1; }
+
+ /// Returns the numbed of nodes in this graph.
+ qsizetype nodeCount() const { return m_nodeEntries.size(); }
+
+ /// Returns true if the graph contains the edge from -> to
+ bool containsEdge(Node from, Node to) const;
+ /// Returns true if the graph has any edges
+ bool hasEdges() const;
+
+ /// Adds an edge to this graph.
+ bool addEdge(Node from, Node to);
+ /// Removes an edge from this graph.
+ bool removeEdge(Node from, Node to);
+ /// Clears the graph
+ void clear() { m_nodeEntries.clear(); }
+
+ /// Dumps a dot graph to a file named \p filename.
+ /// \param fileName file name where the output should be written.
+ /// \param f function returning the name of a node
+ template <class NameFunction>
+ bool dumpDot(const QString& fileName, NameFunction f) const;
+ template <class NameFunction>
+ void formatDot(QTextStream &str, NameFunction f) const;
+ template <class NameFunction>
+ bool showGraph(const QString &name, NameFunction f) const;
+
+ void format(QDebug &debug) const;
+
+ /**
+ * Topologically sort this graph.
+ * \return A collection with all nodes topologically sorted or an empty collection if a cyclic
+ * dependency was found.
+ */
+ GraphSortResult<Node> topologicalSort() const;
+
+private:
+ enum Color { WHITE, GRAY, BLACK };
+
+ struct NodeEntry
+ {
+ Node node;
+ NodeList targets;
+ mutable Color color;
+ };
+
+ Color colorAt(qsizetype i) const { return m_nodeEntries.at(i).color; }
+ qsizetype indexOfNode(Node n) const;
+ void depthFirstVisit(qsizetype i, NodeList &result) const;
+
+ QList<NodeEntry> m_nodeEntries;
+};
+
+template <class Node>
+qsizetype Graph<Node>::indexOfNode(Node n) const
+{
+ for (qsizetype i = 0, size = m_nodeEntries.size(); i < size; ++i) {
+ if (m_nodeEntries.at(i).node == n)
+ return i;
+ }
+ return -1;
+}
+
+template <class Node>
+bool Graph<Node>::addNode(Node n)
+{
+ if (hasNode(n))
+ return false;
+ m_nodeEntries.append({n, {}, WHITE});
+ return true;
+}
+
+template <class Node>
+void Graph<Node>::depthFirstVisit(qsizetype i, NodeList &result) const
+{
+ m_nodeEntries[i].color = GRAY;
+
+ for (auto to : m_nodeEntries[i].targets) {
+ const qsizetype toIndex = indexOfNode(to);
+ Q_ASSERT(toIndex != -1);
+ switch (colorAt(toIndex)) {
+ case WHITE:
+ depthFirstVisit(toIndex, result);
+ break;
+ case GRAY:
+ return; // This is not a DAG!
+ case BLACK:
+ break;
+ }
+ }
+
+ m_nodeEntries[i].color = BLACK;
+
+ result.append(m_nodeEntries.at(i).node);
+}
+
+template <class Node>
+GraphSortResult<Node> Graph<Node>::topologicalSort() const
+{
+ const qsizetype size = m_nodeEntries.size();
+
+ GraphSortResult<Node> result;
+ result.result.reserve(size);
+
+ if (hasEdges()) {
+ for (qsizetype i = 0; i < size; ++i)
+ m_nodeEntries[i].color = WHITE;
+ for (qsizetype i = 0; i < size; ++i) {
+ if (colorAt(i) == WHITE) // recursive calls may have set it to black
+ depthFirstVisit(i, result.result);
+ }
+ } else { // no edges, shortcut
+ std::transform(m_nodeEntries.cbegin(), m_nodeEntries.cend(),
+ std::back_inserter(result.result),
+ [](const NodeEntry &ne) { return ne.node; });
+ }
+
+ if (result.result.size() == size) {
+ std::reverse(result.result.begin(), result.result.end());
+ } else {
+ for (const auto &nodeEntry : m_nodeEntries) {
+ if (!result.result.contains(nodeEntry.node))
+ result.cyclic.append(nodeEntry.node);
+ }
+ result.result.clear(); // Not a DAG!
+ }
+ return result;
+}
+
+template <class Node>
+bool Graph<Node>::containsEdge(Node from, Node to) const
+{
+ const qsizetype i = indexOfNode(from);
+ return i != -1 && m_nodeEntries.at(i).targets.contains(to);
+}
+
+template <class Node>
+bool Graph<Node>::hasEdges() const
+{
+ for (const auto &nodeEntry : m_nodeEntries) {
+ if (!nodeEntry.targets.isEmpty())
+ return true;
+ }
+ return false;
+}
+
+template <class Node>
+bool Graph<Node>::addEdge(Node from, Node to)
+{
+ const qsizetype i = indexOfNode(from);
+ if (i == -1 || !hasNode(to) || m_nodeEntries.at(i).targets.contains(to))
+ return false;
+ m_nodeEntries[i].targets.append(to);
+ return true;
+}
+
+template <class Node>
+bool Graph<Node>::removeEdge(Node from, Node to)
+{
+ const qsizetype i = indexOfNode(from);
+ if (i == -1)
+ return false;
+ auto &targets = m_nodeEntries[i].targets;
+ const qsizetype toIndex = targets.indexOf(to);
+ if (toIndex == -1)
+ return false;
+ targets.removeAt(toIndex);
+ return true;
+}
+
+template <class Node>
+template <class NameFunction>
+bool Graph<Node>::dumpDot(const QString& fileName,
+ NameFunction nameFunction) const
+{
+ QFile output(fileName);
+ if (!output.open(QIODevice::WriteOnly))
+ return false;
+ QTextStream s(&output);
+ formatDot(s, nameFunction);
+ return true;
+}
+
+template <class Node>
+template <class NameFunction>
+void Graph<Node>::formatDot(QTextStream &s,
+ NameFunction nameFunction) const
+{
+ s << "digraph D {\n";
+ for (const auto &nodeEntry : m_nodeEntries) {
+ if (!nodeEntry.targets.isEmpty()) {
+ const QString fromName = nameFunction(nodeEntry.node);
+ for (const Node &to : nodeEntry.targets)
+ s << '"' << fromName << "\" -> \"" << nameFunction(to) << "\"\n";
+ }
+ }
+ s << "}\n";
+}
+
+template <class Node>
+template <class NameFunction>
+bool Graph<Node>::showGraph(const QString &name, NameFunction f) const
+{
+ QString graph;
+ QTextStream s(&graph);
+ formatDot(s, f);
+ return showDotGraph(name, graph);
+}
+
+template <class Node>
+void Graph<Node>::format(QDebug &debug) const
+{
+ const qsizetype size = m_nodeEntries.size();
+ debug << "nodes[" << size << "] = (";
+ for (qsizetype i = 0; i < size; ++i) {
+ const auto &nodeEntry = m_nodeEntries.at(i);
+ if (i)
+ debug << ", ";
+ debug << nodeEntry.node;
+ if (!nodeEntry.targets.isEmpty()) {
+ debug << " -> [";
+ for (qsizetype t = 0, tsize = nodeEntry.targets.size(); t < tsize; ++t) {
+ if (t)
+ debug << ", ";
+ debug << nodeEntry.targets.at(t);
+ }
+ debug << ']';
+ }
+ }
+ debug << ')';
+}
+
+template <class Node>
+QDebug operator<<(QDebug debug, const Graph<Node> &g)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Graph(";
+ g.format(debug);
+ debug << ')';
+ return debug;
+}
+
+template <class Node>
+void GraphSortResult<Node>::format(QDebug &debug) const
+{
+ if (isValid())
+ debug << "Valid, " << result;
+ else
+ debug << "Invalid, cyclic dependencies: " << cyclic;
+}
+
+template <class Node>
+QDebug operator<<(QDebug debug, const GraphSortResult<Node> &r)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Graph::SortResult(";
+ r.format(debug);
+ debug << ')';
+ return debug;
+}
+
+#endif // GRAPH_H
diff --git a/sources/shiboken6/ApiExtractor/header_paths.h b/sources/shiboken6/ApiExtractor/header_paths.h
new file mode 100644
index 000000000..af4a768e8
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/header_paths.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef HEADER_PATHS_H
+#define HEADER_PATHS_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+
+enum class HeaderType
+{
+ Standard,
+ System, // -isystem
+ Framework, // macOS framework path
+ FrameworkSystem // macOS framework system path
+};
+
+class HeaderPath {
+public:
+ QByteArray path;
+ HeaderType type;
+
+ static QByteArray includeOption(const HeaderPath &p)
+ {
+ QByteArray option;
+ switch (p.type) {
+ case HeaderType::Standard:
+ option = QByteArrayLiteral("-I");
+ break;
+ case HeaderType::System:
+ option = QByteArrayLiteral("-isystem");
+ break;
+ case HeaderType::Framework:
+ option = QByteArrayLiteral("-F");
+ break;
+ case HeaderType::FrameworkSystem:
+ option = QByteArrayLiteral("-iframework");
+ break;
+ }
+ return option + p.path;
+ }
+};
+
+using HeaderPaths = QList<HeaderPath>;
+
+#endif // HEADER_PATHS_H
diff --git a/sources/shiboken6/ApiExtractor/icecc.cmake b/sources/shiboken6/ApiExtractor/icecc.cmake
new file mode 100644
index 000000000..fa8d3b7cf
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/icecc.cmake
@@ -0,0 +1,14 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include (CMakeForceCompiler)
+option(ENABLE_ICECC "Enable icecc checking, for distributed compilation")
+if (ENABLE_ICECC)
+ find_program(ICECC icecc)
+ if (ICECC)
+ message(STATUS "icecc found! Distributed compilation for all!! huhuhu.")
+ cmake_force_cxx_compiler(${ICECC} icecc)
+ else(ICECC)
+ message(FATAL_ERROR "icecc NOT found! re-run cmake without -DENABLE_ICECC")
+ endif(ICECC)
+endif(ENABLE_ICECC)
diff --git a/sources/shiboken6/ApiExtractor/include.cpp b/sources/shiboken6/ApiExtractor/include.cpp
new file mode 100644
index 000000000..aee6b7337
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/include.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "include.h"
+#include "textstream.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QHash>
+#include <QtCore/QTextStream>
+
+#include "qtcompat.h"
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+QString Include::toString() const
+{
+ if (m_type == IncludePath)
+ return u"#include <"_s + m_name + u'>';
+ if (m_type == LocalPath)
+ return u"#include \""_s + m_name + u'"';
+ return u"import "_s + m_name + u';';
+}
+
+Qt::strong_ordering compareThreeWay(const Include &lhs, const Include &rhs) noexcept
+{
+ if (lhs.m_type < rhs.m_type)
+ return Qt::strong_ordering::less;
+ if (lhs.m_type > rhs.m_type)
+ return Qt::strong_ordering::greater;
+ if (auto c = lhs.m_name.compare(rhs.m_name))
+ return c < 0 ? Qt::strong_ordering::less : Qt::strong_ordering::greater;
+ return Qt::strong_ordering::equal;
+}
+
+QTextStream& operator<<(QTextStream& out, const Include& g)
+{
+ if (g.isValid())
+ out << g.toString() << Qt::endl;
+ return out;
+}
+
+TextStream& operator<<(TextStream& out, const Include& include)
+{
+ if (include.isValid())
+ out << include.toString() << '\n';
+ return out;
+}
+
+TextStream& operator<<(TextStream &out, const IncludeGroup& g)
+{
+ if (!g.includes.isEmpty()) {
+ if (!g.title.isEmpty())
+ out << "\n// " << g.title << "\n";
+ auto includes = g.includes;
+ std::sort(includes.begin(), includes.end());
+ for (const Include &inc : std::as_const(includes))
+ out << inc.toString() << '\n';
+ }
+ return out;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const Include &i)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "Include(";
+ if (i.isValid())
+ d << "type=" << i.type() << ", file=\"" << QDir::toNativeSeparators(i.name()) << '"';
+ else
+ d << "invalid";
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/include.h b/sources/shiboken6/ApiExtractor/include.h
new file mode 100644
index 000000000..875a941f9
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/include.h
@@ -0,0 +1,95 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef INCLUDE_H
+#define INCLUDE_H
+
+#include <QtCore/QtCompare>
+#include <QtCore/QHashFunctions>
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QTextStream;
+QT_END_NAMESPACE
+
+class TextStream;
+
+class Include
+{
+public:
+ enum IncludeType {
+ IncludePath,
+ LocalPath,
+ TargetLangImport
+ };
+
+ Include() = default;
+ Include(IncludeType t, const QString &nam) : m_type(t), m_name(nam) {};
+
+ bool isValid() const
+ {
+ return !m_name.isEmpty();
+ }
+
+ IncludeType type() const
+ {
+ return m_type;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ QString toString() const;
+
+ int compare(const Include &rhs) const;
+
+private:
+ friend size_t qHash(Include &inc, size_t seed = 0) noexcept
+ {
+ return qHashMulti(seed, inc.m_type, inc.m_name);
+ }
+ friend bool comparesEqual(const Include &lhs, const Include &rhs) noexcept
+ {
+ return lhs.m_type == rhs.m_type && lhs.m_name == rhs.m_name;
+ }
+ friend Qt::strong_ordering compareThreeWay(const Include &lhs,
+ const Include &rhs) noexcept;
+ Q_DECLARE_STRONGLY_ORDERED(Include)
+
+ IncludeType m_type = IncludePath;
+ QString m_name;
+};
+
+QTextStream& operator<<(QTextStream& out, const Include& include);
+TextStream& operator<<(TextStream& out, const Include& include);
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const Include &i);
+#endif
+
+using IncludeList = QList<Include>;
+
+struct IncludeGroup
+{
+ QString title;
+ IncludeList includes;
+
+ void append(const Include &include)
+ {
+ IncludeGroup::appendInclude(include, &includes);
+ }
+
+ static void appendInclude(const Include &include, IncludeList *list)
+ {
+ if (include.isValid() && !list->contains(include))
+ list->append(include);
+ }
+};
+
+TextStream& operator<<(TextStream &out, const IncludeGroup& include);
+
+using IncludeGroupList = QList<IncludeGroup>;
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/merge.xsl b/sources/shiboken6/ApiExtractor/merge.xsl
new file mode 100644
index 000000000..c6cab5a42
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/merge.xsl
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+ <xsl:output method="xml" indent="yes"/>
+ <xsl:param name="lang" />
+ <xsl:param name="source" />
+
+ <xsl:template match="processing-instruction()" />
+
+ <xsl:template match="/typesystem">
+ <xsl:copy>
+ <xsl:for-each select="@*">
+ <xsl:copy>
+ <xsl:value-of select="." />
+ </xsl:copy>
+ </xsl:for-each>
+
+ <xsl:for-each select="document($source)/typesystem/@*">
+ <xsl:copy>
+ <xsl:value-of select="." />
+ </xsl:copy>
+ </xsl:for-each>
+
+ <xsl:variable name="other" select="document($source)/typesystem/*[not(self::object-type | self::value-type | self::interface-type | self::namespace-type)]" />
+ <xsl:if test="$other">
+ <xsl:choose>
+ <xsl:when test="$lang != ''">
+ <xsl:element name="language">
+ <xsl:attribute name="name" ><xsl:value-of select="$lang" /></xsl:attribute>
+ <xsl:copy-of select="$other" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="$other" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:apply-templates select="node()" />
+
+ </xsl:copy>
+ </xsl:template>
+
+
+
+ <xsl:template match="/typesystem/*[self::object-type | self::value-type | self::interface-type | self::namespace-type]">
+ <xsl:variable name="name" select="name()" />
+ <xsl:copy>
+ <xsl:for-each select="@*">
+ <xsl:copy>
+ <xsl:value-of select="." />
+ </xsl:copy>
+ </xsl:for-each>
+
+ <xsl:apply-templates select="node()" />
+
+ <xsl:variable name="other" select="document($source)/typesystem/*[name() = $name][@name = current()/@name]" />
+ <xsl:if test="$other">
+ <xsl:choose>
+ <xsl:when test="$lang != ''">
+ <xsl:element name="language">
+ <xsl:attribute name="name" ><xsl:value-of select="$lang" /></xsl:attribute>
+ <xsl:copy-of select="$other/node()" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="$other/node()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Plain identity transform. -->
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*"/>
+ <xsl:apply-templates select="node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp
new file mode 100644
index 000000000..170595660
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/messages.cpp
@@ -0,0 +1,1004 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "messages.h"
+#include "abstractmetaenum.h"
+#include "abstractmetafield.h"
+#include "abstractmetafunction.h"
+#include "abstractmetalang.h"
+#include "modifications.h"
+#include "sourcelocation.h"
+#include "typedatabase.h"
+#include "functiontypeentry.h"
+#include "enumtypeentry.h"
+#include "smartpointertypeentry.h"
+#include <codemodel.h>
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QStringList>
+#include <QtCore/QXmlStreamReader>
+
+using namespace Qt::StringLiterals;
+
+// abstractmetabuilder.cpp
+
+static QTextStream &operator<<(QTextStream &s, Access a)
+{
+ switch (a) {
+ case Access::Public:
+ s << "public";
+ break;
+ case Access::Protected:
+ s << "protected";
+ break;
+ case Access::Private:
+ s << "private";
+ break;
+ }
+ return s;
+}
+
+QString msgNoFunctionForModification(const AbstractMetaClassCPtr &klass,
+ const QString &signature,
+ const QString &originalSignature,
+ const QStringList &possibleSignatures,
+ const AbstractMetaFunctionCList &allFunctions)
+{
+ QString result;
+ QTextStream str(&result);
+ str << klass->typeEntry()->sourceLocation() << "signature '"
+ << signature << '\'';
+ if (!originalSignature.isEmpty() && originalSignature != signature)
+ str << " (specified as '" << originalSignature << "')";
+ str << " for function modification in '"
+ << klass->qualifiedCppName() << "' not found.";
+ if (!possibleSignatures.isEmpty()) {
+ str << "\n Possible candidates:\n";
+ for (const auto &s : possibleSignatures)
+ str << " " << s << '\n';
+ } else if (!allFunctions.isEmpty()) {
+ str << "\n No candidates were found. Member functions:\n";
+ const auto maxCount = qMin(qsizetype(10), allFunctions.size());
+ for (qsizetype f = 0; f < maxCount; ++f)
+ str << " " << allFunctions.at(f)->minimalSignature() << '\n';
+ if (maxCount < allFunctions.size())
+ str << " ...\n";
+ }
+ return result;
+}
+
+QString msgArgumentIndexOutOfRange(const AbstractMetaFunction *func, int index)
+{
+ QString result;
+ QTextStream str(&result);
+ str <<"Index " << index << " out of range for " << func->classQualifiedSignature() << '.';
+ return result;
+}
+
+QString msgTypeModificationFailed(const QString &type, int n,
+ const AbstractMetaFunction *func,
+ const QString &why)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Unable to modify the ";
+ if (n == 0)
+ str << "return type";
+ else
+ str << "type of argument " << n;
+
+ str << " of ";
+ if (auto c = func->ownerClass())
+ str << c->name() << "::";
+ str << func->signature() << " to \"" << type << "\": " << why;
+ return result;
+}
+
+QString msgInvalidArgumentModification(const AbstractMetaFunctionCPtr &func,
+ int argIndex)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Invalid ";
+ if (argIndex == 0)
+ str << "return type modification";
+ else
+ str << "modification of argument " << argIndex;
+ str << " for " << func->classQualifiedSignature();
+ return result;
+}
+
+QString msgArgumentOutOfRange(int number, int minValue, int maxValue)
+{
+ QString result;
+ QTextStream(&result) << "Argument number " << number
+ << " out of range " << minValue << ".." << maxValue << '.';
+ return result;
+}
+
+QString msgArgumentRemovalFailed(const AbstractMetaFunction *func, int n,
+ const QString &why)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Unable to remove argument " << n << " of ";
+ if (auto c = func->ownerClass())
+ str << c->name() << "::";
+ str << func->signature() << ": " << why;
+ return result;
+}
+
+template <class Stream>
+static void msgFormatEnumType(Stream &str,
+ const EnumModelItem &enumItem,
+ const QString &className)
+{
+ switch (enumItem->enumKind()) {
+ case CEnum:
+ str << "Enum '" << enumItem->qualifiedName().join(u"::"_s) << '\'';
+ break;
+ case AnonymousEnum: {
+ const EnumeratorList &values = enumItem->enumerators();
+ str << "Anonymous enum (";
+ switch (values.size()) {
+ case 0:
+ break;
+ case 1:
+ str << values.constFirst()->name();
+ break;
+ case 2:
+ str << values.at(0)->name() << ", " << values.at(1)->name();
+ break;
+ default:
+ str << values.at(0)->name() << ", ... , "
+ << values.at(values.size() - 1)->name();
+ break;
+ }
+ str << ')';
+ }
+ break;
+ case EnumClass:
+ str << "Scoped enum '" << enumItem->qualifiedName().join(u"::"_s) << '\'';
+ break;
+ }
+ if (!className.isEmpty())
+ str << " (class: " << className << ')';
+}
+
+static void formatAddedFuncError(const QString &addedFuncName,
+ const AbstractMetaClassCPtr &context,
+ QTextStream &str)
+{
+ if (context) {
+ str << context->typeEntry()->sourceLocation()
+ << "Unable to traverse function \"" << addedFuncName
+ << "\" added to \"" << context->name() << "\": ";
+ } else {
+ str << "Unable to traverse added global function \""
+ << addedFuncName << "\": ";
+ }
+}
+
+QString msgAddedFunctionInvalidArgType(const QString &addedFuncName,
+ const QStringList &typeName,
+ int pos, const QString &why,
+ const AbstractMetaClassCPtr &context)
+{
+ QString result;
+ QTextStream str(&result);
+ formatAddedFuncError(addedFuncName, context, str);
+ str << "Unable to translate type \"" << typeName.join(u"::"_s)
+ << "\" of argument " << pos << " of added function \""
+ << addedFuncName << "\": " << why;
+ return result;
+}
+
+QString msgAddedFunctionInvalidReturnType(const QString &addedFuncName,
+ const QStringList &typeName, const QString &why,
+ const AbstractMetaClassCPtr &context)
+{
+ QString result;
+ QTextStream str(&result);
+ formatAddedFuncError(addedFuncName, context, str);
+ str << "Unable to translate return type \"" << typeName.join(u"::"_s)
+ << "\" of added function \"" << addedFuncName << "\": "
+ << why;
+ return result;
+}
+
+QString msgUnnamedArgumentDefaultExpression(const AbstractMetaClassCPtr &context,
+ int n, const QString &className,
+ const AbstractMetaFunction *f)
+{
+ QString result;
+ QTextStream str(&result);
+ if (context)
+ str << context->sourceLocation();
+ str << "Argument " << n << " on function '" << className << "::"
+ << f->minimalSignature() << "' has default expression but does not have name.";
+ return result;
+}
+
+QString msgClassOfEnumNotFound(const EnumTypeEntryCPtr &entry)
+{
+ QString result;
+ QTextStream str(&result);
+ str << entry->sourceLocation() << "AbstractMeta::findEnum(), unknown class '"
+ << entry->parent()->qualifiedCppName() << "' in '"
+ << entry->qualifiedCppName() << '\'';
+ return result;
+}
+
+QString msgNoEnumTypeEntry(const EnumModelItem &enumItem,
+ const QString &className)
+{
+ QString result;
+ QTextStream str(&result);
+ str << enumItem->sourceLocation();
+ msgFormatEnumType(str, enumItem, className);
+ str << " does not have a type entry (type systems: "
+ << TypeDatabase::instance()->loadedTypeSystemNames() << ')';
+ return result;
+}
+
+QString msgNoEnumTypeConflict(const EnumModelItem &enumItem,
+ const QString &className,
+ const TypeEntryCPtr &t)
+{
+ QString result;
+ QDebug debug(&result); // Use the debug operator for TypeEntry::Type
+ debug.noquote();
+ debug.nospace();
+ debug << enumItem->sourceLocation().toString();
+ msgFormatEnumType(debug, enumItem, className);
+ debug << " is not an enum (type: " << t->type() << ')';
+ return result;
+}
+
+QString msgNamespaceNoTypeEntry(const NamespaceModelItem &item,
+ const QString &fullName)
+{
+ QString result;
+ QTextStream str(&result);
+ str << item->sourceLocation() << "namespace '" << fullName
+ << "' does not have a type entry (type systems: "
+ << TypeDatabase::instance()->loadedTypeSystemNames() << ')';
+ return result;
+}
+
+QString msgNamespaceNotFound(const QString &name)
+{
+ return u"namespace '"_s + name + u"' not found."_s;
+}
+
+QString msgAmbiguousVaryingTypesFound(const QString &qualifiedName, const TypeEntryCList &te)
+{
+ QString result = u"Ambiguous types of varying types found for \""_s + qualifiedName
+ + u"\": "_s;
+ QDebug(&result) << te;
+ return result;
+}
+
+QString msgAmbiguousTypesFound(const QString &qualifiedName, const TypeEntryCList &te)
+{
+ QString result = u"Ambiguous types found for \""_s + qualifiedName
+ + u"\": "_s;
+ QDebug(&result) << te;
+ return result;
+}
+
+QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n,
+ const QString &why)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "unmatched type '" << arg->type().toString() << "' in parameter #"
+ << (n + 1);
+ if (!arg->name().isEmpty())
+ str << " \"" << arg->name() << '"';
+ str << ": " << why;
+ return result;
+}
+
+QString msgUnmatchedReturnType(const FunctionModelItem &functionItem,
+ const QString &why)
+{
+ return u"unmatched return type '"_s
+ + functionItem->type().toString()
+ + u"': "_s + why;
+}
+
+QString msgSkippingFunction(const FunctionModelItem &functionItem,
+ const QString &signature, const QString &why)
+{
+ QString result;
+ QTextStream str(&result);
+ str << functionItem->sourceLocation() << "skipping "
+ << functionItem->accessPolicy() << ' ';
+ const bool isAbstract = functionItem->attributes().testFlag(FunctionAttribute::Abstract);
+ if (isAbstract)
+ str << "abstract ";
+ str << "function '" << signature << "', " << why;
+ if (isAbstract) {
+ str << "\nThis will lead to compilation errors due to not "
+ "being able to instantiate the wrapper.";
+ }
+ return result;
+}
+
+QString msgShadowingFunction(const AbstractMetaFunction *f1,
+ const AbstractMetaFunction *f2)
+{
+ auto f2Class = f2->implementingClass();
+ QString result;
+ QTextStream str(&result);
+ str << f2Class->sourceLocation() << "Shadowing: " << f1->classQualifiedSignature()
+ << " and " << f2->classQualifiedSignature();
+ return result;
+}
+
+QString msgSignalOverloaded(const AbstractMetaClassCPtr &c,
+ const AbstractMetaFunction *f)
+{
+ QString result;
+ QTextStream str(&result);
+ str << c->sourceLocation() << "signal '" << f->name() << "' in class '"
+ << c->name() << "' is overloaded.";
+ return result;
+}
+
+QString msgSkippingField(const VariableModelItem &field, const QString &className,
+ const QString &type)
+{
+ QString result;
+ QTextStream str(&result);
+ str << field->sourceLocation() << "skipping " << field->accessPolicy()
+ << " field '" << className << "::" << field->name()
+ << "' with unmatched type '" << type << '\'';
+ return result;
+}
+
+static const char msgCompilationError[] =
+ "This could potentially lead to compilation errors.";
+
+QString msgTypeNotDefined(const TypeEntryCPtr &entry)
+{
+ QString result;
+ QTextStream str(&result);
+ const bool hasConfigCondition = entry->isComplex()
+ && std::static_pointer_cast<const ConfigurableTypeEntry>(entry)->hasConfigCondition();
+ str << entry->sourceLocation() << "type '" <<entry->qualifiedCppName()
+ << "' is specified in typesystem, but not defined";
+ if (hasConfigCondition)
+ str << " (disabled by configuration?).";
+ else
+ str << ". " << msgCompilationError;
+ return result;
+}
+
+QString msgGlobalFunctionNotDefined(const FunctionTypeEntryCPtr &fte,
+ const QString &signature,
+ const QStringList &candidates)
+{
+ QString result;
+ QTextStream str(&result);
+ str << fte->sourceLocation() << "Global function '" << signature
+ << "' is specified in typesystem, but not defined.";
+ if (!candidates.isEmpty())
+ str << " Candidates are: " << candidates.join(u", "_s);
+ str << ' ' << msgCompilationError;
+ return result;
+}
+
+QString msgStrippingArgument(const FunctionModelItem &f, int i,
+ const QString &originalSignature,
+ const ArgumentModelItem &arg,
+ const QString &reason)
+{
+ QString result;
+ QTextStream str(&result);
+ str << f->sourceLocation() << "Stripping argument #" << (i + 1) << " of "
+ << originalSignature << " due to unmatched type \""
+ << arg->type().toString() << "\" with default expression \""
+ << arg->defaultValueExpression() << "\": " << reason;
+ return result;
+}
+
+QString msgEnumNotDefined(const EnumTypeEntryCPtr &t)
+{
+ QString result;
+ QTextStream str(&result);
+ str << t->sourceLocation() << "enum '" << t->qualifiedCppName()
+ << "' is specified in typesystem, but not declared.";
+ return result;
+}
+
+QString msgUnknownBase(const AbstractMetaClassCPtr &metaClass,
+ const QString &baseClassName)
+{
+ QString result;
+ QTextStream str(&result);
+ str << metaClass->sourceLocation() << "Base class '" << baseClassName << "' of class '"
+ << metaClass->name() << "' not found in the code for setting up inheritance.";
+ return result;
+}
+
+QString msgBaseNotInTypeSystem(const AbstractMetaClassCPtr &metaClass,
+ const QString &baseClassName)
+{
+ QString result;
+ QTextStream str(&result);
+ str << metaClass->sourceLocation() << "Base class '" << baseClassName << "' of class '"
+ << metaClass->name() << "' not found in the type system for setting up inheritance.";
+ return result;
+}
+
+QString msgArrayModificationFailed(const FunctionModelItem &functionItem,
+ const QString &className,
+ const QString &errorMessage)
+{
+ QString result;
+ QTextStream str(&result);
+ str << functionItem->sourceLocation() << "While traversing " << className
+ << ": " << errorMessage;
+ return result;
+}
+
+QString msgCannotResolveEntity(const QString &name, const QString &reason)
+{
+ return u"Cannot resolve entity \""_s + name + u"\": "_s + reason;
+}
+
+QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason)
+{
+ return function + u": Cannot use parameter "_s
+ + QString::number(i + 1) + u" as an array: "_s + reason;
+}
+
+QString msgUnableToTranslateType(const QString &t, const QString &why)
+{
+ return u"Unable to translate type \""_s + t + u"\": "_s + why;
+}
+
+QString msgUnableToTranslateType(const TypeInfo &typeInfo,
+ const QString &why)
+{
+ return msgUnableToTranslateType(typeInfo.toString(), why);
+}
+
+QString msgCannotFindTypeEntry(const QString &t)
+{
+ return u"Cannot find type entry for \""_s + t + u"\"."_s;
+}
+
+QString msgCannotFindTypeEntryForSmartPointer(const QString &t, const QString &smartPointerType)
+{
+ return u"Cannot find type entry \""_s + t
+ + 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;
+}
+
+QString msgCannotFindSmartPointerInstantion(const TypeInfo &i)
+{
+ return u"Cannot find instantiation of smart pointer type for \""_s
+ + i.toString() + u"\"."_s;
+}
+
+QString msgCannotTranslateTemplateArgument(int i,
+ const TypeInfo &typeInfo,
+ const QString &why)
+{
+ QString result;
+ QTextStream(&result) << "Unable to translate template argument "
+ << (i + 1) << typeInfo.toString() << ": " << why;
+ return result;
+}
+
+QString msgDisallowThread(const AbstractMetaFunction *f)
+{
+ QString result;
+ QTextStream str(&result);
+ str <<"Disallowing threads for ";
+ if (auto c = f->declaringClass())
+ str << c->name() << "::";
+ str << f->name() << "().";
+ return result;
+}
+
+QString msgNamespaceToBeExtendedNotFound(const QString &namespaceName, const QString &packageName)
+{
+ return u"The namespace '"_s + namespaceName
+ + u"' to be extended cannot be found in package "_s
+ + packageName + u'.';
+}
+
+QString msgPropertyTypeParsingFailed(const QString &name, const QString &typeName,
+ const QString &why)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Unable to decide type of property: \"" << name << "\" (" << typeName
+ << "): " << why;
+ return result;
+}
+
+QString msgPropertyExists(const QString &className, const QString &name)
+{
+ return u"class "_s + className + u" already has a property \""_s
+ + name + u"\" (defined by Q_PROPERTY)."_s;
+}
+
+QString msgFunctionVisibilityModified(const AbstractMetaClassCPtr &c,
+ const AbstractMetaFunction *f)
+{
+ QString result;
+ QTextStream str(&result);
+ str << c->sourceLocation() << "Visibility of function '" << f->name()
+ << "' modified in class '"<< c->name() << '\'';
+ return result;
+}
+
+QString msgUsingMemberClassNotFound(const AbstractMetaClassCPtr &c,
+ const QString &baseClassName,
+ const QString &memberName)
+{
+ QString result;
+ QTextStream str(&result);
+ str << c->sourceLocation() << "base class \"" << baseClassName
+ << "\" of \"" << c->qualifiedCppName() << "\" for using member \""
+ << memberName << "\" not found.";
+ return result;
+}
+// docparser.cpp
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const char *what, const QString &name,
+ const QString &query)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Cannot find documentation for " << what
+ << ' ' << name << " in:\n " << QDir::toNativeSeparators(fileName);
+ if (!query.isEmpty())
+ str << "\n using query:\n " << query;
+ return result;
+}
+
+QString msgFallbackForDocumentation(const QString &fileName,
+ const char *what, const QString &name,
+ const QString &query)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Fallback used while trying to find documentation for " << what
+ << ' ' << name << " in:\n " << QDir::toNativeSeparators(fileName);
+ if (!query.isEmpty())
+ str << "\n using query:\n " << query;
+ return result;
+}
+
+static QString functionDescription(const AbstractMetaFunction *function)
+{
+ QString result = u'"' + function->classQualifiedSignature() + u'"';
+ if (function->flags().testFlag(AbstractMetaFunction::Flag::HiddenFriend))
+ result += u" (hidden friend)"_s;
+ if (function->flags().testFlag(AbstractMetaFunction::Flag::InheritedFromTemplate))
+ result += u" (inherited from template)"_s;
+ return result;
+}
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaFunction *function,
+ const QString &query)
+{
+ return msgCannotFindDocumentation(fileName, "function",
+ functionDescription(function), query);
+}
+
+QString msgFallbackForDocumentation(const QString &fileName,
+ const AbstractMetaFunction *function,
+ const QString &query)
+{
+ return msgFallbackForDocumentation(fileName, "function",
+ functionDescription(function), query);
+}
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClassCPtr &metaClass,
+ const AbstractMetaEnum &e,
+ const QString &query)
+{
+ QString name = e.name();
+ if (metaClass != nullptr)
+ name.prepend(metaClass->name() + "::"_L1);
+ return msgCannotFindDocumentation(fileName, "enum", name, query);
+}
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClassCPtr &metaClass,
+ const AbstractMetaField &f,
+ const QString &query)
+{
+ QString name = f.name();
+ if (metaClass != nullptr)
+ name.prepend(metaClass->name() + "::"_L1);
+ return msgCannotFindDocumentation(fileName, "field", name, query);
+}
+
+QString msgXpathDocModificationError(const DocModificationList& mods,
+ const QString &what)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Error when applying modifications (";
+ for (const DocModification &mod : mods) {
+ if (mod.mode() == TypeSystem::DocModificationXPathReplace) {
+ str << '"' << mod.xpath() << "\" -> \"";
+ const QString simplified = mod.code().simplified();
+ if (simplified.size() > 20)
+ str << QStringView{simplified}.left(20) << "...";
+ else
+ str << simplified;
+ str << '"';
+ }
+ }
+ str << "): " << what;
+ return result;
+}
+
+// fileout.cpp
+
+QString msgCannotOpenForReading(const QFile &f)
+{
+ return QString::fromLatin1("Failed to open file '%1' for reading: %2")
+ .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
+}
+
+QString msgCannotOpenForWriting(const QFile &f)
+{
+ return QString::fromLatin1("Failed to open file '%1' for writing: %2")
+ .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
+}
+
+QString msgWriteFailed(const QFile &f, qsizetype size)
+{
+ QString result;
+ QTextStream(&result) << "Failed to write " << size << "bytes to '"
+ << QDir::toNativeSeparators(f.fileName()) << "': "
+ << f.errorString();
+ return result;
+}
+
+// generator.cpp
+
+QString msgCannotUseEnumAsInt(const QString &name)
+{
+ return u"Cannot convert the protected scoped enum \""_s + name
+ + u"\" to type int when generating wrappers for the protected hack. "
+ "Compilation errors may occur when used as a function argument."_s;
+}
+
+QString msgCannotFindSmartPointerGetter(const SmartPointerTypeEntryCPtr &te)
+{
+ return u"Getter \""_s + te->getter() + u"()\" of smart pointer \""_s
+ + te->name() + u"\" not found."_s;
+}
+
+QString msgCannotFindSmartPointerMethod(const SmartPointerTypeEntryCPtr &te, const QString &m)
+{
+ return u"Method \""_s + m + u"()\" of smart pointer \""_s
+ + te->name() + u"\" not found."_s;
+}
+
+QString msgMethodNotFound(const AbstractMetaClassCPtr &klass, const QString &name)
+{
+ return u"Method \""_s + name + u"\" not found in class "_s
+ + klass->name() + u'.';
+}
+
+// main.cpp
+
+QString msgLeftOverArguments(const QString &remainingArgs, const QStringList &argV)
+{
+ QString message;
+ QTextStream str(&message);
+ str << "shiboken: Unprocessed arguments: " << remainingArgs
+ << "\nCommand line: " << argV.join(u' ');
+ return message;
+}
+
+QString msgInvalidVersion(const QString &package, const QString &version)
+{
+ return u"Invalid version \""_s + version
+ + u"\" specified for package "_s + package + u'.';
+}
+
+QString msgCyclicDependency(const QString &funcName, const QString &graphName,
+ const AbstractMetaFunctionCList &cyclic,
+ const AbstractMetaFunctionCList &involvedConversions)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Cyclic dependency found on overloaddata for \"" << funcName
+ << "\" method! The graph boy saved the graph at \"" << QDir::toNativeSeparators(graphName)
+ << "\". Cyclic functions:";
+ for (const auto &c : cyclic)
+ str << ' ' << c->signature();
+ if (const auto count = involvedConversions.size()) {
+ str << " Implicit conversions (" << count << "): ";
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ str << ", \"";
+ str << involvedConversions.at(i)->signature() << '"';
+ if (const auto c = involvedConversions.at(i)->implementingClass())
+ str << '(' << c->name() << ')';
+ }
+ }
+ return result;
+}
+
+// shibokengenerator.cpp
+
+QString msgClassNotFound(const TypeEntryCPtr &t)
+{
+ return u"Could not find class \""_s
+ + t->qualifiedCppName()
+ + u"\" in the code model. Maybe it is forward declared?"_s;
+}
+
+QString msgEnclosingClassNotFound(const TypeEntryCPtr &t)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Warning: Enclosing class \"" << t->parent()->name()
+ << "\" of class \"" << t->name() << "\" not found.";
+ return result;
+}
+
+QString msgUnknownOperator(const AbstractMetaFunction *func)
+{
+ QString result = u"Unknown operator: \""_s + func->originalName()
+ + u'"';
+ if (const auto c = func->implementingClass())
+ result += u" in class: "_s + c->name();
+ return result;
+}
+
+QString msgWrongIndex(const char *varName, const QString &capture,
+ const AbstractMetaFunction *func)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Wrong index for " << varName << " variable (" << capture << ") on ";
+ if (const auto c = func->implementingClass())
+ str << c->name() << "::";
+ str << func->signature();
+ return result;
+}
+
+QString msgCannotFindType(const QString &type, const QString &variable,
+ const QString &why)
+{
+ QString result;
+ QTextStream(&result) << "Could not find type '"
+ << type << "' for use in '" << variable << "' conversion: " << why
+ << "\nMake sure to use the full C++ name, e.g. 'Namespace::Class'.";
+ return result;
+}
+
+QString msgCannotBuildMetaType(const QString &s)
+{
+ return u"Unable to build meta type for \""_s + s + u"\": "_s;
+}
+
+QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type, const QString &why)
+{
+ QString result;
+ QTextStream str(&result);
+ str << where << ": Could not find a minimal constructor for type '" << type << '\'';
+ if (why.isEmpty())
+ str << '.';
+ else
+ str << ": " << why << ' ';
+ str << "This will result in a compilation error.";
+ return result;
+}
+
+// typedatabase.cpp
+
+QString msgRejectReason(const TypeRejection &r, const QString &needle)
+{
+ QString result;
+ QTextStream str(&result);
+ switch (r.matchType) {
+ case TypeRejection::ExcludeClass:
+ str << "matches class exclusion \"" << r.className.pattern() << '"';
+ break;
+ case TypeRejection::Function:
+ case TypeRejection::Field:
+ case TypeRejection::Enum:
+ str << "matches class \"" << r.className.pattern() << "\" and \""
+ << r.pattern.pattern() << '"';
+ break;
+ case TypeRejection::ArgumentType:
+ case TypeRejection::ReturnType:
+ str << "matches class \"" << r.className.pattern() << "\" and \""
+ << needle << "\" matches \"" << r.pattern.pattern() << '"';
+ break;
+ }
+ return result;
+}
+
+// typesystem.cpp
+
+QString msgCannotFindNamespaceToExtend(const QString &name,
+ const QString &extendsPackage)
+{
+ return u"Cannot find namespace "_s + name
+ + u" in package "_s + extendsPackage;
+}
+
+QString msgExtendingNamespaceRequiresPattern(const QString &name)
+{
+ return u"Namespace "_s + name
+ + u" requires a file pattern since it extends another namespace."_s;
+}
+
+QString msgInvalidRegularExpression(const QString &pattern, const QString &why)
+{
+ return u"Invalid pattern \""_s + pattern + u"\": "_s + why;
+}
+
+QString msgNoRootTypeSystemEntry()
+{
+ return u"Type system entry appears out of order, there does not seem to be a root type system element."_s;
+}
+
+QString msgIncorrectlyNestedName(const QString &name)
+{
+ return u"Nesting types by specifying '::' is no longer supported ("_s
+ + name + u")."_s;
+}
+
+QString msgCannotFindView(const QString &viewedName, const QString &name)
+{
+ return u"Unable to find viewed type "_s + viewedName
+ + u" for "_s + name;
+}
+
+QString msgCannotFindSnippet(const QString &file, const QString &snippetLabel)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Cannot find snippet \"" << snippetLabel << "\" in "
+ << QDir::toNativeSeparators(file) << '.';
+ return result;
+}
+
+QString msgSnippetError(const QString &context, const char *what)
+{
+ return "Error processing code snippet of "_L1 + context
+ + ": "_L1 + QString::fromUtf8(what);
+}
+
+QString msgUnableToResolveTypedef(const QString &sourceType, const QString &sourceName)
+{
+ QString result;
+ QTextStream(&result) << "Unable to resolve typedef \"" << sourceType
+ << "\": Could not find a value, container, object or smart pointer type named \""
+ << sourceName << "\".";
+ return result;
+}
+
+// cppgenerator.cpp
+
+QString msgPureVirtualFunctionRemoved(const AbstractMetaFunction *f)
+{
+ QString result;
+ auto klass = f->ownerClass();
+ QTextStream str(&result);
+ str << klass->sourceLocation() << "Pure virtual method '" << klass->name()
+ << "::"<< f->minimalSignature()
+ << "' must be implemented but was completely removed on type system.";
+ return result;
+}
+
+QString msgUnknownTypeInArgumentTypeReplacement(const QString &typeReplaced,
+ const AbstractMetaFunction *f)
+{
+ QString result;
+ QTextStream str(&result);
+ if (auto klass = f->ownerClass())
+ str << klass->sourceLocation();
+ str << "Unknown type '" << typeReplaced
+ << "' used as argument type replacement in function '" << f->signature()
+ << "', the generated code may be broken.";
+ return result;
+}
+
+QString msgDuplicateBuiltInTypeEntry(const QString &name)
+{
+ return u"A type entry duplicating the built-in type \""_s
+ + name + u"\" was found. It is ignored."_s;
+}
+
+QString msgDuplicateTypeEntry(const QString &name)
+{
+ return u"Duplicate type entry: '"_s + name + u"'."_s;
+}
+
+QString msgInvalidTargetLanguageApiName(const QString &name)
+{
+ return u"Invalid target language API name \""_s
+ + name + u"\"."_s;
+}
+
+QString msgUnknownCheckFunction(const TypeEntryCPtr &t)
+{
+ return u"Unknown check function for type: '"_s
+ + t->qualifiedCppName() + u"'."_s;
+}
+
+QString msgArgumentClassNotFound(const AbstractMetaFunctionCPtr &func,
+ const TypeEntryCPtr &t)
+{
+ QString result;
+ QTextStream(&result) << "Internal Error: Class \"" << t->qualifiedCppName()
+ << "\" for \"" << func->classQualifiedSignature() << "\" not found!";
+ return result;
+}
+
+QString msgMissingCustomConversion(const TypeEntryCPtr &t)
+{
+ QString result;
+ QTextStream(&result) << "Entry \"" << t->qualifiedCppName()
+ << "\" is missing a custom conversion.";
+ return result;
+}
+
+QString msgUnknownArrayPointerConversion(const QString &s)
+{
+ return u"Warning: Falling back to pointer conversion for unknown array type \""_s
+ + s + u"\""_s;
+}
+
+QString msgMissingProjectFileMarker(const QString &name, const QByteArray &startMarker)
+{
+ return u"First line of project file \""_s + QDir::toNativeSeparators(name)
+ + u"\" must be the string \""_s + QString::fromLatin1(startMarker) + u"\"."_s;
+}
+
+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
new file mode 100644
index 000000000..5216b26a7
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/messages.h
@@ -0,0 +1,267 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MESSAGES_H
+#define MESSAGES_H
+
+#include "abstractmetalang_typedefs.h"
+#include "parser/codemodel_fwd.h"
+#include "modifications_typedefs.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QString>
+
+class EnumTypeEntry;
+class FunctionTypeEntry;
+class SmartPointerTypeEntry;
+class TypeEntry;
+class TypeInfo;
+struct TypeRejection;
+
+QT_FORWARD_DECLARE_CLASS(QDir)
+QT_FORWARD_DECLARE_CLASS(QFile)
+QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
+
+QString msgAddedFunctionInvalidArgType(const QString &addedFuncName,
+ const QStringList &typeName,
+ int pos, const QString &why,
+ const AbstractMetaClassCPtr &context = {});
+
+QString msgAddedFunctionInvalidReturnType(const QString &addedFuncName,
+ const QStringList &typeName, const QString &why,
+ const AbstractMetaClassCPtr &context = {});
+
+QString msgUnnamedArgumentDefaultExpression(const AbstractMetaClassCPtr &context,
+ int n, const QString &className,
+ const AbstractMetaFunction *f);
+
+QString msgArgumentIndexOutOfRange(const AbstractMetaFunction *func, int index);
+
+QString msgNoFunctionForModification(const AbstractMetaClassCPtr &klass,
+ const QString &signature,
+ const QString &originalSignature,
+ const QStringList &possibleSignatures,
+ const AbstractMetaFunctionCList &allFunctions);
+
+QString msgTypeModificationFailed(const QString &type, int n,
+ const AbstractMetaFunction *func,
+ const QString &why);
+
+QString msgInvalidArgumentModification(const AbstractMetaFunctionCPtr &func,
+ int argIndex);
+
+QString msgArgumentOutOfRange(int number, int minValue, int maxValue);
+
+QString msgArgumentRemovalFailed(const AbstractMetaFunction *func, int n,
+ const QString &why);
+
+QString msgClassOfEnumNotFound(const EnumTypeEntryCPtr &entry);
+
+QString msgNoEnumTypeEntry(const EnumModelItem &enumItem,
+ const QString &className);
+
+
+QString msgNoEnumTypeConflict(const EnumModelItem &enumItem,
+ const QString &className,
+ const TypeEntryCPtr &t);
+
+QString msgNamespaceNoTypeEntry(const NamespaceModelItem &item,
+ const QString &fullName);
+
+QString msgNamespaceNotFound(const QString &name);
+
+QString msgAmbiguousVaryingTypesFound(const QString &qualifiedName, const TypeEntryCList &te);
+QString msgAmbiguousTypesFound(const QString &qualifiedName, const TypeEntryCList &te);
+
+QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n,
+ const QString &why);
+
+QString msgUnmatchedReturnType(const FunctionModelItem &functionItem,
+ const QString &why);
+
+QString msgShadowingFunction(const AbstractMetaFunction *f1,
+ const AbstractMetaFunction *f2);
+
+QString msgSignalOverloaded(const AbstractMetaClassCPtr &c,
+ const AbstractMetaFunction *f);
+
+QString msgSkippingFunction(const FunctionModelItem &functionItem,
+ const QString &signature, const QString &why);
+
+QString msgSkippingField(const VariableModelItem &field, const QString &className,
+ const QString &type);
+
+QString msgTypeNotDefined(const TypeEntryCPtr &entry);
+
+QString msgGlobalFunctionNotDefined(const FunctionTypeEntryCPtr &fte,
+ const QString &signature,
+ const QStringList &candidates);
+
+QString msgStrippingArgument(const FunctionModelItem &f, int i,
+ const QString &originalSignature,
+ const ArgumentModelItem &arg,
+ const QString &reason);
+
+QString msgEnumNotDefined(const EnumTypeEntryCPtr &t);
+
+QString msgUnknownBase(const AbstractMetaClassCPtr &metaClass,
+ const QString &baseClassName);
+
+QString msgBaseNotInTypeSystem(const AbstractMetaClassCPtr &metaClass,
+ const QString &baseClassName);
+
+QString msgArrayModificationFailed(const FunctionModelItem &functionItem,
+ const QString &className,
+ const QString &errorMessage);
+
+QString msgCannotResolveEntity(const QString &name, const QString &reason);
+
+QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason);
+
+QString msgUnableToTranslateType(const QString &t, const QString &why);
+
+QString msgUnableToTranslateType(const TypeInfo &typeInfo,
+ const QString &why);
+
+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);
+
+QString msgCannotTranslateTemplateArgument(int i,
+ const TypeInfo &typeInfo,
+ const QString &why);
+
+QString msgDisallowThread(const AbstractMetaFunction *f);
+
+QString msgNamespaceToBeExtendedNotFound(const QString &namespaceName, const QString &packageName);
+
+QString msgPropertyTypeParsingFailed(const QString &name, const QString &typeName,
+ const QString &why);
+QString msgPropertyExists(const QString &className, const QString &name);
+
+QString msgFunctionVisibilityModified(const AbstractMetaClassCPtr &c,
+ const AbstractMetaFunction *f);
+
+QString msgUsingMemberClassNotFound(const AbstractMetaClassCPtr &c,
+ const QString &baseClassName,
+ const QString &memberName);
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const char *what, const QString &name,
+ const QString &query = {});
+
+QString msgFallbackForDocumentation(const QString &fileName,
+ const char *what, const QString &name,
+ const QString &query = {});
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaFunction *function,
+ const QString &query = {});
+
+QString msgFallbackForDocumentation(const QString &fileName,
+ const AbstractMetaFunction *function,
+ const QString &query = {});
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClassCPtr &metaClass,
+ const AbstractMetaEnum &e,
+ const QString &query = {});
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClassCPtr &metaClass,
+ const AbstractMetaField &f,
+ const QString &query);
+
+QString msgXpathDocModificationError(const DocModificationList& mods,
+ const QString &what);
+
+QString msgCannotOpenForReading(const QFile &f);
+
+QString msgCannotOpenForWriting(const QFile &f);
+
+QString msgWriteFailed(const QFile &f, qsizetype size);
+
+QString msgCannotUseEnumAsInt(const QString &name);
+
+QString msgCannotFindSmartPointerGetter(const SmartPointerTypeEntryCPtr &);
+
+QString msgCannotFindSmartPointerMethod(const SmartPointerTypeEntryCPtr &te, const QString &m);
+
+QString msgMethodNotFound(const AbstractMetaClassCPtr &klass, const QString &name);
+
+QString msgLeftOverArguments(const QString &remainingArgs, const QStringList &argV);
+
+QString msgInvalidVersion(const QString &package, const QString &version);
+
+QString msgCannotFindNamespaceToExtend(const QString &name,
+ const QString &extendsPackage);
+
+QString msgExtendingNamespaceRequiresPattern(const QString &name);
+
+QString msgInvalidRegularExpression(const QString &pattern, const QString &why);
+
+QString msgNoRootTypeSystemEntry();
+
+QString msgIncorrectlyNestedName(const QString &name);
+
+QString msgCannotFindView(const QString &viewedName, const QString &name);
+
+QString msgCannotFindSnippet(const QString &file, const QString &snippetLabel);
+QString msgSnippetError(const QString &context, const char *what);
+QString msgUnableToResolveTypedef(const QString &sourceType, const QString &sourceName);
+
+QString msgCyclicDependency(const QString &funcName, const QString &graphName,
+ const AbstractMetaFunctionCList &cyclic,
+ const AbstractMetaFunctionCList &involvedConversions);
+
+QString msgClassNotFound(const TypeEntryCPtr &t);
+
+QString msgEnclosingClassNotFound(const TypeEntryCPtr &t);
+
+QString msgUnknownOperator(const AbstractMetaFunction *func);
+
+QString msgWrongIndex(const char *varName, const QString &capture,
+ const AbstractMetaFunction *func);
+
+QString msgCannotFindType(const QString &type, const QString &variable,
+ const QString &why);
+
+QString msgCannotBuildMetaType(const QString &s);
+
+QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type,
+ const QString &why = QString());
+
+QString msgRejectReason(const TypeRejection &r, const QString &needle = QString());
+
+QString msgPureVirtualFunctionRemoved(const AbstractMetaFunction *f);
+
+QString msgUnknownTypeInArgumentTypeReplacement(const QString &typeReplaced,
+ const AbstractMetaFunction *f);
+
+QString msgDuplicateBuiltInTypeEntry(const QString &name);
+QString msgDuplicateTypeEntry(const QString &name);
+QString msgInvalidTargetLanguageApiName(const QString &name);
+
+QString msgUnknownCheckFunction(const TypeEntryCPtr &t);
+
+QString msgArgumentClassNotFound(const AbstractMetaFunctionCPtr &func,
+ const TypeEntryCPtr &t);
+
+QString msgMissingCustomConversion(const TypeEntryCPtr &t);
+
+QString msgUnknownArrayPointerConversion(const QString &s);
+
+QString msgMissingProjectFileMarker(const QString &name, const QByteArray &startMarker);
+
+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/modifications.cpp b/sources/shiboken6/ApiExtractor/modifications.cpp
new file mode 100644
index 000000000..d876e8035
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/modifications.cpp
@@ -0,0 +1,672 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "modifications.h"
+#include "codesnip.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QRegularExpression>
+
+#include <algorithm>
+#include <limits>
+
+using namespace Qt::StringLiterals;
+
+// ---------------------- FieldModification
+
+class FieldModificationData : public QSharedData
+{
+public:
+ QString m_name;
+ QString m_renamedToName;
+ bool m_readable = true;
+ bool m_writable = true;
+ bool m_removed = false;
+ bool m_opaqueContainer = false;
+ TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified;
+};
+
+FieldModification::FieldModification() : d(new FieldModificationData)
+{
+}
+
+FieldModification::FieldModification(const FieldModification &) = default;
+FieldModification &FieldModification::operator=(const FieldModification &) = default;
+FieldModification::FieldModification(FieldModification &&) noexcept = default;
+FieldModification &FieldModification::operator=(FieldModification &&) noexcept = default;
+FieldModification::~FieldModification() = default;
+
+QString FieldModification::name() const
+{
+ return d->m_name;
+}
+
+void FieldModification::setName(const QString &value)
+{
+ if (d->m_name != value)
+ d->m_name = value;
+}
+
+bool FieldModification::isRenameModifier() const
+{
+ return !d->m_renamedToName.isEmpty();
+}
+
+QString FieldModification::renamedToName() const
+{
+ return d->m_renamedToName;
+}
+
+void FieldModification::setRenamedToName(const QString &value)
+{
+ if (d->m_renamedToName != value)
+ d->m_renamedToName = value;
+}
+
+bool FieldModification::isReadable() const
+{
+ return d->m_readable;
+}
+
+void FieldModification::setReadable(bool e)
+{
+ if (d->m_readable != e)
+ d->m_readable = e;
+}
+
+bool FieldModification::isWritable() const
+{
+ return d->m_writable;
+}
+
+void FieldModification::setWritable(bool e)
+{
+ if (d->m_writable != e)
+ d->m_writable = e;
+}
+
+bool FieldModification::isRemoved() const
+{
+ return d->m_removed;
+}
+
+void FieldModification::setRemoved(bool r)
+{
+ if (d->m_removed != r)
+ d->m_removed = r;
+}
+
+bool FieldModification::isOpaqueContainer() const
+{
+ return d->m_opaqueContainer;
+}
+
+void FieldModification::setOpaqueContainer(bool r)
+{
+ if (d->m_opaqueContainer != r)
+ d->m_opaqueContainer = r;
+}
+
+TypeSystem::SnakeCase FieldModification::snakeCase() const
+{
+ return d->snakeCase;
+}
+
+void FieldModification::setSnakeCase(TypeSystem::SnakeCase s)
+{
+ if (d->snakeCase != s)
+ d->snakeCase = s;
+}
+
+// Remove the parameter names enclosed in '@' from an added function signature
+// so that it matches the C++ type signature.
+static QString removeParameterNames(QString signature)
+{
+ while (true) {
+ const auto ampPos = signature.indexOf(u'@');
+ if (ampPos == -1)
+ break;
+ const auto closingAmpPos = signature.indexOf(u'@', ampPos + 1);
+ if (closingAmpPos == -1)
+ break;
+ signature.remove(ampPos, closingAmpPos - ampPos + 1);
+ }
+ return signature;
+}
+
+DocModification::DocModification(const QString &xpath, const QString &signature) :
+ m_xpath(xpath), m_signature(removeParameterNames(signature))
+{
+}
+
+DocModification::DocModification(TypeSystem::DocModificationMode mode, const QString &signature) :
+ m_signature(removeParameterNames(signature)), m_mode(mode)
+{
+}
+
+void DocModification::setCode(const QString &code)
+{
+ m_code = CodeSnipAbstract::fixSpaces(code);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const ReferenceCount &r)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "ReferenceCount(" << r.varName << ", action=" << r.action << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const CodeSnip &s)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ const auto size = s.codeList.size();
+ d << "CodeSnip(language=" << s.language << ", position=" << s.position
+ << ", fragments[" << size << "]=";
+ for (qsizetype i = 0; i < size; ++i) {
+ const auto &f = s.codeList.at(i);
+ if (i)
+ d << ", ";
+ d << '#' << i << ' ';
+ if (!f.instance()) {
+ d << '"';
+ const QString &code = f.code();
+ const auto lines = QStringView{code}.split(u'\n');
+ for (qsizetype i = 0, size = lines.size(); i < size; ++i) {
+ if (i)
+ d << "\\n";
+ d << lines.at(i).trimmed();
+ }
+ d << '"';
+ } else {
+ d << "template=\"" << f.instance()->name() << '"';
+ }
+ }
+ d << ')';
+ return d;
+}
+
+class ArgumentModificationData : public QSharedData
+{
+public:
+ ArgumentModificationData(int idx = -1) : index(idx),
+ removedDefaultExpression(false), removed(false),
+ noNullPointers(false), resetAfterUse(false), array(false)
+ {}
+
+ QList<ReferenceCount> referenceCounts;
+ QString modified_type;
+ QString pyiType;
+ QString replacedDefaultExpression;
+ TypeSystem::Ownership m_targetOwnerShip = TypeSystem::UnspecifiedOwnership;
+ TypeSystem::Ownership m_nativeOwnerShip = TypeSystem::UnspecifiedOwnership;
+ CodeSnipList conversion_rules;
+ ArgumentOwner owner;
+ QString renamed_to;
+ int index = -1;
+ uint removedDefaultExpression : 1;
+ uint removed : 1;
+ uint noNullPointers : 1;
+ uint resetAfterUse : 1;
+ uint array : 1;
+};
+
+ArgumentModification::ArgumentModification() : d(new ArgumentModificationData)
+{
+}
+
+ArgumentModification::ArgumentModification(int idx) : d(new ArgumentModificationData(idx))
+{
+}
+
+ArgumentModification::ArgumentModification(const ArgumentModification &) = default;
+ArgumentModification &ArgumentModification::operator=(const ArgumentModification &) = default;
+ArgumentModification::ArgumentModification(ArgumentModification &&) noexcept = default;
+ArgumentModification &ArgumentModification::operator=(ArgumentModification &&) noexcept = default;
+ArgumentModification::~ArgumentModification() = default;
+
+const QString &ArgumentModification::modifiedType() const
+{
+ return d->modified_type;
+}
+
+void ArgumentModification::setModifiedType(const QString &value)
+{
+ if (d->modified_type != value)
+ d->modified_type = value;
+}
+
+bool ArgumentModification::isTypeModified() const
+{
+ return !d->modified_type.isEmpty();
+}
+
+QString ArgumentModification::pyiType() const
+{
+ return d->pyiType;
+}
+
+void ArgumentModification::setPyiType(const QString &value)
+{
+ if (d->pyiType != value)
+ d->pyiType = value;
+}
+
+QString ArgumentModification::replacedDefaultExpression() const
+{
+ return d->replacedDefaultExpression;
+}
+
+void ArgumentModification::setReplacedDefaultExpression(const QString &value)
+{
+ if (d->replacedDefaultExpression != value)
+ d->replacedDefaultExpression = value;
+}
+
+TypeSystem::Ownership ArgumentModification::targetOwnerShip() const
+{
+ return d->m_targetOwnerShip;
+}
+
+void ArgumentModification::setTargetOwnerShip(TypeSystem::Ownership o)
+{
+ if (o != d->m_targetOwnerShip)
+ d->m_targetOwnerShip = o;
+}
+
+TypeSystem::Ownership ArgumentModification::nativeOwnership() const
+{
+ return d->m_nativeOwnerShip;
+}
+
+void ArgumentModification::setNativeOwnership(TypeSystem::Ownership o)
+{
+ if (o != d->m_nativeOwnerShip)
+ d->m_nativeOwnerShip = o;
+}
+
+const CodeSnipList &ArgumentModification::conversionRules() const
+{
+ return d->conversion_rules;
+}
+
+CodeSnipList &ArgumentModification::conversionRules()
+{
+ return d->conversion_rules;
+}
+
+ArgumentOwner ArgumentModification::owner() const
+{
+ return d->owner;
+}
+
+void ArgumentModification::setOwner(const ArgumentOwner &value)
+{
+ d->owner = value;
+}
+
+QString ArgumentModification::renamedToName() const
+{
+ return d->renamed_to;
+}
+
+void ArgumentModification::setRenamedToName(const QString &value)
+{
+ if (d->renamed_to != value)
+ d->renamed_to = value;
+}
+
+int ArgumentModification::index() const
+{
+ return d->index;
+}
+
+void ArgumentModification::setIndex(int value)
+{
+ if (d->index != value)
+ d->index = value;
+}
+
+bool ArgumentModification::removedDefaultExpression() const
+{
+ return d->removedDefaultExpression;
+}
+
+void ArgumentModification::setRemovedDefaultExpression(const uint &value)
+{
+ if (d->removedDefaultExpression != value)
+ d->removedDefaultExpression = value;
+}
+
+bool ArgumentModification::isRemoved() const
+{
+ return d->removed;
+}
+
+void ArgumentModification::setRemoved(bool value)
+{
+ if (d->removed != value)
+ d->removed = value;
+}
+
+bool ArgumentModification::noNullPointers() const
+{
+ return d->noNullPointers;
+}
+
+void ArgumentModification::setNoNullPointers(bool value)
+{
+ if (d->noNullPointers != value)
+ d->noNullPointers = value;
+}
+
+bool ArgumentModification::resetAfterUse() const
+{
+ return d->resetAfterUse;
+}
+
+void ArgumentModification::setResetAfterUse(bool value)
+{
+ if (d->resetAfterUse != value)
+ d->resetAfterUse = value;
+}
+
+bool ArgumentModification::isArray() const
+{
+ return d->array;
+}
+
+void ArgumentModification::setArray(bool value)
+{
+ if (d->array != value)
+ d->array = value;
+}
+
+const QList<ReferenceCount> &ArgumentModification::referenceCounts() const
+{
+ return d->referenceCounts;
+}
+
+void ArgumentModification::addReferenceCount(const ReferenceCount &value)
+{
+ d->referenceCounts.append(value);
+}
+
+class FunctionModificationData : public QSharedData
+{
+public:
+ QString renamedToName;
+ FunctionModification::Modifiers modifiers;
+ CodeSnipList m_snips;
+ QList<ArgumentModification> m_argument_mods;
+ QString m_signature;
+ QString m_originalSignature;
+ QRegularExpression m_signaturePattern;
+ int m_overloadNumber = TypeSystem::OverloadNumberUnset;
+ bool removed = false;
+ TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified;
+ TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+ TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified;
+};
+
+FunctionModification::FunctionModification() : d(new FunctionModificationData)
+{
+}
+
+FunctionModification::FunctionModification(const FunctionModification &) = default;
+FunctionModification &FunctionModification::operator=(const FunctionModification &) = default;
+FunctionModification::FunctionModification(FunctionModification &&) noexcept = default;
+FunctionModification &FunctionModification::operator=(FunctionModification &&) noexcept = default;
+FunctionModification::~FunctionModification() = default;
+
+void FunctionModification::formatDebug(QDebug &debug) const
+{
+ if (d->m_signature.isEmpty())
+ debug << "pattern=\"" << d->m_signaturePattern.pattern();
+ else
+ debug << "signature=\"" << d->m_signature;
+ debug << "\", modifiers=" << d->modifiers;
+ if (d->removed)
+ debug << ", removed";
+ if (!d->renamedToName.isEmpty())
+ debug << ", renamedToName=\"" << d->renamedToName << '"';
+ if (d->m_allowThread != TypeSystem::AllowThread::Unspecified)
+ debug << ", allowThread=" << int(d->m_allowThread);
+ if (d->m_exceptionHandling != TypeSystem::ExceptionHandling::Unspecified)
+ debug << ", exceptionHandling=" << int(d->m_exceptionHandling);
+ if (!d->m_snips.isEmpty())
+ debug << ", snips=(" << d->m_snips << ')';
+ if (!d->m_argument_mods.isEmpty())
+ debug << ", argument_mods=(" << d->m_argument_mods << ')';
+}
+
+QString FunctionModification::renamedToName() const
+{
+ return d->renamedToName;
+}
+
+void FunctionModification::setRenamedToName(const QString &value)
+{
+ if (d->renamedToName != value)
+ d->renamedToName = value;
+}
+
+FunctionModification::Modifiers FunctionModification::modifiers() const
+{
+ return d->modifiers;
+}
+
+void FunctionModification::setModifiers(Modifiers m)
+{
+ if (d->modifiers != m)
+ d->modifiers = m;
+}
+
+void FunctionModification::setModifierFlag(FunctionModification::ModifierFlag f)
+{
+ auto newMods = d->modifiers | f;
+ if (d->modifiers != newMods)
+ d->modifiers = newMods;
+}
+
+void FunctionModification::clearModifierFlag(ModifierFlag f)
+{
+ auto newMods = d->modifiers & ~f;
+ if (d->modifiers != newMods)
+ d->modifiers = newMods;
+}
+
+bool FunctionModification::isRemoved() const
+{
+ return d->removed;
+}
+
+void FunctionModification::setRemoved(bool r)
+{
+ if (d->removed != r)
+ d->removed = r;
+}
+
+const QList<ArgumentModification> &FunctionModification::argument_mods() const
+{
+ return d->m_argument_mods;
+}
+
+QList<ArgumentModification> &FunctionModification::argument_mods()
+{
+ return d->m_argument_mods;
+}
+
+void FunctionModification::setArgument_mods(const QList<ArgumentModification> &argument_mods)
+{
+ d->m_argument_mods = argument_mods;
+}
+
+TypeSystem::SnakeCase FunctionModification::snakeCase() const
+{
+ return d->snakeCase;
+}
+
+void FunctionModification::setSnakeCase(TypeSystem::SnakeCase s)
+{
+ if (d->snakeCase != s)
+ d->snakeCase = s;
+}
+
+const CodeSnipList &FunctionModification::snips() const
+{
+ return d->m_snips;
+}
+
+CodeSnipList &FunctionModification::snips()
+{
+ return d->m_snips;
+}
+
+void FunctionModification::appendSnip(const CodeSnip &snip)
+{
+ d->m_snips.append(snip);
+}
+
+void FunctionModification::setSnips(const CodeSnipList &snips)
+{
+ d->m_snips = snips;
+}
+
+// ---------------------- FunctionModification
+FunctionModification::AllowThread FunctionModification::allowThread() const
+{
+ return d->m_allowThread;
+}
+
+void FunctionModification::setAllowThread(FunctionModification::AllowThread allow)
+{
+ if (d->m_allowThread != allow)
+ d->m_allowThread = allow;
+}
+
+bool FunctionModification::matches(const QStringList &functionSignatures) const
+{
+ if (!d->m_signature.isEmpty())
+ return functionSignatures.contains(d->m_signature);
+
+ for (const auto &s : functionSignatures) {
+ if (d->m_signaturePattern.match(s).hasMatch())
+ return true;
+ }
+ return false;
+}
+
+bool FunctionModification::setSignature(const QString &s, QString *errorMessage)
+{
+ if (s.startsWith(u'^')) {
+ d->m_signaturePattern.setPattern(s);
+ if (!d->m_signaturePattern.isValid()) {
+ if (errorMessage) {
+ *errorMessage = u"Invalid signature pattern: \""_s
+ + s + u"\": "_s + d->m_signaturePattern.errorString();
+ }
+ return false;
+ }
+ } else {
+ d->m_signature = s;
+ }
+ return true;
+}
+
+QString FunctionModification::signature() const
+{
+ return d->m_signature.isEmpty() ? d->m_signaturePattern.pattern() : d->m_signature;
+}
+
+void FunctionModification::setOriginalSignature(const QString &s)
+{
+ if (d->m_originalSignature != s)
+ d->m_originalSignature = s;
+}
+
+QString FunctionModification::originalSignature() const
+{
+ return d->m_originalSignature;
+}
+
+TypeSystem::ExceptionHandling FunctionModification::exceptionHandling() const
+{
+ return d->m_exceptionHandling;
+}
+
+void FunctionModification::setExceptionHandling(TypeSystem::ExceptionHandling e)
+{
+ if (d->m_exceptionHandling != e)
+ d->m_exceptionHandling = e;
+}
+
+int FunctionModification::overloadNumber() const
+{
+ return d->m_overloadNumber;
+}
+
+void FunctionModification::setOverloadNumber(int overloadNumber)
+{
+ d->m_overloadNumber = overloadNumber;
+}
+
+QDebug operator<<(QDebug d, const ArgumentOwner &a)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "ArgumentOwner(index=" << a.index << ", action=" << a.action << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const ArgumentModification &a)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "ArgumentModification(index=" << a.index();
+ if (a.removedDefaultExpression())
+ d << ", removedDefaultExpression";
+ if (a.isRemoved())
+ d << ", removed";
+ if (a.noNullPointers())
+ d << ", noNullPointers";
+ if (a.isArray())
+ d << ", array";
+ if (!a.referenceCounts().isEmpty())
+ d << ", referenceCounts=" << a.referenceCounts();
+ if (!a.modifiedType().isEmpty())
+ d << ", modified_type=\"" << a.modifiedType() << '"';
+ if (!a.replacedDefaultExpression().isEmpty())
+ d << ", replacedDefaultExpression=\"" << a.replacedDefaultExpression() << '"';
+ if (a.targetOwnerShip() != TypeSystem::UnspecifiedOwnership)
+ d << ", target ownership=" << a.targetOwnerShip();
+ if (a.nativeOwnership() != TypeSystem::UnspecifiedOwnership)
+ d << ", native ownership=" << a.nativeOwnership();
+ if (!a.renamedToName().isEmpty())
+ d << ", renamed_to=\"" << a.renamedToName() << '"';
+ const auto &rules = a.conversionRules();
+ if (!rules.isEmpty())
+ d << ", conversionRules[" << rules.size() << "]=" << rules;
+ d << ", owner=" << a.owner() << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const FunctionModification &fm)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "FunctionModification(";
+ fm.formatDebug(d);
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/modifications.h b/sources/shiboken6/ApiExtractor/modifications.h
new file mode 100644
index 000000000..27a38f1aa
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/modifications.h
@@ -0,0 +1,342 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MODIFICATIONS_H
+#define MODIFICATIONS_H
+
+#include "typesystem_enums.h"
+#include "modifications_typedefs.h"
+
+#include <QtCore/QList>
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QString>
+
+class ArgumentModificationData;
+class CodeSnip;
+class FunctionModificationData;
+class ModificationData;
+class FieldModificationData;
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+QT_END_NAMESPACE
+
+struct ReferenceCount
+{
+ enum Action { // 0x01 - 0xff
+ Add = 0x01,
+ AddAll = 0x02,
+ Remove = 0x04,
+ Set = 0x08,
+ Ignore = 0x10,
+
+ ActionsMask = 0xff,
+
+ Padding = 0xffffffff
+ };
+
+ QString varName;
+ Action action;
+};
+
+struct ArgumentOwner
+{
+ enum Action {
+ Invalid = 0x00,
+ Add = 0x01,
+ Remove = 0x02
+ };
+ enum {
+ InvalidIndex = -2,
+ ThisIndex = -1,
+ ReturnIndex = 0,
+ FirstArgumentIndex = 1
+ };
+
+ Action action = Invalid;
+ int index = InvalidIndex;
+};
+
+class ArgumentModification
+{
+public:
+ ArgumentModification();
+ explicit ArgumentModification(int idx);
+ ArgumentModification(const ArgumentModification &);
+ ArgumentModification &operator=(const ArgumentModification &);
+ ArgumentModification(ArgumentModification &&) noexcept;
+ ArgumentModification &operator=(ArgumentModification &&) noexcept;
+ ~ArgumentModification();
+
+ // Reference count flags for this argument
+ const QList<ReferenceCount> &referenceCounts() const;
+ void addReferenceCount(const ReferenceCount &value);
+
+ // The text given for the new type of the argument
+ const QString &modifiedType() const;
+ void setModifiedType(const QString &value);
+ bool isTypeModified() const;
+
+ QString pyiType() const;
+ void setPyiType(const QString &value);
+
+ // The text of the new default expression of the argument
+ QString replacedDefaultExpression() const;
+ void setReplacedDefaultExpression(const QString &value);
+
+ // The new definition of ownership for a specific argument
+
+ TypeSystem::Ownership targetOwnerShip() const;
+ void setTargetOwnerShip(TypeSystem::Ownership o);
+ TypeSystem::Ownership nativeOwnership() const;
+ void setNativeOwnership(TypeSystem::Ownership o);
+
+ // Different conversion rules
+ const QList<CodeSnip> &conversionRules() const;
+ QList<CodeSnip> &conversionRules();
+
+ // QObject parent(owner) of this argument
+ ArgumentOwner owner() const;
+ void setOwner(const ArgumentOwner &value);
+
+ // New name
+ QString renamedToName() const;
+ void setRenamedToName(const QString &value);
+
+ int index() const;
+ void setIndex(int value);
+
+ bool removedDefaultExpression() const;
+ void setRemovedDefaultExpression(const uint &value);
+
+ bool isRemoved() const;
+ void setRemoved(bool value);
+
+ bool noNullPointers() const;
+ void setNoNullPointers(bool value);
+
+ bool resetAfterUse() const;
+ void setResetAfterUse(bool value);
+
+ // consider "int*" to be "int[]"
+ bool isArray() const;
+ void setArray(bool value);
+
+private:
+ QSharedDataPointer<ArgumentModificationData> d;
+};
+
+class FunctionModification
+{
+public:
+ using AllowThread = TypeSystem::AllowThread;
+
+ FunctionModification();
+ FunctionModification(const FunctionModification &);
+ FunctionModification &operator=(const FunctionModification &);
+ FunctionModification(FunctionModification &&) noexcept;
+ FunctionModification &operator=(FunctionModification &&) noexcept;
+ ~FunctionModification();
+
+ enum ModifierFlag {
+ Private = 0x0001,
+ Protected = 0x0002,
+ Public = 0x0004,
+ AccessModifierMask = 0x000f,
+
+ Final = 0x0010,
+ NonFinal = 0x0020,
+ FinalMask = Final | NonFinal,
+
+ Readable = 0x0100,
+ Writable = 0x0200,
+
+ CodeInjection = 0x1000,
+ Rename = 0x2000,
+ Deprecated = 0x4000,
+ Undeprecated = 0x8000,
+ ReplaceExpression = 0x10000
+ };
+
+ Q_DECLARE_FLAGS(Modifiers, ModifierFlag);
+
+ QString renamedToName() const;
+ void setRenamedToName(const QString &value);
+
+ Modifiers modifiers() const;
+ void setModifiers(Modifiers m);
+ void setModifierFlag(ModifierFlag f);
+ void clearModifierFlag(ModifierFlag f);
+ bool isRemoved() const;
+ void setRemoved(bool r);
+
+ bool isAccessModifier() const
+ {
+ return (modifiers() & AccessModifierMask) != 0;
+ }
+ Modifiers accessModifier() const
+ {
+ return modifiers() & AccessModifierMask;
+ }
+ bool isPrivate() const
+ {
+ return accessModifier() == Private;
+ }
+ bool isProtected() const
+ {
+ return accessModifier() == Protected;
+ }
+ bool isPublic() const
+ {
+ return accessModifier() == Public;
+ }
+ bool isFinal() const
+ {
+ return modifiers().testFlag(Final);
+ }
+ bool isNonFinal() const
+ {
+ return modifiers().testFlag(NonFinal);
+ }
+
+ bool isDeprecated() const
+ {
+ return modifiers().testFlag(Deprecated);
+ }
+
+ bool isRenameModifier() const
+ {
+ return modifiers().testFlag(Rename);
+ }
+
+ bool isRemoveModifier() const { return isRemoved(); }
+
+
+
+ bool isCodeInjection() const
+ {
+ return modifiers().testFlag(CodeInjection);
+ }
+
+ AllowThread allowThread() const;
+ void setAllowThread(AllowThread allow);
+
+ bool matches(const QStringList &functionSignatures) const;
+
+ bool setSignature(const QString &s, QString *errorMessage = nullptr);
+ QString signature() const;
+
+ void setOriginalSignature(const QString &s);
+ QString originalSignature() const;
+
+ TypeSystem::ExceptionHandling exceptionHandling() const;
+ void setExceptionHandling(TypeSystem::ExceptionHandling e);
+
+ int overloadNumber() const;
+ void setOverloadNumber(int overloadNumber);
+
+ const QList<CodeSnip> &snips() const;
+ QList<CodeSnip> &snips();
+ void appendSnip(const CodeSnip &snip);
+ void setSnips(const QList<CodeSnip> &snips);
+
+ const QList<ArgumentModification> &argument_mods() const;
+ QList<ArgumentModification> &argument_mods();
+ void setArgument_mods(const QList<ArgumentModification> &argument_mods);
+
+ TypeSystem::SnakeCase snakeCase() const;
+ void setSnakeCase(TypeSystem::SnakeCase s);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+private:
+ QSharedDataPointer<FunctionModificationData> d;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionModification::Modifiers)
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const ReferenceCount &);
+QDebug operator<<(QDebug d, const CodeSnip &s);
+QDebug operator<<(QDebug d, const ArgumentOwner &a);
+QDebug operator<<(QDebug d, const ArgumentModification &a);
+QDebug operator<<(QDebug d, const FunctionModification &fm);
+#endif
+
+class FieldModification
+{
+public:
+ FieldModification();
+ FieldModification(const FieldModification &);
+ FieldModification &operator=(const FieldModification &);
+ FieldModification(FieldModification &&) noexcept;
+ FieldModification &operator=(FieldModification &&) noexcept;
+ ~FieldModification();
+
+ QString name() const;
+ void setName(const QString &value);
+
+ bool isRenameModifier() const;
+ QString renamedToName() const;
+ void setRenamedToName(const QString &value);
+
+ bool isReadable() const;
+ void setReadable(bool e);
+
+ bool isWritable() const;
+ void setWritable(bool e);
+
+ bool isRemoved() const;
+ void setRemoved(bool r);
+
+ bool isOpaqueContainer() const;
+ void setOpaqueContainer(bool r);
+
+ TypeSystem::SnakeCase snakeCase() const;
+ void setSnakeCase(TypeSystem::SnakeCase s);
+
+private:
+ QSharedDataPointer<FieldModificationData> d;
+};
+
+class DocModification
+{
+public:
+ DocModification() = default;
+ explicit DocModification(const QString& xpath, const QString& signature);
+ explicit DocModification(TypeSystem::DocModificationMode mode, const QString& signature);
+
+ void setCode(const QString& code);
+ void setCode(QStringView code) { setCode(code.toString()); }
+
+ QString code() const
+ {
+ return m_code;
+ }
+ QString xpath() const
+ {
+ return m_xpath;
+ }
+ QString signature() const
+ {
+ return m_signature;
+ }
+ TypeSystem::DocModificationMode mode() const
+ {
+ return m_mode;
+ }
+
+ TypeSystem::Language format() const { return m_format; }
+ void setFormat(TypeSystem::Language f) { m_format = f; }
+
+private:
+ QString m_code;
+ QString m_xpath;
+ QString m_signature;
+ TypeSystem::DocModificationMode m_mode = TypeSystem::DocModificationXPathReplace;
+ TypeSystem::Language m_format = TypeSystem::NativeCode;
+};
+
+#endif // MODIFICATIONS_H
diff --git a/sources/shiboken6/ApiExtractor/modifications_typedefs.h b/sources/shiboken6/ApiExtractor/modifications_typedefs.h
new file mode 100644
index 000000000..3b86c55d3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/modifications_typedefs.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MODIFICATIONS_TYPEDEFS_H
+#define MODIFICATIONS_TYPEDEFS_H
+
+#include <QtCore/QList>
+
+#include <memory>
+
+class CodeSnip;
+class DocModification;
+
+struct AddedFunction;
+class FieldModification;
+class FunctionModification;
+
+using AddedFunctionPtr = std::shared_ptr<AddedFunction>;
+using AddedFunctionList = QList<AddedFunctionPtr>;
+using CodeSnipList = QList<CodeSnip>;
+using DocModificationList = QList<DocModification>;
+using FieldModificationList = QList<FieldModification>;
+using FunctionModificationList = QList<FunctionModification>;
+
+#endif // MODIFICATIONS_TYPEDEFS_H
diff --git a/sources/shiboken6/ApiExtractor/namespacetypeentry.h b/sources/shiboken6/ApiExtractor/namespacetypeentry.h
new file mode 100644
index 000000000..6ffd38430
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/namespacetypeentry.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef NAMESPACETYPEENTRY_H
+#define NAMESPACETYPEENTRY_H
+
+#include "complextypeentry.h"
+
+class NamespaceTypeEntryPrivate;
+
+class NamespaceTypeEntry : public ComplexTypeEntry
+{
+public:
+ explicit NamespaceTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ TypeEntry *clone() const override;
+
+ NamespaceTypeEntryCPtr extends() const;
+ void setExtends(const NamespaceTypeEntryCPtr &e);
+
+ const QRegularExpression &filePattern() const; // restrict files
+ void setFilePattern(const QRegularExpression &r);
+
+ bool hasPattern() const;
+
+ bool matchesFile(const QString &needle) const;
+
+ bool isVisible() const;
+ void setVisibility(TypeSystem::Visibility v);
+
+ // C++ 11 inline namespace, from code model
+ bool isInlineNamespace() const;
+ void setInlineNamespace(bool i);
+
+ static bool isVisibleScope(const TypeEntryCPtr &e);
+ static bool isVisibleScope(const TypeEntry *e);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+ // Whether to generate "using namespace" into wrapper
+ bool generateUsing() const;
+ void setGenerateUsing(bool generateUsing);
+
+protected:
+ explicit NamespaceTypeEntry(NamespaceTypeEntryPrivate *d);
+};
+
+#endif // NAMESPACETYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/objecttypeentry.h b/sources/shiboken6/ApiExtractor/objecttypeentry.h
new file mode 100644
index 000000000..da91e8ff4
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/objecttypeentry.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OBJECTTYPEENTRY_H
+#define OBJECTTYPEENTRY_H
+
+#include "complextypeentry.h"
+
+class ObjectTypeEntry : public ComplexTypeEntry
+{
+public:
+ explicit ObjectTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ TypeEntry *clone() const override;
+
+protected:
+ explicit ObjectTypeEntry(ComplexTypeEntryPrivate *d);
+};
+
+#endif // OBJECTTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/optionsparser.cpp b/sources/shiboken6/ApiExtractor/optionsparser.cpp
new file mode 100644
index 000000000..f2e64c7e4
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/optionsparser.cpp
@@ -0,0 +1,232 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "optionsparser.h"
+#include "messages.h"
+#include "exception.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+
+using namespace Qt::StringLiterals;
+
+template <class Stream> void formatBoolOption(Stream &s, const BoolOption &bo)
+{
+ switch (bo.source) {
+ case OptionSource::CommandLine:
+ s << "--";
+ break;
+ case OptionSource::CommandLineSingleDash:
+ s << '-';
+ break;
+ default:
+ break;
+ }
+ s << bo.option;
+ if (bo.source == OptionSource::ProjectFile)
+ s << " (project)";
+}
+
+template <class Stream> void formatOptionValue(Stream &s, const OptionValue &ov)
+{
+ switch (ov.source) {
+ case OptionSource::CommandLine:
+ s << "--";
+ break;
+ case OptionSource::CommandLineSingleDash:
+ s << '-';
+ break;
+ default:
+ break;
+ }
+ s << ov.option << '=' << ov.value;
+ if (ov.source == OptionSource::ProjectFile)
+ s << " (project)";
+}
+
+QTextStream &operator<<(QTextStream &s, const BoolOption &bo)
+{
+ formatBoolOption(s, bo);
+ return s;
+}
+
+QTextStream &operator<<(QTextStream &s, const OptionValue &ov)
+{
+ formatOptionValue(s, ov);
+ return s;
+}
+
+QDebug operator<<(QDebug debug, const BoolOption &bo)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ formatBoolOption(debug, bo);
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const OptionValue &v)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ formatOptionValue(debug, v);
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const Options &v)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Options(";
+ if (!v.boolOptions.isEmpty())
+ debug << "bools=" << v.boolOptions;
+ if (!v.valueOptions.isEmpty())
+ debug << ", option values=" << v.valueOptions;
+ if (!v.positionalArguments.isEmpty())
+ debug << ", pos=" << v.positionalArguments;
+ debug << ')';
+ return debug;
+}
+
+QTextStream &operator<<(QTextStream &s, const OptionDescription &od)
+{
+ if (!od.name.startsWith(u'-'))
+ s << "--";
+ s << od.name;
+ if (od.description.isEmpty()) { // For formatting {{"-s", ""}, {"--short", "descr"}}
+ s << ", ";
+ } else {
+ s << '\n';
+ const auto lines = QStringView{od.description}.split(u'\n');
+ for (const auto &line : lines)
+ s << " " << line << '\n';
+ s << '\n';
+ }
+ return s;
+}
+
+QTextStream &operator<<(QTextStream &s, const OptionDescriptions &options)
+{
+ s.setFieldAlignment(QTextStream::AlignLeft);
+ for (const auto &od : options)
+ s << od;
+ return s;
+}
+
+OptionsParser::OptionsParser() noexcept = default;
+OptionsParser::~OptionsParser() = default;
+
+const QString &OptionsParser::pathSyntax()
+{
+ static const QString result =
+ u"<path>["_s + QDir::listSeparator() + u"<path>"_s
+ + QDir::listSeparator() + u"...]"_s;
+ return result;
+}
+
+bool OptionsParser::handleBoolOption(const QString &, OptionSource)
+{
+ return false;
+}
+
+bool OptionsParser::handleOption(const QString &, const QString &, OptionSource)
+{
+ return false;
+}
+
+void OptionsParser::process(Options *o)
+{
+ for (auto i = o->boolOptions.size() - 1; i >= 0; --i) {
+ const auto &opt = o->boolOptions.at(i);
+ if (handleBoolOption(opt.option, opt.source))
+ o->boolOptions.removeAt(i);
+ }
+ for (auto i = o->valueOptions.size() - 1; i >= 0; --i) {
+ const auto &opt = o->valueOptions.at(i);
+ if (handleOption(opt.option, opt.value, opt.source))
+ o->valueOptions.removeAt(i);
+ }
+}
+
+bool OptionsParserList::handleBoolOption(const QString &key, OptionSource source)
+{
+ for (const auto &p : std::as_const(m_parsers)) {
+ if (p->handleBoolOption(key, source))
+ return true;
+ }
+ return false;
+}
+
+bool OptionsParserList::handleOption(const QString &key, const QString &value, OptionSource source)
+{
+ for (const auto &p : std::as_const(m_parsers)) {
+ if (p->handleOption(key, value, source))
+ return true;
+ }
+ return false;
+}
+
+static void processOption(const QString &o, OptionSource source,
+ BoolOptions *bools, OptionValues *values)
+{
+ const auto equals = o.indexOf(u'=');
+ if (equals == -1) {
+ bools->append({o.trimmed(), source});
+ } else {
+ QString key = o.left(equals).trimmed();
+ QString value = o.mid(equals + 1).trimmed();
+ if (!value.isEmpty())
+ values->append({key, value, source});
+ }
+}
+
+static void readProjectFile(const QString &name, Options *o)
+{
+ const auto startMarker = "[generator-project]"_ba;
+
+ QFile file(name);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ throw Exception(msgCannotOpenForReading(file));
+
+ if (file.atEnd() || file.readLine().trimmed() != startMarker)
+ throw Exception(msgMissingProjectFileMarker(name, startMarker));
+
+ while (!file.atEnd()) {
+ const QByteArray lineB = file.readLine().trimmed();
+ if (!lineB.isEmpty() && !lineB.startsWith('#')) {
+ processOption(QString::fromUtf8(lineB), OptionSource::ProjectFile,
+ &o->boolOptions, &o->valueOptions);
+ }
+ }
+}
+
+void Options::setOptions(const QStringList &argv)
+{
+ const auto projectFileOption = "--project-file="_L1;
+ for (const auto &o : argv) {
+ if (o.startsWith(projectFileOption)) {
+ readProjectFile(o.sliced(projectFileOption.size()), this);
+ } else if (o.startsWith(u"--")) {
+ processOption(o.sliced(2), OptionSource::CommandLine,
+ &boolOptions, &valueOptions);
+ } else if (o.startsWith(u'-')) {
+ processOption(o.sliced(1), OptionSource::CommandLineSingleDash,
+ &boolOptions, &valueOptions);
+ } else {
+ positionalArguments.append(o);
+ }
+ }
+}
+
+QString Options::msgUnprocessedOptions() const
+{
+ QString result;
+ QTextStream str(&result);
+ for (const auto &b : boolOptions)
+ str << b << ' ';
+ for (const auto &v : valueOptions)
+ str << v << ' ';
+ return result.trimmed();
+}
diff --git a/sources/shiboken6/ApiExtractor/optionsparser.h b/sources/shiboken6/ApiExtractor/optionsparser.h
new file mode 100644
index 000000000..d5557dc15
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/optionsparser.h
@@ -0,0 +1,98 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OPTIONSPARSER_H
+#define OPTIONSPARSER_H
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+#include <memory>
+
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+
+enum class OptionSource
+{
+ CommandLine, // "--option"
+ CommandLineSingleDash, // "-o"
+ ProjectFile
+};
+
+struct BoolOption
+{
+ QString option;
+ OptionSource source = OptionSource::CommandLine;
+};
+
+struct OptionValue // --option=value pair
+{
+ QString option;
+ QString value;
+ OptionSource source = OptionSource::CommandLine;
+};
+
+using BoolOptions = QList<BoolOption>;
+using OptionValues = QList<OptionValue>;
+
+struct Options // Options from command line and project file
+{
+ void setOptions(const QStringList &argv);
+ QString msgUnprocessedOptions() const;
+
+ BoolOptions boolOptions;
+ OptionValues valueOptions;
+ QStringList positionalArguments;
+};
+
+struct OptionDescription // For help formatting
+{
+ QString name;
+ QString description;
+};
+
+using OptionDescriptions = QList<OptionDescription>;
+
+QTextStream &operator<<(QTextStream &s, const BoolOption &bo);
+QTextStream &operator<<(QTextStream &s, const OptionValue &ov);
+QTextStream &operator<<(QTextStream &s, const OptionDescription &od);
+QTextStream &operator<<(QTextStream &s, const OptionDescriptions &options);
+
+class OptionsParser
+{
+public:
+ Q_DISABLE_COPY_MOVE(OptionsParser)
+
+ virtual ~OptionsParser();
+
+ // Return true to indicate the option was processed.
+ virtual bool handleBoolOption(const QString &key, OptionSource source);
+ virtual bool handleOption(const QString &key, const QString &value, OptionSource source);
+
+ void process(Options *);
+
+ static const QString &pathSyntax();
+
+protected:
+ OptionsParser() noexcept;
+};
+
+class OptionsParserList : public OptionsParser
+{
+public:
+ using OptionsParserPtr = std::shared_ptr<OptionsParser>;
+
+ void append(const OptionsParserPtr &parser) { m_parsers.append(parser); }
+ void clear() { m_parsers.clear(); }
+
+ bool handleBoolOption(const QString &key, OptionSource source) override;
+ bool handleOption(const QString &key, const QString &value, OptionSource source) override;
+
+private:
+ QList<OptionsParserPtr> m_parsers;
+};
+
+QDebug operator<<(QDebug debug, const BoolOption &bo);
+QDebug operator<<(QDebug debug, const OptionValue &v);
+QDebug operator<<(QDebug debug, const Options &v);
+
+#endif // OPTIONSPARSER_H
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
new file mode 100644
index 000000000..259a706dc
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
@@ -0,0 +1,1562 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+#include "codemodel.h"
+
+#include <sourcelocation.h>
+#include <debughelpers_p.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QRegularExpression>
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+template <class T>
+static std::shared_ptr<T> findModelItem(const QList<std::shared_ptr<T> > &list,
+ QAnyStringView name)
+{
+ using ItemPtr = std::shared_ptr<T>;
+ auto pred = [name](const ItemPtr &item) { return item->name() == name; };
+ const auto it = std::find_if(list.cbegin(), list.cend(), pred);
+ return it != list.cend() ? *it : ItemPtr{};
+}
+
+// ---------------------------------------------------------------------------
+
+CodeModel::CodeModel() : m_globalNamespace(new _NamespaceModelItem(this))
+{
+}
+
+CodeModel::~CodeModel() = default;
+
+NamespaceModelItem CodeModel::globalNamespace() const
+{
+ return m_globalNamespace;
+}
+
+void CodeModel::addFile(const FileModelItem &item)
+{
+ m_files.append(item);
+}
+
+FileModelItem CodeModel::findFile(QAnyStringView name) const
+{
+ return findModelItem(m_files, name);
+}
+
+static CodeModelItem findRecursion(const ScopeModelItem &scope,
+ const QStringList &qualifiedName, int segment = 0)
+{
+ const QString &nameSegment = qualifiedName.at(segment);
+ if (segment == qualifiedName.size() - 1) { // Leaf item
+ if (ClassModelItem cs = scope->findClass(nameSegment))
+ return cs;
+ if (EnumModelItem es = scope->findEnum(nameSegment))
+ return es;
+ if (TypeDefModelItem tp = scope->findTypeDef(nameSegment))
+ return tp;
+ if (TemplateTypeAliasModelItem tta = scope->findTemplateTypeAlias(nameSegment))
+ return tta;
+ return {};
+ }
+ if (auto nestedClass = scope->findClass(nameSegment))
+ return findRecursion(nestedClass, qualifiedName, segment + 1);
+ if (auto namespaceItem = std::dynamic_pointer_cast<_NamespaceModelItem>(scope)) {
+ for (const auto &nestedNamespace : namespaceItem->namespaces()) {
+ if (nestedNamespace->name() == nameSegment) {
+ if (auto item = findRecursion(nestedNamespace, qualifiedName, segment + 1))
+ return item;
+ }
+ }
+ }
+ return {};
+}
+
+CodeModelItem CodeModel::findItem(const QStringList &qualifiedName, const ScopeModelItem &scope)
+{
+ return findRecursion(scope, qualifiedName);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug d, Access a)
+{
+ QDebugStateSaver s(d);
+ d.noquote();
+ d.nospace();
+ switch (a) {
+ case Access::Public:
+ d << "public";
+ break;
+ case Access::Protected:
+ d << "protected";
+ break;
+ case Access::Private:
+ d << "private";
+ break;
+ }
+ return d;
+}
+
+QDebug operator<<(QDebug d, const CodeModel *m)
+{
+ QDebugStateSaver s(d);
+ d.noquote();
+ d.nospace();
+ d << "CodeModel(";
+ if (m) {
+ const NamespaceModelItem globalNamespaceP = m->globalNamespace();
+ if (globalNamespaceP)
+ globalNamespaceP->formatDebug(d);
+ } else {
+ d << '0';
+ }
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_CodeModelItem::_CodeModelItem(CodeModel *model, int kind)
+ : m_model(model),
+ m_kind(kind),
+ m_startLine(0),
+ m_startColumn(0),
+ m_endLine(0),
+ m_endColumn(0)
+{
+}
+
+_CodeModelItem::_CodeModelItem(CodeModel *model, const QString &name, int kind)
+ : m_model(model),
+ m_kind(kind),
+ m_startLine(0),
+ m_startColumn(0),
+ m_endLine(0),
+ m_endColumn(0),
+ m_name(name)
+{
+}
+
+_CodeModelItem::~_CodeModelItem() = default;
+
+int _CodeModelItem::kind() const
+{
+ return m_kind;
+}
+
+QStringList _CodeModelItem::qualifiedName() const
+{
+ QStringList q = scope();
+
+ if (!name().isEmpty())
+ q += name();
+
+ return q;
+}
+
+QString _CodeModelItem::name() const
+{
+ return m_name;
+}
+
+void _CodeModelItem::setName(const QString &name)
+{
+ m_name = name;
+}
+
+QStringList _CodeModelItem::scope() const
+{
+ return m_scope;
+}
+
+void _CodeModelItem::setScope(const QStringList &scope)
+{
+ m_scope = scope;
+}
+
+QString _CodeModelItem::fileName() const
+{
+ return m_fileName;
+}
+
+void _CodeModelItem::setFileName(const QString &fileName)
+{
+ m_fileName = fileName;
+}
+
+FileModelItem _CodeModelItem::file() const
+{
+ return model()->findFile(fileName());
+}
+
+void _CodeModelItem::getStartPosition(int *line, int *column)
+{
+ *line = m_startLine;
+ *column = m_startColumn;
+}
+
+void _CodeModelItem::setStartPosition(int line, int column)
+{
+ m_startLine = line;
+ m_startColumn = column;
+}
+
+void _CodeModelItem::getEndPosition(int *line, int *column)
+{
+ *line = m_endLine;
+ *column = m_endColumn;
+}
+
+void _CodeModelItem::setEndPosition(int line, int column)
+{
+ m_endLine = line;
+ m_endColumn = column;
+}
+
+SourceLocation _CodeModelItem::sourceLocation() const
+{
+ return SourceLocation(m_fileName, m_startLine);
+}
+
+const _ScopeModelItem *_CodeModelItem::enclosingScope() const
+{
+ return m_enclosingScope;
+}
+
+void _CodeModelItem::setEnclosingScope(const _ScopeModelItem *s)
+{
+ m_enclosingScope = s;
+}
+
+_ScopeModelItem::_ScopeModelItem(CodeModel *model, int kind)
+ : _CodeModelItem(model, kind)
+{
+}
+
+_ScopeModelItem::_ScopeModelItem(CodeModel *model, const QString &name, int kind)
+ : _CodeModelItem(model, name, kind)
+{
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _CodeModelItem::formatKind(QDebug &d, int k)
+{
+ switch (k) {
+ case Kind_Argument:
+ d << "ArgumentModelItem";
+ break;
+ case Kind_Class:
+ d << "ClassModelItem";
+ break;
+ case Kind_Enum:
+ d << "EnumModelItem";
+ break;
+ case Kind_Enumerator:
+ d << "EnumeratorModelItem";
+ break;
+ case Kind_File:
+ d << "FileModelItem";
+ break;
+ case Kind_Function:
+ d << "FunctionModelItem";
+ break;
+ case Kind_Member:
+ d << "MemberModelItem";
+ break;
+ case Kind_Namespace:
+ d << "NamespaceModelItem";
+ break;
+ case Kind_Variable:
+ d << "VariableModelItem";
+ break;
+ case Kind_Scope:
+ d << "ScopeModelItem";
+ break;
+ case Kind_TemplateParameter:
+ d << "TemplateParameter";
+ break;
+ case Kind_TypeDef:
+ d << "TypeDefModelItem";
+ break;
+ case Kind_TemplateTypeAlias:
+ d << "TemplateTypeAliasModelItem";
+ break;
+ default:
+ d << "CodeModelItem";
+ break;
+ }
+}
+
+void _CodeModelItem::formatDebug(QDebug &d) const
+{
+ d << "(\"" << name() << '"';
+ if (!m_scope.isEmpty()) {
+ d << ", scope=";
+ formatSequence(d, m_scope.cbegin(), m_scope.cend(), "::");
+ }
+ if (!m_fileName.isEmpty()) {
+ d << ", file=\"" << QDir::toNativeSeparators(m_fileName);
+ if (m_startLine > 0)
+ d << ':' << m_startLine;
+ d << '"';
+ }
+}
+
+QDebug operator<<(QDebug d, const _CodeModelItem *t)
+{
+ QDebugStateSaver s(d);
+ d.noquote();
+ d.nospace();
+ if (!t) {
+ d << "CodeModelItem(0)";
+ return d;
+ }
+ _CodeModelItem::formatKind(d, t->kind());
+ t->formatDebug(d);
+ switch (t->kind()) {
+ case _CodeModelItem::Kind_Class:
+ d << " /* class " << t->name() << " */";
+ break;
+ case _CodeModelItem::Kind_Namespace:
+ d << " /* namespace " << t->name() << " */";
+ break;
+ }
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_ClassModelItem::~_ClassModelItem() = default;
+
+TemplateParameterList _ClassModelItem::templateParameters() const
+{
+ return m_templateParameters;
+}
+
+void _ClassModelItem::setTemplateParameters(const TemplateParameterList &templateParameters)
+{
+ m_templateParameters = templateParameters;
+}
+
+bool _ClassModelItem::extendsClass(const QString &name) const
+{
+ for (const BaseClass &bc : m_baseClasses) {
+ if (bc.name == name)
+ return true;
+ }
+ return false;
+}
+
+_ClassModelItem::_ClassModelItem(CodeModel *model, int kind)
+ : _ScopeModelItem(model, kind)
+{
+}
+
+_ClassModelItem::_ClassModelItem(CodeModel *model, const QString &name, int kind)
+ : _ScopeModelItem(model, name, kind)
+{
+}
+
+const QList<_ClassModelItem::UsingMember> &_ClassModelItem::usingMembers() const
+{
+ return m_usingMembers;
+}
+
+void _ClassModelItem::addUsingMember(const QString &className,
+ const QString &memberName,
+ Access accessPolicy)
+{
+ m_usingMembers.append({className, memberName, accessPolicy});
+}
+
+void _ClassModelItem::setClassType(CodeModel::ClassType type)
+{
+ m_classType = type;
+}
+
+CodeModel::ClassType _ClassModelItem::classType() const
+{
+ return m_classType;
+}
+
+void _ClassModelItem::addPropertyDeclaration(const QString &propertyDeclaration)
+{
+ m_propertyDeclarations << propertyDeclaration;
+}
+
+bool _ClassModelItem::isEmpty() const
+{
+ return _ScopeModelItem::isEmpty() && m_propertyDeclarations.isEmpty();
+}
+
+bool _ClassModelItem::isTemplate() const
+{
+ return !m_templateParameters.isEmpty();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class List>
+static void formatModelItemList(QDebug &d, const char *prefix, const List &l,
+ const char *separator = ", ")
+{
+ if (const auto size = l.size()) {
+ d << prefix << '[' << size << "](";
+ for (qsizetype i = 0; i < size; ++i) {
+ if (i)
+ d << separator;
+ l.at(i)->formatDebug(d);
+ }
+ d << ')';
+ }
+}
+
+void _ClassModelItem::formatDebug(QDebug &d) const
+{
+ _ScopeModelItem::formatDebug(d);
+ if (!m_baseClasses.isEmpty()) {
+ if (m_final)
+ d << " [final]";
+ d << ", inherits=";
+ d << ", inherits=";
+ for (qsizetype i = 0, size = m_baseClasses.size(); i < size; ++i) {
+ if (i)
+ d << ", ";
+ d << m_baseClasses.at(i).name << " (" << m_baseClasses.at(i).accessPolicy << ')';
+ }
+ }
+ for (const auto &im : m_usingMembers)
+ d << ", using " << im.className << "::" << im.memberName
+ << " (" << im.access << ')';
+ formatModelItemList(d, ", templateParameters=", m_templateParameters);
+ formatScopeItemsDebug(d);
+ if (!m_propertyDeclarations.isEmpty())
+ d << ", Properties=" << m_propertyDeclarations;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+FunctionModelItem _ScopeModelItem::declaredFunction(const FunctionModelItem &item)
+{
+ for (const FunctionModelItem &fun : std::as_const(m_functions)) {
+ if (fun->name() == item->name() && fun->isSimilar(item))
+ return fun;
+
+ }
+ return {};
+}
+
+_ScopeModelItem::~_ScopeModelItem() = default;
+
+void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration)
+{
+ m_enumsDeclarations << enumsDeclaration;
+}
+
+void _ScopeModelItem::addClass(const ClassModelItem &item)
+{
+ m_classes.append(item);
+ item->setEnclosingScope(this);
+}
+
+void _ScopeModelItem::addFunction(const FunctionModelItem &item)
+{
+ m_functions.append(item);
+ item->setEnclosingScope(this);
+}
+
+void _ScopeModelItem::addVariable(const VariableModelItem &item)
+{
+ m_variables.append(item);
+ item->setEnclosingScope(this);
+}
+
+void _ScopeModelItem::addTypeDef(const TypeDefModelItem &item)
+{
+ m_typeDefs.append(item);
+ item->setEnclosingScope(this);
+}
+
+void _ScopeModelItem::addTemplateTypeAlias(const TemplateTypeAliasModelItem &item)
+{
+ m_templateTypeAliases.append(item);
+ item->setEnclosingScope(this);
+}
+
+qsizetype _ScopeModelItem::indexOfEnum(const QString &name) const
+{
+ for (qsizetype i = 0, size = m_enums.size(); i < size; ++i) {
+ if (m_enums.at(i)->name() == name)
+ return i;
+ }
+ return -1;
+}
+
+void _ScopeModelItem::addEnum(const EnumModelItem &item)
+{
+ item->setEnclosingScope(this);
+ // A forward declaration of an enum ("enum class Foo;") is undistinguishable
+ // from an enum without values ("enum class QCborTag {}"), so, add all
+ // enums and replace existing ones without values by ones with values.
+ const int index = indexOfEnum(item->name());
+ if (index >= 0) {
+ if (item->hasValues() && !m_enums.at(index)->hasValues())
+ m_enums[index] = item;
+ return;
+ }
+ m_enums.append(item);
+}
+
+void _ScopeModelItem::appendScope(const _ScopeModelItem &other)
+{
+ m_classes += other.m_classes;
+ m_enums += other.m_enums;
+ m_typeDefs += other.m_typeDefs;
+ m_templateTypeAliases += other.m_templateTypeAliases;
+ m_variables += other.m_variables;
+ m_functions += other.m_functions;
+ m_enumsDeclarations += other.m_enumsDeclarations;
+}
+
+bool _ScopeModelItem::isEmpty() const
+{
+ return m_classes.isEmpty() && m_enums.isEmpty()
+ && m_typeDefs.isEmpty() && m_templateTypeAliases.isEmpty()
+ && m_variables.isEmpty() && m_functions.isEmpty()
+ && m_enumsDeclarations.isEmpty();
+}
+
+/* This function removes MSVC export declarations of non-type template
+ * specializations (see below code from photon.h) for which
+ * clang_isCursorDefinition() returns true, causing them to be added as
+ * definitions of empty classes shadowing the template definition depending
+ * on QHash seed values.
+
+template <int N> class Tpl
+{
+public:
+...
+};
+
+#ifdef WIN32
+template class LIBSAMPLE_EXPORT Tpl<54>;
+*/
+void _ScopeModelItem::purgeClassDeclarations()
+{
+ for (auto i = m_classes.size() - 1; i >= 0; --i) {
+ auto klass = m_classes.at(i);
+ // For an empty class, check if there is a matching template
+ // definition, and remove it if this is the case.
+ if (!klass->isTemplate() && klass->isEmpty()) {
+ const QString definitionPrefix = klass->name() + u'<';
+ const bool definitionFound =
+ std::any_of(m_classes.cbegin(), m_classes.cend(),
+ [definitionPrefix] (const ClassModelItem &c) {
+ return c->isTemplate() && !c->isEmpty()
+ && c->name().startsWith(definitionPrefix);
+ });
+ if (definitionFound)
+ m_classes.removeAt(i);
+ }
+ }
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class Hash>
+static void formatScopeHash(QDebug &d, const char *prefix, const Hash &h,
+ const char *separator = ", ",
+ bool trailingNewLine = false)
+{
+ if (!h.isEmpty()) {
+ d << prefix << '[' << h.size() << "](";
+ const auto begin = h.cbegin();
+ for (auto it = begin, end = h.cend(); it != end; ++it) { // Omit the names as they are repeated
+ if (it != begin)
+ d << separator;
+ d << it.value().data();
+ }
+ d << ')';
+ if (trailingNewLine)
+ d << '\n';
+ }
+}
+
+template <class List>
+static void formatScopeList(QDebug &d, const char *prefix, const List &l,
+ const char *separator = ", ",
+ bool trailingNewLine = false)
+{
+ if (!l.isEmpty()) {
+ d << prefix << '[' << l.size() << "](";
+ formatPtrSequence(d, l.begin(), l.end(), separator);
+ d << ')';
+ if (trailingNewLine)
+ d << '\n';
+ }
+}
+
+void _ScopeModelItem::formatScopeItemsDebug(QDebug &d) const
+{
+ formatScopeList(d, ", classes=", m_classes, "\n", true);
+ formatScopeList(d, ", enums=", m_enums, "\n", true);
+ formatScopeList(d, ", aliases=", m_typeDefs, "\n", true);
+ formatScopeList(d, ", template type aliases=", m_templateTypeAliases, "\n", true);
+ formatScopeList(d, ", functions=", m_functions, "\n", true);
+ formatScopeList(d, ", variables=", m_variables);
+}
+
+void _ScopeModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ formatScopeItemsDebug(d);
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// Predicate to match a non-template class name against the class list.
+// "Vector" should match "Vector" as well as "Vector<T>" (as seen for methods
+// from within the class "Vector").
+static bool matchClassNameNonTemplatePart(const ClassModelItem &item, const QString &name)
+{
+ const QString &itemName = item->name();
+ if (!itemName.startsWith(name))
+ return false;
+ return itemName.size() == name.size() || itemName.at(name.size()) == u'<';
+}
+
+ClassModelItem _ScopeModelItem::findClass(const QString &name) const
+{
+ // A fully qualified template is matched by name only
+ const ClassList::const_iterator it = name.contains(u'<')
+ ? std::find_if(m_classes.begin(), m_classes.end(),
+ [&name](const ClassModelItem &item) {
+ return item->name() == name; })
+ : std::find_if(m_classes.begin(), m_classes.end(),
+ [&name](const ClassModelItem &item) {
+ return matchClassNameNonTemplatePart(item, name); });
+ return it != m_classes.end() ? *it : ClassModelItem();
+}
+
+VariableModelItem _ScopeModelItem::findVariable(QAnyStringView name) const
+{
+ return findModelItem(m_variables, name);
+}
+
+TypeDefModelItem _ScopeModelItem::findTypeDef(QAnyStringView name) const
+{
+ return findModelItem(m_typeDefs, name);
+}
+
+TemplateTypeAliasModelItem _ScopeModelItem::findTemplateTypeAlias(QAnyStringView name) const
+{
+ return findModelItem(m_templateTypeAliases, name);
+}
+
+EnumModelItem _ScopeModelItem::findEnum(QAnyStringView name) const
+{
+ return findModelItem(m_enums, name);
+}
+
+_ScopeModelItem::FindEnumByValueReturn
+ _ScopeModelItem::findEnumByValueHelper(QStringView fullValue,
+ QStringView enumValue) const
+{
+ const bool unqualified = fullValue.size() == enumValue.size();
+ QString scopePrefix = scope().join(u"::");
+ if (!scopePrefix.isEmpty())
+ scopePrefix += u"::"_s;
+ scopePrefix += name() + u"::"_s;
+
+ for (const auto &e : m_enums) {
+ const auto index = e->indexOfValue(enumValue);
+ if (index != -1) {
+ QString fullyQualifiedName = scopePrefix;
+ if (e->enumKind() != AnonymousEnum)
+ fullyQualifiedName += e->name() + u"::"_s;
+ fullyQualifiedName += e->enumerators().at(index)->name();
+ if (unqualified || fullyQualifiedName.endsWith(fullValue))
+ return {e, fullyQualifiedName};
+ // For standard enums, check the name without enum name
+ if (e->enumKind() == CEnum) {
+ const QString qualifiedName =
+ scopePrefix + e->enumerators().at(index)->name();
+ if (qualifiedName.endsWith(fullValue))
+ return {e, fullyQualifiedName};
+ }
+ }
+ }
+
+ return {};
+}
+
+// Helper to recursively find the scope of an enum value
+_ScopeModelItem::FindEnumByValueReturn
+ _ScopeModelItem::findEnumByValueRecursion(const _ScopeModelItem *scope,
+ QStringView fullValue,
+ QStringView enumValue,
+ bool searchSiblingNamespaces)
+{
+ if (const auto e = scope->findEnumByValueHelper(fullValue, enumValue))
+ return e;
+
+ if (auto *enclosingScope = scope->enclosingScope()) {
+ // The enclosing scope may have several sibling namespaces of that name.
+ if (searchSiblingNamespaces && scope->kind() == Kind_Namespace) {
+ if (auto *enclosingNamespace = dynamic_cast<const _NamespaceModelItem *>(enclosingScope)) {
+ for (const auto &sibling : enclosingNamespace->namespaces()) {
+ if (sibling.get() != scope && sibling->name() == scope->name()) {
+ if (const auto e = findEnumByValueRecursion(sibling.get(),
+ fullValue, enumValue, false)) {
+ return e;
+ }
+ }
+ }
+ }
+ }
+
+ if (const auto e = findEnumByValueRecursion(enclosingScope, fullValue, enumValue))
+ return e;
+ }
+
+ // PYSIDE-331: We need to also search the base classes.
+ if (auto *classItem = dynamic_cast<const _ClassModelItem *>(scope)) {
+ for (const auto &base : classItem->baseClasses()) {
+ if (base.klass) {
+ auto *c = base.klass.get();
+ if (const auto e = findEnumByValueRecursion(c, fullValue, enumValue))
+ return e;
+ }
+ }
+ }
+
+ return {};
+}
+
+_ScopeModelItem::FindEnumByValueReturn
+ _ScopeModelItem::findEnumByValue(QStringView value) const
+{
+ const auto lastQualifier = value.lastIndexOf(u"::");
+ const auto enumValue = lastQualifier == -1
+ ? value : value.mid(lastQualifier + 2);
+ return findEnumByValueRecursion(this, value, enumValue);
+}
+
+FunctionList _ScopeModelItem::findFunctions(QAnyStringView name) const
+{
+ FunctionList result;
+ for (const FunctionModelItem &func : m_functions) {
+ if (func->name() == name)
+ result.append(func);
+ }
+ return result;
+}
+
+// ---------------------------------------------------------------------------
+_NamespaceModelItem::_NamespaceModelItem(CodeModel *model, int kind)
+ : _ScopeModelItem(model, kind)
+{
+}
+
+_NamespaceModelItem::_NamespaceModelItem(CodeModel *model, const QString &name, int kind)
+ : _ScopeModelItem(model, name, kind)
+{
+}
+
+_NamespaceModelItem::~_NamespaceModelItem() = default;
+
+void _NamespaceModelItem::addNamespace(NamespaceModelItem item)
+{
+ item->setEnclosingScope(this);
+ m_namespaces.append(item);
+}
+
+NamespaceModelItem _NamespaceModelItem::findNamespace(QAnyStringView name) const
+{
+ return findModelItem(m_namespaces, name);
+}
+
+_FileModelItem::~_FileModelItem() = default;
+
+void _NamespaceModelItem::appendNamespace(const _NamespaceModelItem &other)
+{
+ appendScope(other);
+ m_namespaces += other.m_namespaces;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _NamespaceModelItem::formatDebug(QDebug &d) const
+{
+ _ScopeModelItem::formatDebug(d);
+ switch (m_type) {
+ case NamespaceType::Default:
+ break;
+ case NamespaceType::Anonymous:
+ d << ", anonymous";
+ break;
+ case NamespaceType::Inline:
+ d << ", inline";
+ break;
+ }
+ formatScopeList(d, ", namespaces=", m_namespaces);
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_ArgumentModelItem::_ArgumentModelItem(CodeModel *model, int kind)
+ : _CodeModelItem(model, kind)
+{
+}
+
+_ArgumentModelItem::_ArgumentModelItem(CodeModel *model, const QString &name, int kind)
+ : _CodeModelItem(model, name, kind)
+{
+}
+
+_ArgumentModelItem::~_ArgumentModelItem() = default;
+
+TypeInfo _ArgumentModelItem::type() const
+{
+ return m_type;
+}
+
+void _ArgumentModelItem::setType(const TypeInfo &type)
+{
+ m_type = type;
+}
+
+bool _ArgumentModelItem::defaultValue() const
+{
+ return m_defaultValue;
+}
+
+void _ArgumentModelItem::setDefaultValue(bool defaultValue)
+{
+ m_defaultValue = defaultValue;
+}
+
+bool _ArgumentModelItem::scopeResolution() const
+{
+ return m_scopeResolution;
+}
+
+void _ArgumentModelItem::setScopeResolution(bool v)
+{
+ m_scopeResolution = v;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _ArgumentModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ d << ", type=" << m_type;
+ if (m_scopeResolution)
+ d << ", [m_scope resolution]";
+ if (m_defaultValue)
+ d << ", defaultValue=\"" << m_defaultValueExpression << '"';
+}
+#endif // !QT_NO_DEBUG_STREAM
+// ---------------------------------------------------------------------------
+_FunctionModelItem::~_FunctionModelItem() = default;
+
+bool _FunctionModelItem::isSimilar(const FunctionModelItem &other) const
+{
+ if (name() != other->name())
+ return false;
+
+ if (isConstant() != other->isConstant())
+ return false;
+
+ if (isVariadics() != other->isVariadics())
+ return false;
+
+ if (arguments().size() != other->arguments().size())
+ return false;
+
+ // ### check the template parameters
+
+ for (qsizetype i = 0; i < arguments().size(); ++i) {
+ ArgumentModelItem arg1 = arguments().at(i);
+ ArgumentModelItem arg2 = other->arguments().at(i);
+
+ if (arg1->type() != arg2->type())
+ return false;
+ }
+
+ return true;
+}
+
+_FunctionModelItem::_FunctionModelItem(CodeModel *model, int kind)
+ : _MemberModelItem(model, kind), m_flags(0)
+{
+}
+
+_FunctionModelItem::_FunctionModelItem(CodeModel *model, const QString &name, int kind)
+ : _MemberModelItem(model, name, kind), m_flags(0)
+{
+}
+
+ArgumentList _FunctionModelItem::arguments() const
+{
+ return m_arguments;
+}
+
+void _FunctionModelItem::addArgument(const ArgumentModelItem& item)
+{
+ m_arguments.append(item);
+}
+
+CodeModel::FunctionType _FunctionModelItem::functionType() const
+{
+ return m_functionType;
+}
+
+void _FunctionModelItem::setFunctionType(CodeModel::FunctionType functionType)
+{
+ m_functionType = functionType;
+}
+
+bool _FunctionModelItem::isVariadics() const
+{
+ return m_isVariadics;
+}
+
+void _FunctionModelItem::setVariadics(bool isVariadics)
+{
+ m_isVariadics = isVariadics;
+}
+
+bool _FunctionModelItem::scopeResolution() const
+{
+ return m_scopeResolution;
+}
+
+void _FunctionModelItem::setScopeResolution(bool v)
+{
+ m_scopeResolution = v;
+}
+
+bool _FunctionModelItem::isDefaultConstructor() const
+{
+ return m_functionType == CodeModel::Constructor
+ && (m_arguments.isEmpty() || m_arguments.constFirst()->defaultValue());
+}
+
+bool _FunctionModelItem::isSpaceshipOperator() const
+{
+ return m_functionType == CodeModel::ComparisonOperator
+ && name() == u"operator<=>";
+}
+
+bool _FunctionModelItem::isNoExcept() const
+{
+ return m_exceptionSpecification == ExceptionSpecification::NoExcept;
+}
+
+bool _FunctionModelItem::isOperator() const
+{
+ bool result = false;
+ switch (m_functionType) {
+ case CodeModel::CallOperator:
+ case CodeModel::ConversionOperator:
+ case CodeModel::DereferenceOperator:
+ case CodeModel::ReferenceOperator:
+ case CodeModel::ArrowOperator:
+ case CodeModel::ArithmeticOperator:
+ case CodeModel::IncrementOperator:
+ case CodeModel::DecrementOperator:
+ case CodeModel::BitwiseOperator:
+ case CodeModel::LogicalOperator:
+ case CodeModel::ShiftOperator:
+ case CodeModel::SubscriptOperator:
+ case CodeModel::ComparisonOperator:
+ result = true;
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+ExceptionSpecification _FunctionModelItem::exceptionSpecification() const
+{
+ return m_exceptionSpecification;
+}
+
+void _FunctionModelItem::setExceptionSpecification(ExceptionSpecification e)
+{
+ m_exceptionSpecification = e;
+}
+
+bool _FunctionModelItem::isDeleted() const
+{
+ return m_isDeleted;
+}
+
+void _FunctionModelItem::setDeleted(bool d)
+{
+ m_isDeleted = d;
+}
+
+bool _FunctionModelItem::isInline() const
+{
+ return m_isInline;
+}
+
+void _FunctionModelItem::setInline(bool isInline)
+{
+ m_isInline = isInline;
+}
+
+bool _FunctionModelItem::isHiddenFriend() const
+{
+ return m_isHiddenFriend;
+}
+
+void _FunctionModelItem::setHiddenFriend(bool f)
+{
+ m_isHiddenFriend = f;
+}
+
+QString _FunctionModelItem::typeSystemSignature() const // For dumping out type system files
+{
+ QString result;
+ QTextStream str(&result);
+ str << name() << '(';
+ for (qsizetype a = 0, size = m_arguments.size(); a < size; ++a) {
+ if (a)
+ str << ',';
+ m_arguments.at(a)->type().formatTypeSystemSignature(str);
+ }
+ str << ')';
+ return result;
+}
+
+using NameFunctionTypeHash = QHash<QStringView, CodeModel::FunctionType>;
+
+static const NameFunctionTypeHash &nameToOperatorFunction()
+{
+ static const NameFunctionTypeHash result = {
+ {u"operator=", CodeModel::AssignmentOperator},
+ {u"operator+", CodeModel::ArithmeticOperator},
+ {u"operator+=", CodeModel::ArithmeticOperator},
+ {u"operator-", CodeModel::ArithmeticOperator},
+ {u"operator-=", CodeModel::ArithmeticOperator},
+ {u"operator*", CodeModel::ArithmeticOperator},
+ {u"operator*=", CodeModel::ArithmeticOperator},
+ {u"operator/", CodeModel::ArithmeticOperator},
+ {u"operator/=", CodeModel::ArithmeticOperator},
+ {u"operator%", CodeModel::ArithmeticOperator},
+ {u"operator%=", CodeModel::ArithmeticOperator},
+ {u"operator++", CodeModel::IncrementOperator},
+ {u"operator--", CodeModel::DecrementOperator},
+ {u"operator&", CodeModel::BitwiseOperator},
+ {u"operator&=", CodeModel::BitwiseOperator},
+ {u"operator|", CodeModel::BitwiseOperator},
+ {u"operator|=", CodeModel::BitwiseOperator},
+ {u"operator^", CodeModel::BitwiseOperator},
+ {u"operator^=", CodeModel::BitwiseOperator},
+ {u"operator~", CodeModel::BitwiseOperator},
+ {u"operator<<", CodeModel::ShiftOperator},
+ {u"operator<<=", CodeModel::ShiftOperator},
+ {u"operator>>", CodeModel::ShiftOperator},
+ {u"operator>>=", CodeModel::ShiftOperator},
+ {u"operator<", CodeModel::ComparisonOperator},
+ {u"operator<=", CodeModel::ComparisonOperator},
+ {u"operator>", CodeModel::ComparisonOperator},
+ {u"operator>=", CodeModel::ComparisonOperator},
+ {u"operator==", CodeModel::ComparisonOperator},
+ {u"operator!=", CodeModel::ComparisonOperator},
+ {u"operator<=>", CodeModel::ComparisonOperator},
+ {u"operator!", CodeModel::LogicalOperator},
+ {u"operator&&", CodeModel::LogicalOperator},
+ {u"operator||", CodeModel::LogicalOperator},
+ {u"operator[]", CodeModel::SubscriptOperator},
+ {u"operator()", CodeModel::CallOperator}, // Can be void
+ {u"operator->", CodeModel::ArrowOperator}
+ };
+ return result;
+}
+
+std::optional<CodeModel::FunctionType> _FunctionModelItem::functionTypeFromName(QStringView name)
+{
+ const auto it = nameToOperatorFunction().constFind(name);
+ if (it != nameToOperatorFunction().constEnd())
+ return it.value();
+ // This check is only for added functions. Clang detects this
+ // by cursor type CXCursor_ConversionFunction.
+ if (name.startsWith(u"operator "))
+ return CodeModel::ConversionOperator;
+ return {};
+}
+
+// Check for operators, etc. unless it is a specific type like a constructor
+CodeModel::FunctionType _FunctionModelItem::_determineTypeHelper() const
+{
+ switch (m_functionType) {
+ case CodeModel::Constructor:
+ case CodeModel::CopyConstructor:
+ case CodeModel::MoveConstructor:
+ case CodeModel::Destructor:
+ case CodeModel::Signal:
+ case CodeModel::Slot:
+ return m_functionType; // nothing to do here
+ default:
+ break;
+ }
+ const QString &functionName = name();
+ const auto newTypeOpt = _FunctionModelItem::functionTypeFromName(functionName);
+ if (!newTypeOpt.has_value())
+ return m_functionType;
+
+ auto newType = newTypeOpt.value();
+ // It's some sort of dereference operator?!
+ if (m_arguments.isEmpty()) {
+ switch (newType) {
+ case CodeModel::ArithmeticOperator:
+ if (functionName == u"operator*")
+ return CodeModel::DereferenceOperator;
+ break;
+ case CodeModel::BitwiseOperator:
+ if (functionName == u"operator&")
+ return CodeModel::ReferenceOperator;
+ break;
+ default:
+ break;
+ }
+ }
+ return newType;
+}
+
+void _FunctionModelItem::_determineType()
+{
+ m_functionType = _determineTypeHelper();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _FunctionModelItem::formatDebug(QDebug &d) const
+{
+ _MemberModelItem::formatDebug(d);
+ d << ", type=" << m_functionType << ", exspec=" << int(m_exceptionSpecification);
+ if (m_isDeleted)
+ d << " [deleted!]";
+ if (m_isInline)
+ d << " [inline]";
+ if (m_attributes.testFlag(FunctionAttribute::Virtual))
+ d << " [virtual]";
+ if (m_attributes.testFlag(FunctionAttribute::Override))
+ d << " [override]";
+ if (m_attributes.testFlag(FunctionAttribute::Deprecated))
+ d << " [deprecated]";
+ if (m_attributes.testFlag(FunctionAttribute::Final))
+ d << " [final]";
+ if (m_attributes.testFlag(FunctionAttribute::Abstract))
+ d << " [abstract]";
+ if (m_attributes.testFlag(FunctionAttribute::Explicit))
+ d << " [explicit]";
+ if (m_isInvokable)
+ d << " [invokable]";
+ if (m_scopeResolution)
+ d << " [scope resolution]";
+ formatModelItemList(d, ", arguments=", m_arguments);
+ if (m_isVariadics)
+ d << ",...";
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_TypeDefModelItem::_TypeDefModelItem(CodeModel *model, int kind)
+ : _CodeModelItem(model, kind)
+{
+}
+
+_TypeDefModelItem::_TypeDefModelItem(CodeModel *model, const QString &name, int kind)
+ : _CodeModelItem(model, name, kind)
+{
+}
+
+TypeInfo _TypeDefModelItem::type() const
+{
+ return m_type;
+}
+
+void _TypeDefModelItem::setType(const TypeInfo &type)
+{
+ m_type = type;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _TypeDefModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ d << ", type=" << m_type;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+
+_TemplateTypeAliasModelItem::_TemplateTypeAliasModelItem(CodeModel *model, int kind)
+ : _CodeModelItem(model, kind) {}
+
+_TemplateTypeAliasModelItem::_TemplateTypeAliasModelItem(CodeModel *model, const QString &name, int kind)
+ : _CodeModelItem(model, name, kind) {}
+
+TemplateParameterList _TemplateTypeAliasModelItem::templateParameters() const
+{
+ return m_templateParameters;
+}
+
+void _TemplateTypeAliasModelItem::addTemplateParameter(const TemplateParameterModelItem &templateParameter)
+{
+ m_templateParameters.append(templateParameter);
+}
+
+TypeInfo _TemplateTypeAliasModelItem::type() const
+{
+ return m_type;
+}
+
+void _TemplateTypeAliasModelItem::setType(const TypeInfo &type)
+{
+ m_type = type;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _TemplateTypeAliasModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ d << ", <";
+ for (qsizetype i = 0, count = m_templateParameters.size(); i < count; ++i) {
+ if (i)
+ d << ", ";
+ d << m_templateParameters.at(i)->name();
+ }
+ d << ">, type=" << m_type;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_EnumModelItem::_EnumModelItem(CodeModel *model, const QString &name, int kind)
+ : _CodeModelItem(model, name, kind)
+{
+}
+
+_EnumModelItem::_EnumModelItem(CodeModel *model, int kind)
+ : _CodeModelItem(model, kind)
+{
+}
+
+Access _EnumModelItem::accessPolicy() const
+{
+ return m_accessPolicy;
+}
+
+_EnumModelItem::~_EnumModelItem() = default;
+
+void _EnumModelItem::setAccessPolicy(Access accessPolicy)
+{
+ m_accessPolicy = accessPolicy;
+}
+
+EnumeratorList _EnumModelItem::enumerators() const
+{
+ return m_enumerators;
+}
+
+void _EnumModelItem::addEnumerator(const EnumeratorModelItem &item)
+{
+ m_enumerators.append(item);
+}
+
+qsizetype _EnumModelItem::indexOfValue(QStringView value) const
+{
+ for (qsizetype i = 0, size = m_enumerators.size(); i < size; ++i) {
+ if (m_enumerators.at(i)->name() == value)
+ return i;
+ }
+ return -1;
+}
+
+bool _EnumModelItem::isSigned() const
+{
+ return m_signed;
+}
+
+void _EnumModelItem::setSigned(bool s)
+{
+ m_signed = s;
+}
+
+QString _EnumModelItem::underlyingType() const
+{
+ return m_underlyingType;
+}
+
+void _EnumModelItem::setUnderlyingType(const QString &underlyingType)
+{
+ m_underlyingType = underlyingType;
+}
+
+bool _EnumModelItem::isDeprecated() const
+{
+ return m_deprecated;
+}
+
+void _EnumModelItem::setDeprecated(bool d)
+{
+ m_deprecated = d;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _EnumModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ switch (m_enumKind) {
+ case CEnum:
+ break;
+ case AnonymousEnum:
+ d << " (anonymous)";
+ break;
+ case EnumClass:
+ d << " (class)";
+ break;
+ }
+ if (m_deprecated)
+ d << " (deprecated)";
+ if (!m_signed)
+ d << " (unsigned)";
+ formatModelItemList(d, ", enumerators=", m_enumerators);
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_EnumeratorModelItem::~_EnumeratorModelItem() = default;
+
+_EnumeratorModelItem::_EnumeratorModelItem(CodeModel *model, int kind)
+ : _CodeModelItem(model, kind)
+{
+}
+
+_EnumeratorModelItem::_EnumeratorModelItem(CodeModel *model, const QString &name, int kind)
+ : _CodeModelItem(model, name, kind)
+{
+}
+
+QString _EnumeratorModelItem::stringValue() const
+{
+ return m_stringValue;
+}
+
+void _EnumeratorModelItem::setStringValue(const QString &value)
+{
+ m_stringValue = value;
+}
+
+bool _EnumeratorModelItem::isDeprecated() const
+{
+ return m_deprecated;
+}
+
+void _EnumeratorModelItem::setDeprecated(bool d)
+{
+ m_deprecated = d;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _EnumeratorModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ d << ", value=" << m_value << ", stringValue=\"" << m_stringValue << '"';
+ if (m_deprecated)
+ d << " (deprecated)";
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_TemplateParameterModelItem::~_TemplateParameterModelItem() = default;
+
+_TemplateParameterModelItem::_TemplateParameterModelItem(CodeModel *model, int kind)
+ : _CodeModelItem(model, kind)
+{
+}
+
+_TemplateParameterModelItem::_TemplateParameterModelItem(CodeModel *model,
+ const QString &name, int kind)
+ : _CodeModelItem(model, name, kind)
+{
+}
+
+TypeInfo _TemplateParameterModelItem::type() const
+{
+ return m_type;
+}
+
+void _TemplateParameterModelItem::setType(const TypeInfo &type)
+{
+ m_type = type;
+}
+
+bool _TemplateParameterModelItem::defaultValue() const
+{
+ return m_defaultValue;
+}
+
+void _TemplateParameterModelItem::setDefaultValue(bool defaultValue)
+{
+ m_defaultValue = defaultValue;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _TemplateParameterModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ d << ", type=" << m_type;
+ if (m_defaultValue)
+ d << " [defaultValue]";
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+TypeInfo _MemberModelItem::type() const
+{
+ return m_type;
+}
+
+void _MemberModelItem::setType(const TypeInfo &type)
+{
+ m_type = type;
+}
+
+Access _MemberModelItem::accessPolicy() const
+{
+ return m_accessPolicy;
+}
+
+_MemberModelItem::~_MemberModelItem() = default;
+
+void _MemberModelItem::setAccessPolicy(Access accessPolicy)
+{
+ m_accessPolicy = accessPolicy;
+}
+
+bool _MemberModelItem::isStatic() const
+{
+ return m_isStatic;
+}
+
+void _MemberModelItem::setStatic(bool isStatic)
+{
+ m_isStatic = isStatic;
+}
+
+_MemberModelItem::_MemberModelItem(CodeModel *model, int kind)
+ : _CodeModelItem(model, kind), m_flags(0)
+{
+}
+
+_MemberModelItem::_MemberModelItem(CodeModel *model, const QString &name, int kind)
+ : _CodeModelItem(model, name, kind), m_flags(0)
+{
+}
+
+bool _MemberModelItem::isConstant() const
+{
+ return m_isConstant;
+}
+
+void _MemberModelItem::setConstant(bool isConstant)
+{
+ m_isConstant = isConstant;
+}
+
+bool _MemberModelItem::isVolatile() const
+{
+ return m_isVolatile;
+}
+
+void _MemberModelItem::setVolatile(bool isVolatile)
+{
+ m_isVolatile = isVolatile;
+}
+
+bool _MemberModelItem::isAuto() const
+{
+ return m_isAuto;
+}
+
+void _MemberModelItem::setAuto(bool isAuto)
+{
+ m_isAuto = isAuto;
+}
+
+bool _MemberModelItem::isFriend() const
+{
+ return m_isFriend;
+}
+
+void _MemberModelItem::setFriend(bool isFriend)
+{
+ m_isFriend = isFriend;
+}
+
+bool _MemberModelItem::isRegister() const
+{
+ return m_isRegister;
+}
+
+void _MemberModelItem::setRegister(bool isRegister)
+{
+ m_isRegister = isRegister;
+}
+
+bool _MemberModelItem::isExtern() const
+{
+ return m_isExtern;
+}
+
+void _MemberModelItem::setExtern(bool isExtern)
+{
+ m_isExtern = isExtern;
+}
+
+bool _MemberModelItem::isMutable() const
+{
+ return m_isMutable;
+}
+
+void _MemberModelItem::setMutable(bool isMutable)
+{
+ m_isMutable = isMutable;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _MemberModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ d << ", " << m_accessPolicy << ", type=";
+ if (m_isConstant)
+ d << "const ";
+ if (m_isVolatile)
+ d << "volatile ";
+ if (m_isStatic)
+ d << "static ";
+ if (m_isAuto)
+ d << "auto ";
+ if (m_isFriend)
+ d << "friend ";
+ if (m_isRegister)
+ d << "register ";
+ if (m_isExtern)
+ d << "extern ";
+ if (m_isMutable)
+ d << "mutable ";
+ d << m_type;
+ formatScopeList(d, ", templateParameters", m_templateParameters);
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.h b/sources/shiboken6/ApiExtractor/parser/codemodel.h
new file mode 100644
index 000000000..b31c09163
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel.h
@@ -0,0 +1,700 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+#ifndef CODEMODEL_H
+#define CODEMODEL_H
+
+#include "codemodel_fwd.h"
+#include "codemodel_enums.h"
+#include "enumvalue.h"
+#include "typeinfo.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QSet>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QList>
+#include <QtCore/QWeakPointer>
+
+#include <optional>
+#include <utility>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+#define DECLARE_MODEL_NODE(k) \
+ enum { __node_kind = Kind_##k };
+
+class SourceLocation;
+
+class CodeModel
+{
+ Q_GADGET
+public:
+ Q_DISABLE_COPY_MOVE(CodeModel)
+
+ enum FunctionType {
+ Normal,
+ Constructor,
+ CopyConstructor,
+ MoveConstructor,
+ Destructor,
+ Signal,
+ Slot,
+ AssignmentOperator,
+ CallOperator,
+ ConversionOperator,
+ DereferenceOperator, // Iterator's operator *
+ ReferenceOperator, // operator &
+ ArrowOperator,
+ ArithmeticOperator,
+ IncrementOperator,
+ DecrementOperator,
+ BitwiseOperator,
+ LogicalOperator,
+ ShiftOperator,
+ SubscriptOperator,
+ ComparisonOperator
+ };
+ Q_ENUM(FunctionType)
+
+ enum ClassType {
+ Class,
+ Struct,
+ Union
+ };
+ Q_ENUM(ClassType)
+
+public:
+ CodeModel();
+ virtual ~CodeModel();
+
+ FileList files() const { return m_files; }
+ NamespaceModelItem globalNamespace() const;
+
+ void addFile(const FileModelItem &item);
+ FileModelItem findFile(QAnyStringView name) const;
+
+ static CodeModelItem findItem(const QStringList &qualifiedName,
+ const ScopeModelItem &scope);
+
+private:
+ FileList m_files;
+ NamespaceModelItem m_globalNamespace;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, Access a);
+QDebug operator<<(QDebug d, const CodeModel *m);
+#endif
+
+class _CodeModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_CodeModelItem)
+
+ enum Kind {
+ /* These are bit-flags resembling inheritance */
+ Kind_Scope = 0x1,
+ Kind_Namespace = 0x2 | Kind_Scope,
+ Kind_Member = 0x4,
+ Kind_Function = 0x8 | Kind_Member,
+ KindMask = 0xf,
+
+ /* These are for classes that are not inherited from */
+ FirstKind = 0x8,
+ Kind_Argument = 1 << FirstKind,
+ Kind_Class = 2 << FirstKind | Kind_Scope,
+ Kind_Enum = 3 << FirstKind,
+ Kind_Enumerator = 4 << FirstKind,
+ Kind_File = 5 << FirstKind | Kind_Namespace,
+ Kind_TemplateParameter = 7 << FirstKind,
+ Kind_TypeDef = 8 << FirstKind,
+ Kind_TemplateTypeAlias = 9 << FirstKind,
+ Kind_Variable = 10 << FirstKind | Kind_Member
+ };
+
+public:
+ virtual ~_CodeModelItem();
+
+ int kind() const;
+
+ QStringList qualifiedName() const;
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QStringList scope() const;
+ void setScope(const QStringList &scope);
+
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ FileModelItem file() const;
+
+ void getStartPosition(int *line, int *column);
+ int startLine() const { return m_startLine; }
+ void setStartPosition(int line, int column);
+
+ void getEndPosition(int *line, int *column);
+ void setEndPosition(int line, int column);
+
+ SourceLocation sourceLocation() const;
+
+ inline CodeModel *model() const { return m_model; }
+
+ const _ScopeModelItem *enclosingScope() const;
+ void setEnclosingScope(const _ScopeModelItem *s);
+
+#ifndef QT_NO_DEBUG_STREAM
+ static void formatKind(QDebug &d, int k);
+ virtual void formatDebug(QDebug &d) const;
+#endif
+
+protected:
+ explicit _CodeModelItem(CodeModel *model, int kind);
+ explicit _CodeModelItem(CodeModel *model, const QString &name, int kind);
+
+private:
+ CodeModel *m_model;
+ const _ScopeModelItem *m_enclosingScope = nullptr;
+ int m_kind;
+ int m_startLine;
+ int m_startColumn;
+ int m_endLine;
+ int m_endColumn;
+ QString m_name;
+ QString m_fileName;
+ QStringList m_scope;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const _CodeModelItem *t);
+#endif
+
+class _ScopeModelItem: public _CodeModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_ScopeModelItem)
+ DECLARE_MODEL_NODE(Scope)
+
+ ~_ScopeModelItem();
+
+ ClassList classes() const { return m_classes; }
+ const EnumList &enums() const { return m_enums; }
+ inline const FunctionList &functions() const { return m_functions; }
+ TypeDefList typeDefs() const { return m_typeDefs; }
+ TemplateTypeAliasList templateTypeAliases() const { return m_templateTypeAliases; }
+ VariableList variables() const { return m_variables; }
+
+ void addClass(const ClassModelItem &item);
+ void addEnum(const EnumModelItem &item);
+ void addFunction(const FunctionModelItem &item);
+ void addTypeDef(const TypeDefModelItem &item);
+ void addTemplateTypeAlias(const TemplateTypeAliasModelItem &item);
+ void addVariable(const VariableModelItem &item);
+
+ ClassModelItem findClass(const QString &name) const;
+ EnumModelItem findEnum(QAnyStringView name) const;
+
+ struct FindEnumByValueReturn
+ {
+ operator bool() const { return bool(item); }
+
+ EnumModelItem item;
+ QString qualifiedName;
+ };
+ FindEnumByValueReturn findEnumByValue(QStringView value) const;
+
+ FunctionList findFunctions(QAnyStringView name) const;
+ TypeDefModelItem findTypeDef(QAnyStringView name) const;
+ TemplateTypeAliasModelItem findTemplateTypeAlias(QAnyStringView name) const;
+ VariableModelItem findVariable(QAnyStringView name) const;
+
+ void addEnumsDeclaration(const QString &enumsDeclaration);
+ QStringList enumsDeclarations() const { return m_enumsDeclarations; }
+
+ FunctionModelItem declaredFunction(const FunctionModelItem &item);
+
+ bool isEmpty() const;
+ void purgeClassDeclarations();
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+protected:
+ explicit _ScopeModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _ScopeModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+
+ void appendScope(const _ScopeModelItem &other);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatScopeItemsDebug(QDebug &d) const;
+#endif
+
+private:
+ qsizetype indexOfEnum(const QString &name) const;
+
+ FindEnumByValueReturn findEnumByValueHelper(QStringView fullValue,
+ QStringView value) const;
+ static FindEnumByValueReturn
+ findEnumByValueRecursion(const _ScopeModelItem *scope,
+ QStringView fullValue, QStringView value,
+ bool searchSiblingNamespaces = true);
+
+ ClassList m_classes;
+ EnumList m_enums;
+ TypeDefList m_typeDefs;
+ TemplateTypeAliasList m_templateTypeAliases;
+ VariableList m_variables;
+ FunctionList m_functions;
+
+private:
+ QStringList m_enumsDeclarations;
+};
+
+class _ClassModelItem: public _ScopeModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_ClassModelItem)
+ DECLARE_MODEL_NODE(Class)
+
+ struct BaseClass
+ {
+ QString name;
+ ClassModelItem klass; // Might be null in case of templates
+ Access accessPolicy = Access::Public;
+ };
+
+ struct UsingMember // Introducing a base class member via 'using' directive
+ {
+ QString className;
+ QString memberName;
+ Access access = Access::Public;
+ };
+
+ explicit _ClassModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _ClassModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+ ~_ClassModelItem();
+
+ const QList<BaseClass> &baseClasses() const { return m_baseClasses; }
+
+ const QList<UsingMember> &usingMembers() const;
+ void addUsingMember(const QString &className, const QString &memberName,
+ Access accessPolicy);
+
+ void addBaseClass(const BaseClass &b) { m_baseClasses.append(b); }
+
+ TemplateParameterList templateParameters() const;
+ void setTemplateParameters(const TemplateParameterList &templateParameters);
+
+ bool extendsClass(const QString &name) const;
+
+ void setClassType(CodeModel::ClassType type);
+ CodeModel::ClassType classType() const;
+
+ void addPropertyDeclaration(const QString &propertyDeclaration);
+ QStringList propertyDeclarations() const { return m_propertyDeclarations; }
+
+ bool isFinal() const { return m_final; }
+ void setFinal(bool f) { m_final = f; }
+
+ bool isEmpty() const;
+ bool isTemplate() const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ QList<BaseClass> m_baseClasses;
+ QList<UsingMember> m_usingMembers;
+ TemplateParameterList m_templateParameters;
+ CodeModel::ClassType m_classType = CodeModel::Class;
+
+ QStringList m_propertyDeclarations;
+ bool m_final = false;
+};
+
+class _NamespaceModelItem: public _ScopeModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_NamespaceModelItem)
+ DECLARE_MODEL_NODE(Namespace)
+
+ explicit _NamespaceModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _NamespaceModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+ ~_NamespaceModelItem();
+
+ const NamespaceList &namespaces() const { return m_namespaces; }
+
+ NamespaceType type() const { return m_type; }
+ void setType(NamespaceType t) { m_type = t; }
+
+ void addNamespace(NamespaceModelItem item);
+
+ NamespaceModelItem findNamespace(QAnyStringView name) const;
+
+ void appendNamespace(const _NamespaceModelItem &other);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ NamespaceList m_namespaces;
+ NamespaceType m_type = NamespaceType::Default;
+};
+
+class _FileModelItem: public _NamespaceModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_FileModelItem)
+ DECLARE_MODEL_NODE(File)
+
+ using _NamespaceModelItem::_NamespaceModelItem;
+
+ ~_FileModelItem();
+};
+
+class _ArgumentModelItem: public _CodeModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_ArgumentModelItem)
+ DECLARE_MODEL_NODE(Argument)
+
+ explicit _ArgumentModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _ArgumentModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+ ~_ArgumentModelItem();
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+ bool defaultValue() const;
+ void setDefaultValue(bool defaultValue);
+
+ QString defaultValueExpression() const { return m_defaultValueExpression; }
+ void setDefaultValueExpression(const QString &expr) { m_defaultValueExpression = expr; }
+
+ // Argument type has scope resolution "::ArgumentType"
+ bool scopeResolution() const;
+ void setScopeResolution(bool v);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ TypeInfo m_type;
+ QString m_defaultValueExpression;
+ bool m_defaultValue = false;
+ bool m_scopeResolution = false;
+};
+
+class _MemberModelItem: public _CodeModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_MemberModelItem)
+ DECLARE_MODEL_NODE(Member)
+
+ explicit _MemberModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _MemberModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+ ~_MemberModelItem();
+
+ bool isConstant() const;
+ void setConstant(bool isConstant);
+
+ bool isVolatile() const;
+ void setVolatile(bool isVolatile);
+
+ bool isStatic() const;
+ void setStatic(bool isStatic);
+
+ bool isAuto() const;
+ void setAuto(bool isAuto);
+
+ bool isFriend() const;
+ void setFriend(bool isFriend);
+
+ bool isRegister() const;
+ void setRegister(bool isRegister);
+
+ bool isExtern() const;
+ void setExtern(bool isExtern);
+
+ bool isMutable() const;
+ void setMutable(bool isMutable);
+
+ Access accessPolicy() const;
+ void setAccessPolicy(Access accessPolicy);
+
+ TemplateParameterList templateParameters() const { return m_templateParameters; }
+ void setTemplateParameters(const TemplateParameterList &templateParameters) { m_templateParameters = templateParameters; }
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ TemplateParameterList m_templateParameters;
+ TypeInfo m_type;
+ Access m_accessPolicy = Access::Public;
+ union {
+ struct {
+ uint m_isConstant: 1;
+ uint m_isVolatile: 1;
+ uint m_isStatic: 1;
+ uint m_isAuto: 1;
+ uint m_isFriend: 1;
+ uint m_isRegister: 1;
+ uint m_isExtern: 1;
+ uint m_isMutable: 1;
+ };
+ uint m_flags;
+ };
+
+};
+
+class _FunctionModelItem: public _MemberModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_FunctionModelItem)
+ DECLARE_MODEL_NODE(Function)
+
+ explicit _FunctionModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _FunctionModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+ ~_FunctionModelItem();
+
+ ArgumentList arguments() const;
+
+ void addArgument(const ArgumentModelItem& item);
+
+ CodeModel::FunctionType functionType() const;
+ void setFunctionType(CodeModel::FunctionType functionType);
+
+ static std::optional<CodeModel::FunctionType> functionTypeFromName(QStringView name);
+
+ FunctionAttributes attributes() const { return m_attributes; }
+ void setAttributes(FunctionAttributes a) { m_attributes = a; }
+ void setAttribute(FunctionAttribute a, bool on = true) { m_attributes.setFlag(a, on); }
+
+ bool isDeleted() const;
+ void setDeleted(bool d);
+
+ bool isInline() const;
+ void setInline(bool isInline);
+
+ bool isHiddenFriend() const;
+ void setHiddenFriend(bool f);
+
+ bool isVariadics() const;
+ void setVariadics(bool isVariadics);
+
+ bool scopeResolution() const; // Return type has scope resolution "::ReturnType"
+ void setScopeResolution(bool v);
+
+ bool isDefaultConstructor() const;
+ bool isSpaceshipOperator() const;
+
+ bool isSimilar(const FunctionModelItem &other) const;
+
+ bool isNoExcept() const;
+
+ bool isOperator() const;
+
+ ExceptionSpecification exceptionSpecification() const;
+ void setExceptionSpecification(ExceptionSpecification e);
+
+ QString typeSystemSignature() const; // For dumping out type system files
+
+ // Private, for usage by the clang builder.
+ void _determineType();
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ CodeModel::FunctionType _determineTypeHelper() const;
+
+ ArgumentList m_arguments;
+ FunctionAttributes m_attributes;
+ CodeModel::FunctionType m_functionType = CodeModel::Normal;
+ union {
+ struct {
+ uint m_isDeleted: 1;
+ uint m_isInline: 1;
+ uint m_isVariadics: 1;
+ uint m_isHiddenFriend: 1;
+ uint m_isInvokable : 1; // Qt
+ uint m_scopeResolution: 1;
+ };
+ uint m_flags;
+ };
+ ExceptionSpecification m_exceptionSpecification = ExceptionSpecification::Unknown;
+};
+
+class _VariableModelItem: public _MemberModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Variable)
+
+ using _MemberModelItem::_MemberModelItem;
+};
+
+class _TypeDefModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(TypeDef)
+
+ explicit _TypeDefModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _TypeDefModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ TypeInfo m_type;
+};
+
+class _TemplateTypeAliasModelItem : public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(TemplateTypeAlias)
+
+ explicit _TemplateTypeAliasModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _TemplateTypeAliasModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+
+ TemplateParameterList templateParameters() const;
+ void addTemplateParameter(const TemplateParameterModelItem &templateParameter);
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ TemplateParameterList m_templateParameters;
+ TypeInfo m_type;
+};
+
+class _EnumModelItem: public _CodeModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_EnumModelItem)
+ DECLARE_MODEL_NODE(Enum)
+
+ explicit _EnumModelItem(CodeModel *model, const QString &name, int kind = __node_kind);
+ explicit _EnumModelItem(CodeModel *model, int kind = __node_kind);
+ ~_EnumModelItem();
+
+ Access accessPolicy() const;
+ void setAccessPolicy(Access accessPolicy);
+
+ bool hasValues() const { return !m_enumerators.isEmpty(); }
+ EnumeratorList enumerators() const;
+ void addEnumerator(const EnumeratorModelItem &item);
+
+ EnumKind enumKind() const { return m_enumKind; }
+ void setEnumKind(EnumKind kind) { m_enumKind = kind; }
+
+ qsizetype indexOfValue(QStringView value) const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+ bool isDeprecated() const;
+ void setDeprecated(bool d);
+
+ bool isSigned() const;
+ void setSigned(bool s);
+
+ QString underlyingType() const;
+ void setUnderlyingType(const QString &underlyingType);
+
+private:
+ QString m_underlyingType;
+ Access m_accessPolicy = Access::Public;
+ EnumeratorList m_enumerators;
+ EnumKind m_enumKind = CEnum;
+ bool m_deprecated = false;
+ bool m_signed = true;
+};
+
+class _EnumeratorModelItem: public _CodeModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_EnumeratorModelItem)
+ DECLARE_MODEL_NODE(Enumerator)
+
+ explicit _EnumeratorModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _EnumeratorModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+ ~_EnumeratorModelItem();
+
+ QString stringValue() const;
+ void setStringValue(const QString &stringValue);
+
+ EnumValue value() const { return m_value; }
+ void setValue(EnumValue v) { m_value = v; }
+
+ bool isDeprecated() const;
+ void setDeprecated(bool d);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ QString m_stringValue;
+ EnumValue m_value;
+ bool m_deprecated = false;
+};
+
+class _TemplateParameterModelItem: public _CodeModelItem
+{
+public:
+ Q_DISABLE_COPY_MOVE(_TemplateParameterModelItem)
+ DECLARE_MODEL_NODE(TemplateParameter)
+
+ explicit _TemplateParameterModelItem(CodeModel *model, int kind = __node_kind);
+ explicit _TemplateParameterModelItem(CodeModel *model, const QString &name,
+ int kind = __node_kind);
+ ~_TemplateParameterModelItem();
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+ bool defaultValue() const;
+ void setDefaultValue(bool defaultValue);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ TypeInfo m_type;
+ bool m_defaultValue = false;
+};
+
+#endif // CODEMODEL_H
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h
new file mode 100644
index 000000000..e5c429bd0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CODEMODEL_ENUMS_H
+#define CODEMODEL_ENUMS_H
+
+#include <QtCore/qflags.h>
+
+enum ReferenceType {
+ NoReference,
+ LValueReference,
+ RValueReference
+};
+
+enum EnumKind {
+ CEnum, // Standard C: enum Foo { value1, value2 }
+ AnonymousEnum, // enum { value1, value2 }
+ EnumClass // C++ 11 : enum class Foo { value1, value2 }
+};
+
+enum class Indirection
+{
+ Pointer, // int *
+ ConstPointer // int *const
+};
+
+enum class ExceptionSpecification
+{
+ Unknown,
+ NoExcept,
+ Throws
+};
+
+enum class NamespaceType
+{
+ Default,
+ Anonymous,
+ Inline
+};
+
+enum class Access
+{
+ Private,
+ Protected,
+ Public
+};
+
+enum class FunctionAttribute {
+ Abstract = 0x00000001,
+ Static = 0x00000002,
+ Virtual = 0x00000004,
+ Override = 0x00000008,
+ Final = 0x00000010,
+ Deprecated = 0x00000020, // Code annotation
+ Explicit = 0x00000040, // Constructor
+};
+
+Q_DECLARE_FLAGS(FunctionAttributes, FunctionAttribute)
+Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionAttributes)
+
+#endif // CODEMODEL_ENUMS_H
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel_fwd.h b/sources/shiboken6/ApiExtractor/parser/codemodel_fwd.h
new file mode 100644
index 000000000..f0a25c9db
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel_fwd.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+#ifndef CODEMODEL_FWD_H
+#define CODEMODEL_FWD_H
+
+#include <QtCore/QList>
+
+#include <memory>
+
+// forward declarations
+class CodeModel;
+class _ArgumentModelItem;
+class _ClassModelItem;
+class _CodeModelItem;
+class _EnumModelItem;
+class _EnumeratorModelItem;
+class _FileModelItem;
+class _FunctionModelItem;
+class _NamespaceModelItem;
+class _ScopeModelItem;
+class _TemplateParameterModelItem;
+class _TypeDefModelItem;
+class _TemplateTypeAliasModelItem;
+class _VariableModelItem;
+class _MemberModelItem;
+class TypeInfo;
+
+using ArgumentModelItem = std::shared_ptr<_ArgumentModelItem>;
+using ClassModelItem = std::shared_ptr<_ClassModelItem>;
+using CodeModelItem = std::shared_ptr<_CodeModelItem>;
+using EnumModelItem = std::shared_ptr<_EnumModelItem>;
+using EnumeratorModelItem = std::shared_ptr<_EnumeratorModelItem>;
+using FileModelItem = std::shared_ptr<_FileModelItem>;
+using FunctionModelItem = std::shared_ptr<_FunctionModelItem>;
+using NamespaceModelItem = std::shared_ptr<_NamespaceModelItem>;
+using ScopeModelItem = std::shared_ptr<_ScopeModelItem>;
+using TemplateParameterModelItem = std::shared_ptr<_TemplateParameterModelItem>;
+using TypeDefModelItem = std::shared_ptr<_TypeDefModelItem>;
+using TemplateTypeAliasModelItem = std::shared_ptr<_TemplateTypeAliasModelItem>;
+using VariableModelItem = std::shared_ptr<_VariableModelItem>;
+using MemberModelItem = std::shared_ptr<_MemberModelItem>;
+
+using ArgumentList = QList<ArgumentModelItem>;
+using ClassList = QList<ClassModelItem>;
+using ItemList = QList<CodeModelItem>;
+using EnumList = QList<EnumModelItem>;
+using EnumeratorList = QList<EnumeratorModelItem>;
+using FileList = QList<FileModelItem>;
+using FunctionList = QList<FunctionModelItem>;
+using NamespaceList = QList<NamespaceModelItem>;
+using ScopeList = QList<ScopeModelItem>;
+using TemplateParameterList = QList<TemplateParameterModelItem>;
+using TypeDefList = QList<TypeDefModelItem>;
+using TemplateTypeAliasList = QList<TemplateTypeAliasModelItem>;
+using VariableList = QList<VariableModelItem>;
+using MemberList = QList<MemberModelItem>;
+
+#endif // CODEMODEL_FWD_H
diff --git a/sources/shiboken6/ApiExtractor/parser/enumvalue.cpp b/sources/shiboken6/ApiExtractor/parser/enumvalue.cpp
new file mode 100644
index 000000000..3749e16a8
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/parser/enumvalue.cpp
@@ -0,0 +1,103 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "enumvalue.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QString>
+#include <QtCore/QTextStream>
+
+using namespace Qt::StringLiterals;
+
+QString EnumValue::toString() const
+{
+ return m_type == EnumValue::Signed
+ ? QString::number(m_value) : QString::number(m_unsignedValue);
+}
+
+QString EnumValue::toHex(int fieldWidth) const
+{
+ QString result;
+ QTextStream str(&result);
+ // Note: Qt goofes up formatting of negative padded hex numbers, it ends up
+ // with "0x00-1". Write '-' before.
+ if (isNegative())
+ str << '-';
+ str << "0x" << Qt::hex;
+ if (fieldWidth) {
+ str.setFieldWidth(fieldWidth);
+ str.setPadChar(u'0');
+ }
+ if (m_type == EnumValue::Signed)
+ str << qAbs(m_value);
+ else
+ str << m_unsignedValue;
+ return result;
+}
+
+void EnumValue::setValue(qint64 v)
+{
+ m_value = v;
+ m_type = Signed;
+}
+
+void EnumValue::setUnsignedValue(quint64 v)
+{
+ m_unsignedValue = v;
+ m_type = Unsigned;
+}
+
+EnumValue EnumValue::toUnsigned() const
+{
+ if (m_type == Unsigned)
+ return *this;
+ EnumValue result;
+ result.setUnsignedValue(m_value < 0 ? quint64(-m_value) : quint64(m_value));
+ return result;
+}
+
+bool comparesEqual(const EnumValue &lhs, const EnumValue &rhs) noexcept
+{
+ if (lhs.m_type != rhs.m_type)
+ return false;
+ return lhs.m_type == EnumValue::Signed
+ ? lhs.m_value == rhs.m_value : lhs.m_unsignedValue == rhs.m_unsignedValue;
+}
+
+void EnumValue::formatDebugHex(QDebug &d) const
+{
+ d << "0x" << Qt::hex;
+ formatDebug(d);
+ d << Qt::dec;
+}
+
+void EnumValue::formatDebug(QDebug &d) const
+{
+
+ if (m_type == EnumValue::Signed)
+ d << m_value;
+ else
+ d << m_unsignedValue << 'u';
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d,const EnumValue &v)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d.noquote();
+ d << "EnumValue(";
+ v.formatDebug(d);
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+QTextStream &operator<<(QTextStream &s, const EnumValue &v)
+{
+ if (v.m_type == EnumValue::Signed)
+ s << v.m_value;
+ else
+ s << v.m_unsignedValue;
+ return s;
+}
diff --git a/sources/shiboken6/ApiExtractor/parser/enumvalue.h b/sources/shiboken6/ApiExtractor/parser/enumvalue.h
new file mode 100644
index 000000000..bbd5a712d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/parser/enumvalue.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ENUMVALUE_H
+#define ENUMVALUE_H
+
+#include <QtCore/qtypes.h>
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/QtCompare>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+QT_FORWARD_DECLARE_CLASS(QString)
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+
+class EnumValue
+{
+public:
+ enum Type
+ {
+ Signed,
+ Unsigned
+ };
+
+ QString toString() const;
+ QString toHex(int fieldWidth = 0) const;
+
+ Type type() { return m_type; }
+ qint64 value() const { return m_value; }
+ quint64 unsignedValue() const { return m_unsignedValue; }
+ bool isNullValue() const { return m_type == Signed ? m_value == 0 : m_unsignedValue == 0u; }
+ bool isNegative() const { return m_type == Signed && m_value < 0; }
+
+ void setValue(qint64 v);
+ void setUnsignedValue(quint64 v);
+
+ EnumValue toUnsigned() const;
+
+ bool equals(const EnumValue &rhs) const;
+
+ void formatDebug(QDebug &d) const;
+ void formatDebugHex(QDebug &d) const;
+
+private:
+ friend bool comparesEqual(const EnumValue &lhs,
+ const EnumValue &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(EnumValue)
+
+#ifndef QT_NO_DEBUG_STREAM
+ friend QDebug operator<<(QDebug, const EnumValue &);
+#endif
+ friend QTextStream &operator<<(QTextStream &, const EnumValue &);
+
+ union
+ {
+ qint64 m_value = 0;
+ quint64 m_unsignedValue;
+ };
+ Type m_type = Signed;
+};
+
+#endif // ENUMVALUE_H
diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp
new file mode 100644
index 000000000..f8c5c31d8
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp
@@ -0,0 +1,624 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+#include "typeinfo.h"
+#include "codemodel.h"
+
+#include <clangparser/clangutils.h>
+#include <debughelpers_p.h>
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QStack>
+#include <QtCore/QTextStream>
+
+#include <iostream>
+
+using namespace Qt::StringLiterals;
+
+class TypeInfoData : public QSharedData
+{
+
+public:
+ TypeInfoData();
+
+ bool isVoid() const;
+ bool equals(const TypeInfoData &other) const;
+ bool isStdType() const;
+ void simplifyStdType();
+
+ QStringList m_qualifiedName;
+ QStringList m_arrayElements;
+ TypeInfo::TypeInfoList m_arguments;
+ TypeInfo::TypeInfoList m_instantiations;
+ TypeInfo::Indirections m_indirections;
+
+ union {
+ uint flags;
+
+ struct {
+ uint m_constant: 1;
+ uint m_volatile: 1;
+ uint m_functionPointer: 1;
+ uint m_padding: 29;
+ };
+ };
+
+ ReferenceType m_referenceType = NoReference;
+};
+
+TypeInfoData::TypeInfoData() : flags(0)
+{
+}
+
+TypeInfo::TypeInfo() : d(new TypeInfoData)
+{
+}
+
+TypeInfo::~TypeInfo() = default;
+TypeInfo::TypeInfo(const TypeInfo &) = default;
+TypeInfo& TypeInfo::operator=(const TypeInfo &) = default;
+TypeInfo::TypeInfo(TypeInfo &&) noexcept = default;
+TypeInfo &TypeInfo::operator=(TypeInfo &&) noexcept = default;
+
+static inline TypeInfo createType(const QString &name)
+{
+ TypeInfo result;
+ result.addName(name);
+ return result;
+}
+
+TypeInfo TypeInfo::voidType()
+{
+ static const TypeInfo result = createType(u"void"_s);
+ return result;
+}
+
+TypeInfo TypeInfo::varArgsType()
+{
+ static const TypeInfo result = createType(u"..."_s);
+ return result;
+}
+
+TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs)
+{
+ TypeInfo __result = __lhs;
+
+ __result.setConstant(__result.isConstant() || __rhs.isConstant());
+ __result.setVolatile(__result.isVolatile() || __rhs.isVolatile());
+ if (__rhs.referenceType() > __result.referenceType())
+ __result.setReferenceType(__rhs.referenceType());
+
+ const auto indirections = __rhs.indirectionsV();
+ for (auto i : indirections)
+ __result.addIndirection(i);
+
+ __result.setArrayElements(__result.arrayElements() + __rhs.arrayElements());
+
+ const auto &instantiations = __rhs.instantiations();
+ for (const auto &i : instantiations)
+ __result.addInstantiation(i);
+
+ return __result;
+}
+
+QStringList TypeInfo::qualifiedName() const
+{
+ return d->m_qualifiedName;
+}
+
+void TypeInfo::setQualifiedName(const QStringList &qualified_name)
+{
+ if (d->m_qualifiedName != qualified_name)
+ d->m_qualifiedName = qualified_name;
+}
+
+void TypeInfo::addName(const QString &n)
+{
+ d->m_qualifiedName.append(n);
+}
+
+bool TypeInfoData::isVoid() const
+{
+ return m_indirections.isEmpty() && m_referenceType == NoReference
+ && m_arguments.isEmpty() && m_arrayElements.isEmpty()
+ && m_instantiations.isEmpty()
+ && m_qualifiedName.size() == 1
+ && m_qualifiedName.constFirst() == u"void";
+}
+
+bool TypeInfo::isVoid() const
+{
+ return d->isVoid();
+}
+
+bool TypeInfo::isConstant() const
+{
+ return d->m_constant;
+}
+
+void TypeInfo::setConstant(bool is)
+{
+ if (d->m_constant != is)
+ d->m_constant = is;
+}
+
+bool TypeInfo::isVolatile() const
+{
+ return d->m_volatile;
+}
+
+void TypeInfo::setVolatile(bool is)
+{
+ if (d->m_volatile != is)
+ d->m_volatile = is;
+}
+
+ReferenceType TypeInfo::referenceType() const
+{
+ return d->m_referenceType;
+}
+
+void TypeInfo::setReferenceType(ReferenceType r)
+{
+ if (d->m_referenceType != r)
+ d->m_referenceType = r;
+}
+
+const TypeInfo::Indirections &TypeInfo::indirectionsV() const
+{
+ return d->m_indirections;
+}
+
+void TypeInfo::setIndirectionsV(const TypeInfo::Indirections &i)
+{
+ if (d->m_indirections != i)
+ d->m_indirections = i;
+}
+
+int TypeInfo::indirections() const
+{
+ return d->m_indirections.size();
+}
+
+void TypeInfo::setIndirections(int indirections)
+{
+ const Indirections newValue(indirections, Indirection::Pointer);
+ if (d->m_indirections != newValue)
+ d->m_indirections = newValue;
+}
+
+void TypeInfo::addIndirection(Indirection i)
+{
+ d->m_indirections.append(i);
+}
+
+bool TypeInfo::isFunctionPointer() const
+{
+ return d->m_functionPointer;
+}
+
+void TypeInfo::setFunctionPointer(bool is)
+{
+ if (d->m_functionPointer != is)
+ d->m_functionPointer = is;
+}
+
+const QStringList &TypeInfo::arrayElements() const
+{
+ return d->m_arrayElements;
+}
+
+void TypeInfo::setArrayElements(const QStringList &arrayElements)
+{
+ if (d->m_arrayElements != arrayElements)
+ d->m_arrayElements = arrayElements;
+}
+
+void TypeInfo::addArrayElement(const QString &a)
+{
+ d->m_arrayElements.append(a);
+}
+
+const QList<TypeInfo> &TypeInfo::arguments() const
+{
+ return d->m_arguments;
+}
+
+void TypeInfo::setArguments(const QList<TypeInfo> &arguments)
+{
+ if (d->m_arguments != arguments)
+ d->m_arguments = arguments;
+}
+
+void TypeInfo::addArgument(const TypeInfo &arg)
+{
+ d->m_arguments.append(arg);
+}
+
+const TypeInfo::TypeInfoList &TypeInfo::instantiations() const
+{
+ return d->m_instantiations;
+}
+
+TypeInfo::TypeInfoList &TypeInfo::instantiations()
+{
+ return d->m_instantiations;
+}
+
+void TypeInfo::setInstantiations(const TypeInfoList &i)
+{
+ if (d->m_instantiations != i)
+ d->m_instantiations = i;
+}
+
+void TypeInfo::addInstantiation(const TypeInfo &i)
+{
+ d->m_instantiations.append(i);
+}
+
+void TypeInfo::clearInstantiations()
+{
+ if (!d->m_instantiations.isEmpty())
+ d->m_instantiations.clear();
+}
+
+bool TypeInfo::isPlain() const
+{
+ return d->m_constant == 0 && d->m_volatile == 0 && d->m_referenceType == NoReference
+ && d->m_indirections.isEmpty() && d->m_arrayElements.isEmpty();
+}
+
+TypeInfo TypeInfo::resolveType(TypeInfo const &__type, const ScopeModelItem &__scope)
+{
+ CodeModel *__model = __scope->model();
+ Q_ASSERT(__model != nullptr);
+
+ return TypeInfo::resolveType(__model->findItem(__type.qualifiedName(), __scope), __type, __scope);
+}
+
+TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, const ScopeModelItem &__scope)
+{
+ // Copy the type and replace with the proper qualified name. This
+ // only makes sence to do if we're actually getting a resolved
+ // type with a namespace. We only get this if the returned type
+ // has more than 2 entries in the qualified name... This test
+ // could be improved by returning if the type was found or not.
+ TypeInfo otherType(__type);
+ if (__item && __item->qualifiedName().size() > 1) {
+ otherType.setQualifiedName(__item->qualifiedName());
+ }
+
+ if (TypeDefModelItem __typedef = std::dynamic_pointer_cast<_TypeDefModelItem>(__item)) {
+ const TypeInfo combined = TypeInfo::combine(__typedef->type(), otherType);
+ const CodeModelItem nextItem = __scope->model()->findItem(combined.qualifiedName(), __scope);
+ if (!nextItem)
+ return combined;
+ // PYSIDE-362, prevent recursion on opaque structs like
+ // typedef struct xcb_connection_t xcb_connection_t;
+ if (nextItem.get() ==__item.get()) {
+ std::cerr << "** WARNING Bailing out recursion of " << __FUNCTION__
+ << "() on " << qPrintable(__type.qualifiedName().join(u"::"_s))
+ << std::endl;
+ return otherType;
+ }
+ return resolveType(nextItem, combined, __scope);
+ }
+
+ if (TemplateTypeAliasModelItem templateTypeAlias = std::dynamic_pointer_cast<_TemplateTypeAliasModelItem>(__item)) {
+
+ TypeInfo combined = TypeInfo::combine(templateTypeAlias->type(), otherType);
+ // For the alias "template<typename T> using QList = QVector<T>" with
+ // other="QList<int>", replace the instantiations to obtain "QVector<int>".
+ auto aliasInstantiations = templateTypeAlias->type().instantiations();
+ const auto &concreteInstantiations = otherType.instantiations();
+ const auto count = qMin(aliasInstantiations.size(), concreteInstantiations.size());
+ for (qsizetype i = 0; i < count; ++i)
+ aliasInstantiations[i] = concreteInstantiations.at(i);
+ combined.setInstantiations(aliasInstantiations);
+ const CodeModelItem nextItem = CodeModel::findItem(combined.qualifiedName(), __scope);
+ if (!nextItem)
+ return combined;
+ return resolveType(nextItem, combined, __scope);
+ }
+
+ return otherType;
+}
+
+// Handler for clang::parseTemplateArgumentList() that populates
+// TypeInfo::m_instantiations
+class TypeInfoTemplateArgumentHandler
+{
+public:
+ explicit TypeInfoTemplateArgumentHandler(TypeInfo *t)
+ {
+ m_parseStack.append(t);
+ }
+
+ void operator()(int level, QStringView name)
+ {
+ if (level > m_parseStack.size()) {
+ Q_ASSERT(!top()->instantiations().isEmpty());
+ m_parseStack.push(&top()->instantiations().back());
+ }
+ while (level < m_parseStack.size())
+ m_parseStack.pop();
+ TypeInfo instantiation;
+ if (name.startsWith(u"const ")) {
+ instantiation.setConstant(true);
+ name = name.mid(6);
+ }
+ instantiation.setQualifiedName(qualifiedName(name));
+ top()->addInstantiation(instantiation);
+ }
+
+private:
+ TypeInfo *top() const { return m_parseStack.back(); }
+
+ static QStringList qualifiedName(QStringView name)
+ {
+ QStringList result;
+ const auto nameParts = name.split(u"::");
+ result.reserve(nameParts.size());
+ for (const auto &p : nameParts)
+ result.append(p.toString());
+ return result;
+ }
+
+ QStack<TypeInfo *> m_parseStack;
+};
+
+std::pair<qsizetype, qsizetype>
+ TypeInfo::parseTemplateArgumentList(const QString &l, qsizetype from)
+{
+ return clang::parseTemplateArgumentList(l, clang::TemplateArgumentHandler(TypeInfoTemplateArgumentHandler(this)), from);
+}
+
+QString TypeInfo::toString() const
+{
+ QString tmp;
+ if (isConstant())
+ tmp += u"const "_s;
+
+ if (isVolatile())
+ tmp += u"volatile "_s;
+
+ tmp += d->m_qualifiedName.join(u"::"_s);
+
+ if (const auto instantiationCount = d->m_instantiations.size()) {
+ tmp += u'<';
+ for (qsizetype i = 0; i < instantiationCount; ++i) {
+ if (i)
+ tmp += u", "_s;
+ tmp += d->m_instantiations.at(i).toString();
+ }
+ if (tmp.endsWith(u'>'))
+ tmp += u' ';
+ tmp += u'>';
+ }
+
+ for (Indirection i : d->m_indirections)
+ tmp.append(indirectionKeyword(i));
+
+ switch (referenceType()) {
+ case NoReference:
+ break;
+ case LValueReference:
+ tmp += u'&';
+ break;
+ case RValueReference:
+ tmp += u"&&"_s;
+ break;
+ }
+
+ if (isFunctionPointer()) {
+ tmp += u" (*)("_s;
+ for (qsizetype i = 0; i < d->m_arguments.size(); ++i) {
+ if (i != 0)
+ tmp += u", "_s;
+
+ tmp += d->m_arguments.at(i).toString();
+ }
+ tmp += u')';
+ }
+
+ for (const QString &elt : d->m_arrayElements)
+ tmp += u'[' + elt + u']';
+
+ return tmp;
+}
+
+bool TypeInfoData::equals(const TypeInfoData &other) const
+{
+ if (m_arrayElements.size() != other.m_arrayElements.size())
+ return false;
+
+#if defined (RXX_CHECK_ARRAY_ELEMENTS) // ### it'll break
+ for (qsizetype i = 0; i < arrayElements().size(); ++i) {
+ QString elt1 = arrayElements().at(i).trimmed();
+ QString elt2 = other.arrayElements().at(i).trimmed();
+
+ if (elt1 != elt2)
+ return false;
+ }
+#endif
+
+ return flags == other.flags
+ && m_qualifiedName == other.m_qualifiedName
+ && (!m_functionPointer || m_arguments == other.m_arguments)
+ && m_instantiations == other.m_instantiations;
+}
+
+
+bool comparesEqual(const TypeInfo &lhs, const TypeInfo &rhs) noexcept
+{
+ return lhs.d.data() == rhs.d.data() || lhs.d->equals(*rhs.d);
+}
+
+QString TypeInfo::indirectionKeyword(Indirection i)
+{
+ return i == Indirection::Pointer ? "*"_L1 : "*const"_L1;
+}
+
+bool TypeInfo::stripLeadingConst(QString *s)
+{
+ return stripLeadingQualifier("const"_L1, s);
+}
+
+bool TypeInfo::stripLeadingVolatile(QString *s)
+{
+ return stripLeadingQualifier("volatile"_L1, s);
+}
+
+bool TypeInfo::stripLeadingQualifier(QLatin1StringView qualifier, QString *s)
+{
+ // "const int x"
+ const auto qualifierSize = qualifier.size();
+ if (s->size() < qualifierSize + 1 || !s->startsWith(qualifier)
+ || !s->at(qualifierSize).isSpace()) {
+ return false;
+ }
+ s->remove(0, qualifierSize + 1);
+ while (!s->isEmpty() && s->at(0).isSpace())
+ s->remove(0, 1);
+ return true;
+}
+
+// Strip all const/volatile/*/&
+void TypeInfo::stripQualifiers(QString *s)
+{
+ stripLeadingConst(s);
+ stripLeadingVolatile(s);
+ while (s->endsWith(u'&') || s->endsWith(u'*') || s->endsWith(u' '))
+ s->chop(1);
+}
+
+// Helper functionality to simplify a raw standard type as returned by
+// clang_getCanonicalType() for g++ standard containers from
+// "std::__cxx11::list<int, std::allocator<int> >" or
+// "std::__1::list<int, std::allocator<int> >" -> "std::list<int>".
+
+bool TypeInfoData::isStdType() const
+{
+ return m_qualifiedName.size() > 1
+ && m_qualifiedName.constFirst() == u"std";
+}
+
+bool TypeInfo::isStdType() const
+{
+ return d->isStdType();
+}
+
+static inline bool discardStdType(const QString &name)
+{
+ return name == u"allocator" || name == u"less";
+}
+
+void TypeInfoData::simplifyStdType()
+{
+ Q_ASSERT(isStdType());
+ if (m_qualifiedName.at(1).startsWith(u"__"))
+ m_qualifiedName.removeAt(1);
+ for (auto t = m_instantiations.size() - 1; t >= 0; --t) {
+ if (m_instantiations.at(t).isStdType()) {
+ if (discardStdType(m_instantiations.at(t).qualifiedName().constLast()))
+ m_instantiations.removeAt(t);
+ else
+ m_instantiations[t].simplifyStdType();
+ }
+ }
+}
+
+void TypeInfo::simplifyStdType()
+{
+ if (isStdType())
+ d->simplifyStdType();
+}
+
+void TypeInfo::formatTypeSystemSignature(QTextStream &str) const
+{
+ if (d->m_constant)
+ str << "const ";
+ str << d->m_qualifiedName.join(u"::"_s);
+ switch (d->m_referenceType) {
+ case NoReference:
+ break;
+ case LValueReference:
+ str << '&';
+ break;
+ case RValueReference:
+ str << "&&";
+ break;
+ }
+ for (auto i : d->m_indirections) {
+ switch (i) {
+ case Indirection::Pointer:
+ str << '*';
+ break;
+ case Indirection::ConstPointer:
+ str << "* const";
+ break;
+ }
+ }
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void TypeInfo::formatDebug(QDebug &debug) const
+{
+ debug << '"';
+ formatSequence(debug, d->m_qualifiedName.begin(), d->m_qualifiedName.end(), "\", \"");
+ debug << '"';
+ if (d->m_constant)
+ debug << ", [const]";
+ if (d->m_volatile)
+ debug << ", [volatile]";
+ if (!d->m_indirections.isEmpty()) {
+ debug << ", indirections=";
+ for (auto i : d->m_indirections)
+ debug << ' ' << TypeInfo::indirectionKeyword(i);
+ }
+ switch (d->m_referenceType) {
+ case NoReference:
+ break;
+ case LValueReference:
+ debug << ", [ref]";
+ break;
+ case RValueReference:
+ debug << ", [rvalref]";
+ break;
+ }
+ if (!d->m_instantiations.isEmpty()) {
+ debug << ", template<";
+ formatSequence(debug, d->m_instantiations.begin(), d->m_instantiations.end());
+ debug << '>';
+ }
+ if (d->m_functionPointer) {
+ debug << ", function ptr(";
+ formatSequence(debug, d->m_arguments.begin(), d->m_arguments.end());
+ debug << ')';
+ }
+ if (!d->m_arrayElements.isEmpty()) {
+ debug << ", array[" << d->m_arrayElements.size() << "][";
+ formatSequence(debug, d->m_arrayElements.begin(), d->m_arrayElements.end());
+ debug << ']';
+ }
+}
+
+QDebug operator<<(QDebug d, const TypeInfo &t)
+{
+ QDebugStateSaver s(d);
+ const int verbosity = d.verbosity();
+ d.noquote();
+ d.nospace();
+ d << "TypeInfo(";
+ if (verbosity > 2)
+ t.formatDebug(d);
+ else
+ d << t.toString();
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.h b/sources/shiboken6/ApiExtractor/parser/typeinfo.h
new file mode 100644
index 000000000..e4f363b67
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.h
@@ -0,0 +1,128 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPEINFO_H
+#define TYPEINFO_H
+
+#include "codemodel_enums.h"
+#include "codemodel_fwd.h"
+
+#include <QtCore/QString>
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QtCompare>
+#include <QtCore/QStringList>
+
+#include <utility>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+
+class TypeInfoData;
+
+class TypeInfo
+{
+ friend class TypeParser;
+public:
+ using Indirections = QList<Indirection>;
+ using TypeInfoList = QList<TypeInfo>;
+
+ TypeInfo();
+ ~TypeInfo();
+ TypeInfo(const TypeInfo &);
+ TypeInfo& operator=(const TypeInfo &);
+ TypeInfo(TypeInfo &&) noexcept;
+ TypeInfo &operator=(TypeInfo &&) noexcept;
+
+ static TypeInfo voidType();
+ static TypeInfo varArgsType();
+
+ QStringList qualifiedName() const;
+ void setQualifiedName(const QStringList &qualified_name);
+ void addName(const QString &);
+
+ bool isVoid() const;
+
+ bool isConstant() const;
+ void setConstant(bool is);
+
+ bool isVolatile() const;
+
+ void setVolatile(bool is);
+
+ ReferenceType referenceType() const;
+ void setReferenceType(ReferenceType r);
+
+ const Indirections &indirectionsV() const;
+ void setIndirectionsV(const Indirections &i);
+ void addIndirection(Indirection i);
+
+ // "Legacy", rename?
+ int indirections() const;
+
+ void setIndirections(int indirections);
+
+ bool isFunctionPointer() const;
+ void setFunctionPointer(bool is);
+
+ const QStringList &arrayElements() const;
+ void setArrayElements(const QStringList &arrayElements);
+
+ void addArrayElement(const QString &a);
+
+ const TypeInfoList &arguments() const;
+ void setArguments(const TypeInfoList &arguments);
+ void addArgument(const TypeInfo &arg);
+
+ const TypeInfoList &instantiations() const;
+ TypeInfoList &instantiations(); // for parsing only
+ void setInstantiations(const TypeInfoList &i);
+ void addInstantiation(const TypeInfo &i);
+ void clearInstantiations();
+
+ bool isPlain() const; // neither const,volatile, no indirections/references, array
+
+ bool isStdType() const;
+
+ std::pair<qsizetype, qsizetype>
+ parseTemplateArgumentList(const QString &l, qsizetype from = 0);
+
+ // ### arrays and templates??
+
+ QString toString() const;
+
+ static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs);
+ static TypeInfo resolveType(TypeInfo const &__type, const ScopeModelItem &__scope);
+
+ void formatTypeSystemSignature(QTextStream &str) const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+ static QString indirectionKeyword(Indirection i);
+
+ static bool stripLeadingConst(QString *s);
+ static bool stripLeadingVolatile(QString *s);
+ static bool stripLeadingQualifier(QLatin1StringView qualifier, QString *s);
+ static void stripQualifiers(QString *s);
+
+ void simplifyStdType();
+
+private:
+ friend bool comparesEqual(const TypeInfo &lhs,
+ const TypeInfo &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(TypeInfo)
+
+ QSharedDataPointer<TypeInfoData> d;
+
+ friend class TypeInfoTemplateArgumentHandler;
+
+ static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, const ScopeModelItem &__scope);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const TypeInfo &t);
+#endif
+
+#endif // TYPEINFO_H
diff --git a/sources/shiboken6/ApiExtractor/predefined_templates.cpp b/sources/shiboken6/ApiExtractor/predefined_templates.cpp
new file mode 100644
index 000000000..992f735ac
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/predefined_templates.cpp
@@ -0,0 +1,276 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "predefined_templates.h"
+
+#include "qtcompat.h"
+
+using namespace Qt::StringLiterals;
+
+static QString pySequenceToCppContainer(const QString &insertFunc,
+ bool reserve)
+{
+ QString result = u"(%out).clear();\n"_s;
+ if (reserve) {
+ result += uR"(if (PyList_Check(%in)) {
+ const Py_ssize_t size = PySequence_Size(%in);
+ if (size > 10)
+ (%out).reserve(size);
+}
+
+)"_s;
+ }
+
+ result += uR"(Shiboken::AutoDecRef it(PyObject_GetIter(%in));
+while (true) {
+ Shiboken::AutoDecRef pyItem(PyIter_Next(it.object()));
+ if (pyItem.isNull()) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ break;
+ }
+ %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
+ (%out).)"_s;
+
+ result += insertFunc;
+ result += uR"((cppItem);
+}
+)"_s;
+ return result;
+}
+
+// Convert a sequence to a limited/fixed array
+static QString pySequenceToCppArray()
+{
+ return uR"(Shiboken::AutoDecRef it(PyObject_GetIter(%in));
+for (auto oit = std::begin(%out), oend = std::end(%out); oit != oend; ++oit) {
+ Shiboken::AutoDecRef pyItem(PyIter_Next(it.object()));
+ if (pyItem.isNull()) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ break;
+ }
+ %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
+ *oit = cppItem;
+}
+)"_s;
+}
+
+static constexpr auto stlMapKeyAccessor = "->first"_L1;
+static constexpr auto stlMapValueAccessor = "->second"_L1;
+static constexpr auto qtMapKeyAccessor = ".key()"_L1;
+static constexpr auto qtMapValueAccessor = ".value()"_L1;
+
+static QString cppMapToPyDict(bool isQMap)
+{
+ return uR"(PyObject *%out = PyDict_New();
+for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ++it) {
+ const auto &key = it)"_s
+ + (isQMap ? qtMapKeyAccessor : stlMapKeyAccessor)
+ + uR"(;
+ const auto &value = it)"_s
+ + (isQMap ? qtMapValueAccessor : stlMapValueAccessor)
+ + uR"(;
+ PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
+ PyObject *pyValue = %CONVERTTOPYTHON[%INTYPE_1](value);
+ PyDict_SetItem(%out, pyKey, pyValue);
+ Py_DECREF(pyKey);
+ Py_DECREF(pyValue);
+}
+return %out;
+)"_s;
+}
+
+static QString pyDictToCppMap(bool isQMap)
+{
+ return uR"(PyObject *key;
+PyObject *value;
+%out.clear();
+Py_ssize_t pos = 0;
+while (PyDict_Next(%in, &pos, &key, &value)) {
+ %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
+ %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
+ %out.insert()"_s
+ // STL needs a pair
+ + (isQMap ? u"cppKey, cppValue"_s : u"{cppKey, cppValue}"_s) + uR"();
+}
+)"_s;
+}
+
+// Convert a STL or Qt multi map to Dict of Lists using upperBound()
+static QString cppMultiMapToPyDict(bool isQMultiMap)
+{
+ return uR"(PyObject *%out = PyDict_New();
+ for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ) {
+ const auto &key = it)"_s
+ + (isQMultiMap ? qtMapKeyAccessor : stlMapKeyAccessor)
+ + uR"(;
+ PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
+ auto upper = %in.)"_s
+ + (isQMultiMap ? u"upperBound"_s : u"upper_bound"_s)
+ + uR"((key);
+ const auto count = Py_ssize_t(std::distance(it, upper));
+ PyObject *pyValues = PyList_New(count);
+ Py_ssize_t idx = 0;
+ for (; it != upper; ++it, ++idx) {
+ const auto &cppItem = it.value();
+ PyList_SET_ITEM(pyValues, idx, %CONVERTTOPYTHON[%INTYPE_1](cppItem));
+ }
+ PyDict_SetItem(%out, pyKey, pyValues);
+ Py_DECREF(pyKey);
+ }
+ return %out;
+)"_s;
+}
+
+// Convert a STL or Qt multi hash to Dict of Lists using equalRange()
+static QString cppMultiHashToPyDict(bool isQMultiHash)
+{
+ return uR"(PyObject *%out = PyDict_New();
+ for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ) {
+ const auto &key = it)"_s
+ + (isQMultiHash ? qtMapKeyAccessor : stlMapKeyAccessor)
+ + uR"(;
+ PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
+ auto range = %in.equal_range(key);
+ const auto count = Py_ssize_t(std::distance(range.first, range.second));
+ PyObject *pyValues = PyList_New(count);
+ Py_ssize_t idx = 0;
+ for (; it != range.second; ++it, ++idx) {
+ const auto &cppItem = it.value();
+ PyList_SET_ITEM(pyValues, idx, %CONVERTTOPYTHON[%INTYPE_1](cppItem));
+ }
+ PyDict_SetItem(%out, pyKey, pyValues);
+ Py_DECREF(pyKey);
+ }
+ return %out;
+)"_s;
+}
+
+// Convert Dict of Lists to a STL or Qt multi hash/map
+static QString pyDictToCppMultiHash(bool isQMultiHash)
+{
+ return uR"(PyObject *key;
+ PyObject *values;
+ %out.clear();
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(%in, &pos, &key, &values)) {
+ %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
+ const Py_ssize_t size = PySequence_Size(values);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ Shiboken::AutoDecRef value(PySequence_GetItem(values, i));
+ %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
+ %out.insert()"_s
+ + (isQMultiHash ? u"cppKey, cppValue"_s : u"{cppKey, cppValue}"_s)
+ + uR"();
+ }
+ }
+)"_s;
+}
+
+const PredefinedTemplates &predefinedTemplates()
+{
+ static const PredefinedTemplates result{
+ {u"shiboken_conversion_pylong_to_cpp"_s,
+ u"%out = %OUTTYPE(PyLong_AsLong(%in));\n"_s},
+
+ // QPair/std::pair
+ {u"shiboken_conversion_pysequence_to_cpppair"_s,
+ uR"(%out.first = %CONVERTTOCPP[%OUTTYPE_0](PySequence_Fast_GET_ITEM(%in, 0));
+%out.second = %CONVERTTOCPP[%OUTTYPE_1](PySequence_Fast_GET_ITEM(%in, 1));
+)"_s},
+
+ {u"shiboken_conversion_cpppair_to_pytuple"_s,
+ uR"(PyObject *%out = PyTuple_New(2);
+PyTuple_SET_ITEM(%out, 0, %CONVERTTOPYTHON[%INTYPE_0](%in.first));
+PyTuple_SET_ITEM(%out, 1, %CONVERTTOPYTHON[%INTYPE_1](%in.second));
+return %out;
+)"_s},
+
+ // Sequential containers
+ {u"shiboken_conversion_cppsequence_to_pylist"_s,
+ uR"(PyObject *%out = PyList_New(Py_ssize_t(%in.size()));
+Py_ssize_t idx = 0;
+for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ++it, ++idx) {
+ const auto &cppItem = *it;
+ PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
+}
+return %out;)"_s},
+
+ // PySet
+ {u"shiboken_conversion_cppsequence_to_pyset"_s,
+ uR"(PyObject *%out = PySet_New(nullptr);
+for (const auto &cppItem : %in) {
+ PySet_Add(%out, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
+}
+return %out;)"_s},
+
+ {u"shiboken_conversion_pyiterable_to_cppsequentialcontainer"_s,
+ pySequenceToCppContainer(u"push_back"_s, false)},
+ {u"shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve"_s,
+ pySequenceToCppContainer(u"push_back"_s, true)},
+ {u"shiboken_conversion_pyiterable_to_cpparray"_s,
+ pySequenceToCppArray()},
+ {u"shiboken_conversion_pyiterable_to_cppsetcontainer"_s,
+ pySequenceToCppContainer(u"insert"_s, false)},
+
+ // Maps
+ {u"shiboken_conversion_stdmap_to_pydict"_s,
+ cppMapToPyDict(false)},
+ {u"shiboken_conversion_qmap_to_pydict"_s,
+ cppMapToPyDict(true)},
+ {u"shiboken_conversion_pydict_to_stdmap"_s,
+ pyDictToCppMap(false)},
+ {u"shiboken_conversion_pydict_to_qmap"_s,
+ pyDictToCppMap(true)},
+
+ // Multi maps
+ {u"shiboken_conversion_stdmultimap_to_pydict"_s,
+ cppMultiMapToPyDict(false)},
+ {u"shiboken_conversion_qmultimap_to_pydict"_s,
+ cppMultiMapToPyDict(true)},
+
+ // Multi hashes
+ {u"shiboken_conversion_stdunorderedmultimap_to_pydict"_s,
+ cppMultiHashToPyDict(false)},
+ {u"shiboken_conversion_qmultihash_to_pydict"_s,
+ cppMultiHashToPyDict(true)},
+
+ // STL multi hash/map
+ {u"shiboken_conversion_pydict_to_stdmultimap"_s,
+ pyDictToCppMultiHash(false)},
+ {u"shiboken_conversion_pydict_to_qmultihash"_s,
+ pyDictToCppMultiHash(true)}
+ };
+
+ return result;
+}
+
+QByteArray containerTypeSystemSnippet(const char *name, const char *type,
+ const char *include,
+ const char *nativeToTarget,
+ const char *targetToNativeType,
+ const char *targetToNative)
+{
+ QByteArray result = QByteArrayLiteral("<container-type name=\"")
+ + name + QByteArrayLiteral("\" type=\"") + type + R"(">
+ <include file-name=")" + include + R"(" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ <insert-template name=")" + nativeToTarget + R"("/>
+ </native-to-target>
+)";
+ if (targetToNativeType != nullptr) {
+ result += QByteArrayLiteral(R"( <target-to-native>
+ <add-conversion type=")") + targetToNativeType
+ + QByteArrayLiteral(R"(">
+ <insert-template name=")") + targetToNative + QByteArrayLiteral(R"("/>
+ </add-conversion>
+ </target-to-native>
+)");
+ }
+result += QByteArrayLiteral(R"( </conversion-rule>
+</container-type>
+)");
+ return result;
+}
diff --git a/sources/shiboken6/ApiExtractor/predefined_templates.h b/sources/shiboken6/ApiExtractor/predefined_templates.h
new file mode 100644
index 000000000..0cc2c7f32
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/predefined_templates.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PREDEFINED_TEMPLATES_H
+#define PREDEFINED_TEMPLATES_H
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+struct PredefinedTemplate
+{
+ QString name;
+ QString content;
+};
+
+using PredefinedTemplates = QList<PredefinedTemplate>;
+
+const PredefinedTemplates &predefinedTemplates();
+
+// Create an XML snippet for a container type.
+QByteArray containerTypeSystemSnippet(const char *name, const char *type,
+ const char *include,
+ const char *nativeToTarget,
+ const char *targetToNativeType = nullptr,
+ const char *targetToNative = nullptr);
+
+#endif // PREDEFINED_TEMPLATES_H
diff --git a/sources/shiboken6/ApiExtractor/primitivetypeentry.h b/sources/shiboken6/ApiExtractor/primitivetypeentry.h
new file mode 100644
index 000000000..6faaf7a61
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/primitivetypeentry.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PRIMITIVETYPEENTRY_H
+#define PRIMITIVETYPEENTRY_H
+
+#include "typesystem.h"
+#include "customconversion_typedefs.h"
+
+class PrimitiveTypeEntryPrivate;
+
+/// A PrimitiveTypeEntry is user-defined type with conversion rules, a C++
+/// primitive type for which a PrimitiveTypeConverter exists in libshiboken
+/// or a typedef to a C++ primitive type as determined by AbstractMetaBuilder.
+class PrimitiveTypeEntry : public TypeEntry
+{
+public:
+ explicit PrimitiveTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ QString defaultConstructor() const;
+ void setDefaultConstructor(const QString& defaultConstructor);
+ bool hasDefaultConstructor() const;
+
+ /**
+ * The PrimitiveTypeEntry pointed by this type entry if it
+ * represents a typedef).
+ * \return the type referenced by the typedef, or a null pointer
+ * if the current object is not an typedef
+ */
+ PrimitiveTypeEntryPtr referencedTypeEntry() const;
+
+ /**
+ * Defines type referenced by this entry.
+ * \param referencedTypeEntry type referenced by this entry
+ */
+ void setReferencedTypeEntry(PrimitiveTypeEntryPtr referencedTypeEntry);
+
+ /// Returns whether this entry references another entry.
+ bool referencesType() const;
+
+ bool preferredTargetLangType() const;
+ void setPreferredTargetLangType(bool b);
+
+ bool hasCustomConversion() const;
+ void setCustomConversion(const CustomConversionPtr &customConversion);
+ CustomConversionPtr customConversion() const;
+
+ TypeEntry *clone() const override;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+protected:
+ explicit PrimitiveTypeEntry(PrimitiveTypeEntryPrivate *d);
+};
+
+/// Finds the most basic primitive type that the typedef represents,
+/// i.e. a type that is not an typedef'ed.
+/// \return the most basic non-typedef'ed primitive type represented
+/// by this typedef or self in case it is not a reference.
+PrimitiveTypeEntryCPtr basicReferencedTypeEntry(const PrimitiveTypeEntryCPtr &e);
+PrimitiveTypeEntryCPtr basicReferencedTypeEntry(const TypeEntryCPtr &e);
+
+/// Finds the basic primitive type that the typedef represents
+/// and was explicitly specified in the type system.
+/// \return the basic primitive type that was explicitly specified in
+/// the type system.
+PrimitiveTypeEntryCPtr basicReferencedNonBuiltinTypeEntry(const PrimitiveTypeEntryCPtr &e);
+
+#endif // PRIMITIVETYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/propertyspec.cpp b/sources/shiboken6/ApiExtractor/propertyspec.cpp
new file mode 100644
index 000000000..32b756fad
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/propertyspec.cpp
@@ -0,0 +1,347 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "propertyspec.h"
+#include "abstractmetalang.h"
+#include "abstractmetabuilder_p.h"
+#include "abstractmetatype.h"
+#include "documentation.h"
+#include "messages.h"
+#include "complextypeentry.h"
+#include "typeinfo.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QHash>
+
+#ifndef QT_NO_DEBUG_STREAM
+# include <QtCore/QDebug>
+#endif
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+class QPropertySpecData : public QSharedData
+{
+public:
+ QPropertySpecData(const TypeSystemProperty &ts,
+ const AbstractMetaType &type) :
+ m_name(ts.name),
+ m_read(ts.read),
+ m_write(ts.write),
+ m_designable(ts.designable),
+ m_reset(ts.reset),
+ m_notify(ts.notify),
+ m_type(type),
+ m_generateGetSetDef(ts.generateGetSetDef)
+ {
+ }
+
+ QString m_name;
+ QString m_read;
+ QString m_write;
+ QString m_designable;
+ QString m_reset;
+ QString m_notify;
+ Documentation m_documentation;
+ AbstractMetaType m_type;
+ int m_index = -1;
+ // Indicates whether actual code is generated instead of relying on libpyside.
+ bool m_generateGetSetDef = false;
+};
+
+QPropertySpec::QPropertySpec(const TypeSystemProperty &ts,
+ const AbstractMetaType &type) :
+ d(new QPropertySpecData(ts, type))
+{
+}
+
+QPropertySpec::QPropertySpec(const QPropertySpec &) = default;
+QPropertySpec &QPropertySpec::operator=(const QPropertySpec &) = default;
+QPropertySpec::QPropertySpec(QPropertySpec &&) noexcept = default;
+QPropertySpec &QPropertySpec::operator=(QPropertySpec &&) noexcept = default;
+QPropertySpec::~QPropertySpec() = default;
+
+const AbstractMetaType &QPropertySpec::type() const
+{
+ return d->m_type;
+}
+
+void QPropertySpec::setType(const AbstractMetaType &t)
+{
+ if (d->m_type != t)
+ d->m_type = t;
+}
+
+TypeEntryCPtr QPropertySpec::typeEntry() const
+{
+ return d->m_type.typeEntry();
+}
+
+QString QPropertySpec::name() const
+{
+ return d->m_name;
+}
+
+void QPropertySpec::setName(const QString &name)
+{
+ if (d->m_name != name)
+ d->m_name = name;
+}
+
+Documentation QPropertySpec::documentation() const
+{
+ return d->m_documentation;
+}
+
+void QPropertySpec::setDocumentation(const Documentation &doc)
+{
+ if (d->m_documentation != doc)
+ d->m_documentation = doc;
+}
+
+QString QPropertySpec::read() const
+{
+ return d->m_read;
+}
+
+void QPropertySpec::setRead(const QString &read)
+{
+ if (d->m_read != read)
+ d->m_read = read;
+}
+
+QString QPropertySpec::write() const
+{
+ return d->m_write;
+}
+
+void QPropertySpec::setWrite(const QString &write)
+{
+ if (d->m_write != write)
+ d->m_write = write;
+}
+
+bool QPropertySpec::hasWrite() const
+{
+ return !d->m_write.isEmpty();
+}
+
+QString QPropertySpec::designable() const
+{
+ return d->m_designable;
+}
+
+void QPropertySpec::setDesignable(const QString &designable)
+{
+ if (d->m_designable != designable)
+ d->m_designable = designable;
+}
+
+QString QPropertySpec::reset() const
+{
+ return d->m_reset;
+}
+
+void QPropertySpec::setReset(const QString &reset)
+{
+ if (d->m_reset != reset)
+ d->m_reset = reset;
+}
+
+QString QPropertySpec::notify() const
+{
+ return d->m_notify;
+}
+
+void QPropertySpec::setNotify(const QString &notify)
+{
+ if (d->m_notify != notify)
+ d->m_notify = notify;
+}
+
+int QPropertySpec::index() const
+{
+ return d->m_index;
+}
+
+void QPropertySpec::setIndex(int index)
+{
+ if (d->m_index != index)
+ d->m_index = index;
+}
+
+bool QPropertySpec::generateGetSetDef() const
+{
+ return d->m_generateGetSetDef;
+}
+
+void QPropertySpec::setGenerateGetSetDef(bool generateGetSetDef)
+{
+ if (d->m_generateGetSetDef != generateGetSetDef)
+ d->m_generateGetSetDef = generateGetSetDef;
+}
+
+// Parse a Q_PROPERTY macro
+// Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged)
+// into a TypeSystemProperty.
+TypeSystemProperty QPropertySpec::typeSystemPropertyFromQ_Property(const QString &declarationIn,
+ QString *errorMessage)
+{
+ enum class PropertyToken { None, Read, Write, Designable, Reset, Notify, Member };
+
+ static const QHash<QString, PropertyToken> tokenLookup = {
+ {"READ"_L1, PropertyToken::Read},
+ {"WRITE"_L1, PropertyToken::Write},
+ {"DESIGNABLE"_L1, PropertyToken::Designable},
+ {"RESET"_L1, PropertyToken::Reset},
+ {"NOTIFY"_L1, PropertyToken::Notify},
+ {"MEMBER"_L1, PropertyToken::Member}
+ };
+
+ errorMessage->clear();
+
+ TypeSystemProperty result;
+
+ // Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged)
+
+ const QString declaration = declarationIn.simplified();
+ auto propertyTokens = declaration.split(u' ', Qt::SkipEmptyParts);
+
+ // To properly parse complicated type declarations like
+ // "Q_PROPERTY(const QList<QString > *objectName READ objectName ..."
+ // we first search the first "READ" token, parse the subsequent tokens and
+ // extract type and name from the tokens before "READ".
+ const auto it = std::find_if(propertyTokens.cbegin(), propertyTokens.cend(),
+ [](const QString &t) { return tokenLookup.contains(t); });
+ if (it == propertyTokens.cend()) {
+ *errorMessage = u"Invalid property specification, READ missing"_s;
+ return result;
+ }
+
+ const auto firstToken = qsizetype(it - propertyTokens.cbegin());
+ if (firstToken < 2) {
+ *errorMessage = u"Insufficient number of tokens in property specification"_s;
+ return result;
+ }
+
+ for (qsizetype pos = firstToken; pos + 1 < propertyTokens.size(); pos += 2) {
+ switch (tokenLookup.value(propertyTokens.at(pos))) {
+ case PropertyToken::Read:
+ result.read = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Write:
+ result.write = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Reset:
+ result.reset = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Designable:
+ result.designable = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Notify:
+ result.notify = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Member:
+ // Ignore MEMBER tokens introduced by QTBUG-16852 as Python
+ // properties are anyways generated for fields.
+ return {};
+
+ case PropertyToken::None:
+ break;
+ }
+ }
+
+ const auto namePos = firstToken - 1;
+ result.name = propertyTokens.at(namePos);
+
+ result.type = propertyTokens.constFirst();
+ for (qsizetype pos = 1; pos < namePos; ++pos)
+ result.type += u' ' + propertyTokens.at(pos);
+
+ // Fix errors like "Q_PROPERTY(QXYSeries *series .." to be of type "QXYSeries*"
+ while (!result.name.isEmpty() && !result.name.at(0).isLetter()) {
+ result.type += result.name.at(0);
+ result.name.remove(0, 1);
+ }
+ if (!result.isValid())
+ *errorMessage = u"Incomplete property specification"_s;
+ return result;
+}
+
+// Create a QPropertySpec from a TypeSystemProperty, determining
+// the AbstractMetaType from the type string.
+std::optional<QPropertySpec>
+ QPropertySpec::fromTypeSystemProperty(AbstractMetaBuilderPrivate *b,
+ const AbstractMetaClassPtr &metaClass,
+ const TypeSystemProperty &ts,
+ const QStringList &scopes,
+ QString *errorMessage)
+ {
+ Q_ASSERT(ts.isValid());
+ QString typeError;
+ TypeInfo info = TypeParser::parse(ts.type, &typeError);
+ if (info.qualifiedName().isEmpty()) {
+ *errorMessage = msgPropertyTypeParsingFailed(ts.name, ts.type, typeError);
+ return {};
+ }
+
+ auto type = b->translateType(info, metaClass, {}, &typeError);
+ if (!type.has_value()) {
+ const QStringList qualifiedName = info.qualifiedName();
+ for (auto j = scopes.size(); j >= 0 && !type; --j) {
+ info.setQualifiedName(scopes.mid(0, j) + qualifiedName);
+ type = b->translateType(info, metaClass, {}, &typeError);
+ }
+ }
+
+ if (!type.has_value()) {
+ *errorMessage = msgPropertyTypeParsingFailed(ts.name, ts.type, typeError);
+ return {};
+ }
+ return QPropertySpec(ts, type.value());
+ }
+
+// Convenience to create a QPropertySpec from a Q_PROPERTY macro
+// via TypeSystemProperty.
+std::optional<QPropertySpec>
+ QPropertySpec::parseQ_Property(AbstractMetaBuilderPrivate *b,
+ const AbstractMetaClassPtr &metaClass,
+ const QString &declarationIn,
+ const QStringList &scopes,
+ QString *errorMessage)
+{
+ const TypeSystemProperty ts =
+ typeSystemPropertyFromQ_Property(declarationIn, errorMessage);
+ if (!ts.isValid())
+ return {};
+ return fromTypeSystemProperty(b, metaClass, ts, scopes, errorMessage);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void QPropertySpec::formatDebug(QDebug &debug) const
+{
+ debug << '#' << d->m_index << " \"" << d->m_name << "\" (" << d->m_type.cppSignature();
+ debug << "), read=" << d->m_read;
+ if (!d->m_write.isEmpty())
+ debug << ", write=" << d->m_write;
+ if (!d->m_reset.isEmpty())
+ debug << ", reset=" << d->m_reset;
+ if (!d->m_designable.isEmpty())
+ debug << ", designable=" << d->m_designable;
+ if (!d->m_documentation.isEmpty())
+ debug << ", doc=\"" << d->m_documentation << '"';
+}
+
+QDebug operator<<(QDebug d, const QPropertySpec &p)
+{
+ QDebugStateSaver s(d);
+ d.noquote();
+ d.nospace();
+ d << "QPropertySpec(";
+ p.formatDebug(d);
+ d << ')';
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/propertyspec.h b/sources/shiboken6/ApiExtractor/propertyspec.h
new file mode 100644
index 000000000..9e2e0f3d4
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/propertyspec.h
@@ -0,0 +1,104 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PROPERTYSPEC_H
+#define PROPERTYSPEC_H
+
+class AbstractMetaType;
+
+#include "abstractmetalang_typedefs.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QSharedDataPointer>
+
+#include <optional>
+
+class AbstractMetaClass;
+class AbstractMetaBuilderPrivate;
+class AbstractMetaType;
+class Documentation;
+class TypeEntry;
+
+struct TypeSystemProperty;
+
+class QPropertySpecData;
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class QPropertySpec
+{
+public:
+ explicit QPropertySpec(const TypeSystemProperty &ts,
+ const AbstractMetaType &type);
+ QPropertySpec(const QPropertySpec &);
+ QPropertySpec &operator=(const QPropertySpec &);
+ QPropertySpec(QPropertySpec &&) noexcept;
+ QPropertySpec &operator=(QPropertySpec &&) noexcept;
+ ~QPropertySpec();
+
+ static TypeSystemProperty typeSystemPropertyFromQ_Property(const QString &declarationIn,
+ QString *errorMessage);
+
+
+ static std::optional<QPropertySpec>
+ fromTypeSystemProperty(AbstractMetaBuilderPrivate *b,
+ const AbstractMetaClassPtr &metaClass,
+ const TypeSystemProperty &ts,
+ const QStringList &scopes,
+ QString *errorMessage);
+
+ static std::optional<QPropertySpec>
+ parseQ_Property(AbstractMetaBuilderPrivate *b,
+ const AbstractMetaClassPtr &metaClass,
+ const QString &declarationIn,
+ const QStringList &scopes,
+ QString *errorMessage);
+
+ const AbstractMetaType &type() const;
+ void setType(const AbstractMetaType &t);
+
+ TypeEntryCPtr typeEntry() const;
+
+ QString name() const;
+ void setName(const QString &name);
+
+ Documentation documentation() const;
+ void setDocumentation(const Documentation &doc);
+
+ QString read() const;
+ void setRead(const QString &read);
+
+ QString write() const;
+ void setWrite(const QString &write);
+ bool hasWrite() const;
+
+ QString designable() const;
+ void setDesignable(const QString &designable);
+
+ QString reset() const;
+ void setReset(const QString &reset);
+
+ QString notify() const; // Q_PROPERTY/C++ only
+ void setNotify(const QString &notify);
+
+ int index() const;
+ void setIndex(int index);
+
+ // Indicates whether actual code is generated instead of relying on libpyside.
+ bool generateGetSetDef() const;
+ void setGenerateGetSetDef(bool generateGetSetDef);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+private:
+ QSharedDataPointer<QPropertySpecData> d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QPropertySpec &p);
+#endif
+
+#endif // PROPERTYSPEC_H
diff --git a/sources/shiboken6/ApiExtractor/pymethoddefentry.cpp b/sources/shiboken6/ApiExtractor/pymethoddefentry.cpp
new file mode 100644
index 000000000..64d44378b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/pymethoddefentry.cpp
@@ -0,0 +1,53 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "pymethoddefentry.h"
+#include "textstream.h"
+
+#include <QtCore/QDebug>
+
+TextStream &operator<<(TextStream &str, const castToPyCFunction &c)
+{
+ str << "reinterpret_cast<PyCFunction>(" << c.m_function << ')';
+ return str;
+}
+
+TextStream &operator<<(TextStream &s, const PyMethodDefEntry &e)
+{
+ s << "{\"" << e.name << "\", " << castToPyCFunction(e.function) <<", ";
+ if (e.methFlags.isEmpty()) {
+ s << '0';
+ } else {
+ for (qsizetype i = 0, size = e.methFlags.size(); i < size; ++i) {
+ if (i)
+ s << '|';
+ s << e.methFlags.at(i);
+ }
+ }
+ if (e.doc.isEmpty())
+ s << ", nullptr";
+ else
+ s << ", R\"(" << e.doc << ")\"";
+ s << '}';
+ return s;
+}
+
+TextStream &operator<<(TextStream &s, const PyMethodDefEntries &entries)
+{
+ for (const auto &e : entries)
+ s << e << ",\n";
+ return s;
+}
+
+QDebug operator<<(QDebug debug, const PyMethodDefEntry &e)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "PyMethodDefEntry(\"" << e.name << "\", " << e.function
+ << ", " << e.methFlags;
+ if (!e.doc.isEmpty())
+ debug << ", \"" << e.doc << '"';
+ debug << ')';
+ return debug;
+}
diff --git a/sources/shiboken6/ApiExtractor/pymethoddefentry.h b/sources/shiboken6/ApiExtractor/pymethoddefentry.h
new file mode 100644
index 000000000..a8694eb30
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/pymethoddefentry.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PYMETHODDEFENTRY_H
+#define PYMETHODDEFENTRY_H
+
+#include <QtCore/QByteArrayList>
+#include <QtCore/QString>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class TextStream;
+
+struct castToPyCFunction
+{
+ explicit castToPyCFunction(QAnyStringView function) noexcept :
+ m_function(function) {}
+
+ QAnyStringView m_function;
+};
+
+struct PyMethodDefEntry
+{
+ QString name;
+ QString function;
+ QByteArrayList methFlags; // "METH_O" etc.
+ QString doc;
+};
+
+using PyMethodDefEntries = QList<PyMethodDefEntry>;
+
+TextStream &operator<<(TextStream &str, const castToPyCFunction &e);
+TextStream &operator<<(TextStream &s, const PyMethodDefEntry &e);
+TextStream &operator<<(TextStream &s, const PyMethodDefEntries &e);
+
+QDebug operator<<(QDebug debug, const PyMethodDefEntry &e);
+
+#endif // PYMETHODDEFENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/pythontypeentry.h b/sources/shiboken6/ApiExtractor/pythontypeentry.h
new file mode 100644
index 000000000..2e0fbda97
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/pythontypeentry.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PYTHONTYPEENTRY_H
+#define PYTHONTYPEENTRY_H
+
+#include "customtypenentry.h"
+#include "typesystem_enums.h"
+
+class PythonTypeEntry : public CustomTypeEntry
+{
+public:
+ explicit PythonTypeEntry(const QString &entryName,
+ const QString &checkFunction,
+ TypeSystem::CPythonType type);
+
+ TypeEntry *clone() const override;
+
+ TypeSystem::CPythonType cPythonType() const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+protected:
+ explicit PythonTypeEntry(TypeEntryPrivate *d);
+};
+
+#endif // PYTHONTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/qtcompat.h b/sources/shiboken6/ApiExtractor/qtcompat.h
new file mode 100644
index 000000000..3837dcfd2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/qtcompat.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QTCOMPAT_H
+#define QTCOMPAT_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#if QT_VERSION < 0x060400
+
+// QTBUG-98434, provide literals of Qt 6.4 for compatibility.
+
+# include <QtCore/QString>
+
+# define QLatin1StringView QLatin1String
+
+namespace Qt {
+inline namespace Literals {
+inline namespace StringLiterals {
+
+constexpr inline QLatin1String operator"" _L1(const char *str, size_t size) noexcept
+{
+ return QLatin1String(str, qsizetype(size));
+}
+
+inline QString operator"" _s(const char16_t *str, size_t size) noexcept
+{
+ return QString(QStringPrivate(nullptr, const_cast<char16_t *>(str), qsizetype(size)));
+}
+
+} // StringLiterals
+} // Literals
+} // Qt
+
+#endif // < 6.4
+
+#endif // QTCOMPAT_H
diff --git a/sources/shiboken6/ApiExtractor/qtdocparser.cpp b/sources/shiboken6/ApiExtractor/qtdocparser.cpp
new file mode 100644
index 000000000..5bd99bbd8
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/qtdocparser.cpp
@@ -0,0 +1,445 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qtdocparser.h"
+#include "classdocumentation.h"
+#include "abstractmetaargument.h"
+#include "abstractmetaenum.h"
+#include "abstractmetafunction.h"
+#include "abstractmetalang.h"
+#include "abstractmetatype.h"
+#include "documentation.h"
+#include "modifications.h"
+#include "messages.h"
+#include "propertyspec.h"
+#include "reporthandler.h"
+#include "flagstypeentry.h"
+#include "complextypeentry.h"
+#include "functiontypeentry.h"
+#include "enumtypeentry.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QUrl>
+
+using namespace Qt::StringLiterals;
+
+enum { debugFunctionSearch = 0 };
+
+constexpr auto briefStartElement = "<brief>"_L1;
+constexpr auto briefEndElement = "</brief>"_L1;
+constexpr auto webxmlSuffix = ".webxml"_L1;
+
+Documentation QtDocParser::retrieveModuleDocumentation()
+{
+ return retrieveModuleDocumentation(packageName());
+}
+
+static void formatPreQualifications(QTextStream &str, const AbstractMetaType &type)
+{
+ if (type.isConstant())
+ str << "const " ;
+}
+
+static void formatPostQualifications(QTextStream &str, const AbstractMetaType &type)
+{
+ if (type.referenceType() == LValueReference)
+ str << " &";
+ else if (type.referenceType() == RValueReference)
+ str << " &&";
+ else if (type.indirections())
+ str << ' ' << QByteArray(type.indirections(), '*');
+}
+
+static void formatFunctionUnqualifiedArgTypeQuery(QTextStream &str,
+ const AbstractMetaType &metaType)
+{
+ switch (metaType.typeUsagePattern()) {
+ case AbstractMetaType::FlagsPattern: {
+ // Modify qualified name "QFlags<Qt::AlignmentFlag>" with name "Alignment"
+ // to "Qt::Alignment" as seen by qdoc.
+ const auto flagsEntry = std::static_pointer_cast<const FlagsTypeEntry>(metaType.typeEntry());
+ QString name = flagsEntry->qualifiedCppName();
+ if (name.endsWith(u'>') && name.startsWith(u"QFlags<")) {
+ const int lastColon = name.lastIndexOf(u':');
+ if (lastColon != -1) {
+ name.replace(lastColon + 1, name.size() - lastColon - 1, metaType.name());
+ name.remove(0, 7);
+ } else {
+ name = metaType.name(); // QFlags<> of enum in global namespace
+ }
+ }
+ str << name;
+ }
+ break;
+ case AbstractMetaType::ContainerPattern: { // QVector<int>
+ str << metaType.typeEntry()->qualifiedCppName() << '<';
+ const auto instantiations = metaType.instantiations();
+ for (qsizetype i = 0, size = instantiations.size(); i < size; ++i) {
+ if (i)
+ str << ", ";
+ const auto &instantiation = instantiations.at(i);
+ formatPreQualifications(str, instantiation);
+ str << instantiation.typeEntry()->qualifiedCppName();
+ formatPostQualifications(str, instantiation);
+ }
+ str << '>';
+ }
+ break;
+ default: // Fully qualify enums (Qt::AlignmentFlag), nested classes, etc.
+ str << metaType.typeEntry()->qualifiedCppName();
+ break;
+ }
+}
+
+static QString formatFunctionArgTypeQuery(const AbstractMetaType &metaType)
+{
+ QString result;
+ QTextStream str(&result);formatPreQualifications(str, metaType);
+ formatFunctionUnqualifiedArgTypeQuery(str, metaType);
+ formatPostQualifications(str, metaType);
+ return result;
+}
+
+QString QtDocParser::functionDocumentation(const QString &sourceFileName,
+ const ClassDocumentation &classDocumentation,
+ const AbstractMetaClassCPtr &metaClass,
+ const AbstractMetaFunctionCPtr &func,
+ QString *errorMessage)
+{
+ errorMessage->clear();
+
+ const QString docString =
+ queryFunctionDocumentation(sourceFileName, classDocumentation, metaClass,
+ func, errorMessage);
+
+ const auto funcModifs = DocParser::getXpathDocModifications(func, metaClass);
+ return docString.isEmpty() || funcModifs.isEmpty()
+ ? docString : applyDocModifications(funcModifs, docString);
+}
+
+QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName,
+ const ClassDocumentation &classDocumentation,
+ const AbstractMetaClassCPtr &metaClass,
+ const AbstractMetaFunctionCPtr &func,
+ QString *errorMessage)
+{
+ // Search candidates by name and const-ness
+ FunctionDocumentationList candidates =
+ classDocumentation.findFunctionCandidates(func->name(), func->isConstant());
+ if (candidates.isEmpty()) {
+ *errorMessage = msgCannotFindDocumentation(sourceFileName, func.get())
+ + u" (no matches)"_s;
+ return {};
+ }
+
+ // Try an exact query
+ FunctionDocumentationQuery fq;
+ fq.name = func->name();
+ fq.constant = func->isConstant();
+ for (const auto &arg : func->arguments())
+ fq.parameters.append(formatFunctionArgTypeQuery(arg.type()));
+
+ const auto funcFlags = func->flags();
+ // Re-add arguments removed by the metabuilder to binary operator functions
+ if (funcFlags.testFlag(AbstractMetaFunction::Flag::OperatorLeadingClassArgumentRemoved)
+ || funcFlags.testFlag(AbstractMetaFunction::Flag::OperatorTrailingClassArgumentRemoved)) {
+ QString classType = metaClass->qualifiedCppName();
+ if (!funcFlags.testFlag(AbstractMetaFunction::Flag::OperatorClassArgumentByValue)) {
+ classType.prepend(u"const "_s);
+ classType.append(u" &"_s);
+ }
+ if (funcFlags.testFlag(AbstractMetaFunction::Flag::OperatorLeadingClassArgumentRemoved))
+ fq.parameters.prepend(classType);
+ else
+ fq.parameters.append(classType);
+ }
+
+ const qsizetype index = ClassDocumentation::indexOfFunction(candidates, fq);
+
+ if (debugFunctionSearch) {
+ qDebug() << __FUNCTION__ << metaClass->name() << fq << funcFlags << "returns"
+ << index << "\n " << candidates.value(index) << "\n " << candidates;
+ }
+
+ if (index != -1)
+ return candidates.at(index).description;
+
+ // Fallback: Try matching by argument count
+ const auto parameterCount = func->arguments().size();
+ auto pend = std::remove_if(candidates.begin(), candidates.end(),
+ [parameterCount](const FunctionDocumentation &fd) {
+ return fd.parameters.size() != parameterCount; });
+ candidates.erase(pend, candidates.end());
+ if (candidates.size() == 1) {
+ const auto &match = candidates.constFirst();
+ QTextStream(errorMessage) << msgFallbackForDocumentation(sourceFileName, func.get())
+ << "\n Falling back to \"" << match.signature
+ << "\" obtained by matching the argument count only.";
+ return candidates.constFirst().description;
+ }
+
+ QTextStream(errorMessage) << msgCannotFindDocumentation(sourceFileName, func.get())
+ << " (" << candidates.size() << " candidates matching the argument count)";
+ return {};
+}
+
+// Extract the <brief> section from a WebXML (class) documentation and remove it
+// from the source.
+static QString extractBrief(QString *value)
+{
+ const auto briefStart = value->indexOf(briefStartElement);
+ if (briefStart < 0)
+ return {};
+ const auto briefEnd = value->indexOf(briefEndElement,
+ briefStart + briefStartElement.size());
+ if (briefEnd < briefStart)
+ return {};
+ const auto briefLength = briefEnd + briefEndElement.size() - briefStart;
+ QString briefValue = value->mid(briefStart, briefLength);
+ briefValue.insert(briefValue.size() - briefEndElement.size(),
+ u"<rst> More_...</rst>"_s);
+ value->remove(briefStart, briefLength);
+ return briefValue;
+}
+
+// Find the webxml file for global functions/enums
+// by the doc-file typesystem attribute or via include file.
+static QString findGlobalWebXmLFile(const QString &documentationDataDirectory,
+ const QString &docFile,
+ const Include &include)
+{
+ QString result;
+ if (!docFile.isEmpty()) {
+ result = documentationDataDirectory + u'/' + docFile;
+ if (!result.endsWith(webxmlSuffix))
+ result += webxmlSuffix;
+ return QFileInfo::exists(result) ? result : QString{};
+ }
+ if (include.name().isEmpty())
+ return {};
+ // qdoc "\headerfile <QtLogging>" directive produces "qtlogging.webxml"
+ result = documentationDataDirectory + u'/' +
+ QFileInfo(include.name()).baseName() + webxmlSuffix;
+ if (QFileInfo::exists(result))
+ return result;
+ // qdoc "\headerfile <qdrawutil.h>" produces "qdrawutil-h.webxml"
+ result.insert(result.size() - webxmlSuffix.size(), "-h"_L1);
+ return QFileInfo::exists(result) ? result : QString{};
+}
+
+void QtDocParser::fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f)
+{
+ auto te = f->typeEntry();
+ if (te == nullptr)
+ return;
+
+ const QString sourceFileName =
+ findGlobalWebXmLFile(documentationDataDirectory(), te->docFile(), te->include());
+ if (sourceFileName.isEmpty())
+ return;
+
+ QString errorMessage;
+ auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage);
+ if (!classDocumentationO.has_value()) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ return;
+ }
+ const QString detailed =
+ functionDocumentation(sourceFileName, classDocumentationO.value(),
+ {}, f, &errorMessage);
+ if (!errorMessage.isEmpty())
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ const Documentation documentation(detailed, {});
+ f->setDocumentation(documentation);
+}
+
+void QtDocParser::fillGlobalEnumDocumentation(AbstractMetaEnum &e)
+{
+ auto te = e.typeEntry();
+ const QString sourceFileName =
+ findGlobalWebXmLFile(documentationDataDirectory(), te->docFile(), te->include());
+ if (sourceFileName.isEmpty())
+ return;
+
+ QString errorMessage;
+ auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage);
+ if (!classDocumentationO.has_value()) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ return;
+ }
+ if (!extractEnumDocumentation(classDocumentationO.value(), e)) {
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(sourceFileName, {}, e, {})));
+ }
+}
+
+void QtDocParser::fillDocumentation(const AbstractMetaClassPtr &metaClass)
+{
+ if (!metaClass)
+ return;
+
+ auto context = metaClass->enclosingClass();
+ while (context) {
+ if (!context->enclosingClass())
+ break;
+ context = context->enclosingClass();
+ }
+
+ QString sourceFileRoot = documentationDataDirectory() + u'/'
+ + metaClass->qualifiedCppName().toLower();
+ sourceFileRoot.replace(u"::"_s, u"-"_s);
+
+ QFileInfo sourceFile(sourceFileRoot + webxmlSuffix);
+ if (!sourceFile.exists())
+ sourceFile.setFile(sourceFileRoot + ".xml"_L1);
+ if (!sourceFile.exists()) {
+ qCWarning(lcShibokenDoc).noquote().nospace()
+ << "Can't find qdoc file for class " << metaClass->name() << ", tried: "
+ << QDir::toNativeSeparators(sourceFile.absoluteFilePath());
+ return;
+ }
+
+ const QString sourceFileName = sourceFile.absoluteFilePath();
+ QString errorMessage;
+
+ const auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage);
+ if (!classDocumentationO.has_value()) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ return;
+ }
+
+ const auto &classDocumentation = classDocumentationO.value();
+ for (const auto &p : classDocumentation.properties) {
+ Documentation doc(p.description, p.brief);
+ metaClass->setPropertyDocumentation(p.name, doc);
+ }
+
+ QString docString = applyDocModifications(DocParser::getXpathDocModifications(metaClass),
+ classDocumentation.description);
+
+ if (docString.isEmpty()) {
+ QString className = metaClass->name();
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, {})));
+ }
+ const QString brief = extractBrief(&docString);
+
+ Documentation doc;
+ if (!brief.isEmpty())
+ doc.setValue(brief, Documentation::Brief);
+ doc.setValue(docString);
+ metaClass->setDocumentation(doc);
+
+ //Functions Documentation
+ const auto &funcs = DocParser::documentableFunctions(metaClass);
+ for (const auto &func : funcs) {
+ const QString detailed =
+ functionDocumentation(sourceFileName, classDocumentation,
+ metaClass, func, &errorMessage);
+ if (!errorMessage.isEmpty())
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ const Documentation documentation(detailed, {});
+ std::const_pointer_cast<AbstractMetaFunction>(func)->setDocumentation(documentation);
+ }
+#if 0
+ // Fields
+ const AbstractMetaFieldList &fields = metaClass->fields();
+ for (AbstractMetaField *field : fields) {
+ if (field->isPrivate())
+ return;
+
+ QString query = "/doxygen/compounddef/sectiondef/memberdef/name[text()=\"" + field->name() + "\"]/..";
+ Documentation doc = getDocumentation(DocModificationList(), xquery, query);
+ field->setDocumentation(doc);
+ }
+#endif
+ // Enums
+ for (AbstractMetaEnum &meta_enum : metaClass->enums()) {
+ if (!extractEnumDocumentation(classDocumentation, meta_enum)) {
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(sourceFileName, metaClass, meta_enum, {})));
+ }
+ }
+}
+
+bool QtDocParser::extractEnumDocumentation(const ClassDocumentation &classDocumentation,
+ AbstractMetaEnum &meta_enum)
+{
+ Documentation enumDoc;
+ const auto index = classDocumentation.indexOfEnum(meta_enum.name());
+ if (index == -1)
+ return false;
+ QString doc = classDocumentation.enums.at(index).description;
+ const auto firstPara = doc.indexOf(u"<para>");
+ if (firstPara != -1) {
+ const QString baseClass = QtDocParser::enumBaseClass(meta_enum);
+ if (baseClass != "Enum"_L1) {
+ const QString note = "(inherits <teletype>enum."_L1 + baseClass
+ + "</teletype>) "_L1;
+ doc.insert(firstPara + 6, note);
+ }
+ }
+ enumDoc.setValue(doc);
+ meta_enum.setDocumentation(enumDoc);
+ return true;
+}
+
+static QString qmlReferenceLink(const QFileInfo &qmlModuleFi)
+{
+ QString result;
+ QTextStream(&result) << "<para>The module also provides <link"
+ << R"( type="page" page="https://doc.qt.io/qt-)" << QT_VERSION_MAJOR
+ << '/' << qmlModuleFi.baseName() << R"(.html")"
+ << ">QML types</link>.</para>";
+ return result;
+}
+
+Documentation QtDocParser::retrieveModuleDocumentation(const QString& name)
+{
+ // TODO: This method of acquiring the module name supposes that the target language uses
+ // dots as module separators in package names. Improve this.
+ QString moduleName = name;
+ moduleName.remove(0, name.lastIndexOf(u'.') + 1);
+ if (moduleName == u"QtQuickControls2")
+ moduleName.chop(1);
+ const QString prefix = documentationDataDirectory() + u'/'
+ + moduleName.toLower();
+
+ const QString sourceFile = prefix + u"-index.webxml"_s;
+ if (!QFile::exists(sourceFile)) {
+ qCWarning(lcShibokenDoc).noquote().nospace()
+ << "Can't find qdoc file for module " << name << ", tried: "
+ << QDir::toNativeSeparators(sourceFile);
+ return Documentation();
+ }
+
+ QString errorMessage;
+ QString docString = webXmlModuleDescription(sourceFile, &errorMessage);
+ if (!errorMessage.isEmpty()) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ return {};
+ }
+
+ Documentation doc(docString, {});
+ if (doc.isEmpty()) {
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(sourceFile, "module", name)));
+ return doc;
+ }
+
+ // If a QML module info file exists, insert a link to the Qt docs.
+ const QFileInfo qmlModuleFi(prefix + u"-qmlmodule.webxml"_s);
+ if (qmlModuleFi.isFile()) {
+ QString docString = doc.detailed();
+ const int pos = docString.lastIndexOf(u"</description>");
+ if (pos != -1) {
+ docString.insert(pos, qmlReferenceLink(qmlModuleFi));
+ doc.setDetailed(docString);
+ }
+ }
+
+ return doc;
+}
diff --git a/sources/shiboken6/ApiExtractor/qtdocparser.h b/sources/shiboken6/ApiExtractor/qtdocparser.h
new file mode 100644
index 000000000..f6ba5e47a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/qtdocparser.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QTDOCPARSER_H
+#define QTDOCPARSER_H
+
+#include "docparser.h"
+
+struct ClassDocumentation;
+
+class QtDocParser : public DocParser
+{
+public:
+ QtDocParser() = default;
+ void fillDocumentation(const AbstractMetaClassPtr &metaClass) override;
+ void fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f) override;
+ void fillGlobalEnumDocumentation(AbstractMetaEnum &e) override;
+
+ Documentation retrieveModuleDocumentation() override;
+ Documentation retrieveModuleDocumentation(const QString& name) override;
+
+private:
+ static QString functionDocumentation(const QString &sourceFileName,
+ const ClassDocumentation &classDocumentation,
+ const AbstractMetaClassCPtr &metaClass,
+ const AbstractMetaFunctionCPtr &func,
+ QString *errorMessage);
+
+ static QString queryFunctionDocumentation(const QString &sourceFileName,
+ const ClassDocumentation &classDocumentation,
+ const AbstractMetaClassCPtr &metaClass,
+ const AbstractMetaFunctionCPtr &func,
+ QString *errorMessage);
+ static bool extractEnumDocumentation(const ClassDocumentation &classDocumentation,
+ AbstractMetaEnum &meta_enum);
+
+};
+
+#endif // QTDOCPARSER_H
+
diff --git a/sources/shiboken6/ApiExtractor/reporthandler.cpp b/sources/shiboken6/ApiExtractor/reporthandler.cpp
new file mode 100644
index 000000000..23066ba21
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/reporthandler.cpp
@@ -0,0 +1,194 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "reporthandler.h"
+#include "typedatabase.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QSet>
+#include <cstring>
+#include <cstdarg>
+#include <cstdio>
+
+using namespace Qt::StringLiterals;
+
+#if defined(_WINDOWS) || defined(NOCOLOR)
+ #define COLOR_END ""
+ #define COLOR_WHITE ""
+ #define COLOR_YELLOW ""
+ #define COLOR_GREEN ""
+#else
+ #define COLOR_END "\033[0m"
+ #define COLOR_WHITE "\033[1;37m"
+ #define COLOR_YELLOW "\033[1;33m"
+ #define COLOR_GREEN "\033[0;32m"
+#endif
+
+static bool m_silent = false;
+static int m_warningCount = 0;
+static int m_suppressedCount = 0;
+static ReportHandler::DebugLevel m_debugLevel = ReportHandler::NoDebug;
+static QSet<QString> m_reportedWarnings;
+static QString m_prefix;
+static bool m_withinProgress = false;
+static QByteArray m_progressMessage;
+static int m_step_warning = 0;
+static QElapsedTimer m_timer;
+
+Q_LOGGING_CATEGORY(lcShiboken, "qt.shiboken")
+Q_LOGGING_CATEGORY(lcShibokenDoc, "qt.shiboken.doc")
+
+void ReportHandler::install()
+{
+ qInstallMessageHandler(ReportHandler::messageOutput);
+ startTimer();
+}
+
+void ReportHandler::startTimer()
+{
+ m_timer.start();
+}
+
+ReportHandler::DebugLevel ReportHandler::debugLevel()
+{
+ return m_debugLevel;
+}
+
+void ReportHandler::setDebugLevel(ReportHandler::DebugLevel level)
+{
+ m_debugLevel = level;
+}
+
+bool ReportHandler::setDebugLevelFromArg(const QString &level)
+{
+ bool result = true;
+ if (level == u"sparse")
+ ReportHandler::setDebugLevel(ReportHandler::SparseDebug);
+ else if (level == u"medium")
+ ReportHandler::setDebugLevel(ReportHandler::MediumDebug);
+ else if (level == u"full")
+ ReportHandler::setDebugLevel(ReportHandler::FullDebug);
+ else
+ result = false;
+ return result;
+}
+
+int ReportHandler::suppressedCount()
+{
+ return m_suppressedCount;
+}
+
+int ReportHandler::warningCount()
+{
+ return m_warningCount;
+}
+
+bool ReportHandler::isSilent()
+{
+ return m_silent;
+}
+
+void ReportHandler::setSilent(bool silent)
+{
+ m_silent = silent;
+}
+
+void ReportHandler::setPrefix(const QString &p)
+{
+ m_prefix = p;
+}
+
+void ReportHandler::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &text)
+{
+ // Check for file location separator added by SourceLocation
+ int fileLocationPos = text.indexOf(u":\t");
+ if (type == QtWarningMsg) {
+ if (m_silent || m_reportedWarnings.contains(text))
+ return;
+ if (auto db = TypeDatabase::instance()) {
+ const bool suppressed = fileLocationPos >= 0
+ ? db->isSuppressedWarning(QStringView{text}.mid(fileLocationPos + 2))
+ : db->isSuppressedWarning(text);
+ if (suppressed) {
+ ++m_suppressedCount;
+ return;
+ }
+ }
+ ++m_warningCount;
+ ++m_step_warning;
+ m_reportedWarnings.insert(text);
+ }
+ QString message = m_prefix;
+ if (!message.isEmpty())
+ message.append(u' ');
+ const auto prefixLength = message.size();
+ message.append(text);
+ // Replace file location tab by space
+ if (fileLocationPos >= 0)
+ message[prefixLength + fileLocationPos + 1] = u' ';
+ fprintf(stderr, "%s\n", qPrintable(qFormatLogMessage(type, context, message)));
+}
+
+static QByteArray timeStamp()
+{
+ const qint64 elapsed = m_timer.elapsed();
+ return elapsed > 5000
+ ? QByteArray::number(elapsed / 1000) + 's'
+ : QByteArray::number(elapsed) + "ms";
+}
+
+void ReportHandler::startProgress(const QByteArray& str)
+{
+ if (m_silent)
+ return;
+
+ if (m_withinProgress)
+ endProgress();
+
+ m_withinProgress = true;
+ m_progressMessage = str;
+}
+
+static void indentStdout(qsizetype n)
+{
+ for (qsizetype i = 0; i < n; ++i)
+ fputc(' ', stdout);
+}
+
+void ReportHandler::endProgress()
+{
+ if (m_silent)
+ return;
+
+ m_withinProgress = false;
+
+ std::fputs(m_prefix.toUtf8().constData(), stdout);
+ const auto ts = timeStamp();
+ if (ts.size() < 6)
+ indentStdout(6 - ts.size());
+ std::fputs(" [", stdout);
+ std::fputs(ts.constData(), stdout);
+ std::fputs("] ", stdout);
+ std::fputs(m_progressMessage.constData(), stdout);
+ if (m_progressMessage.size() < 60)
+ indentStdout(60 - m_progressMessage.size());
+ const char *endMessage = m_step_warning == 0
+ ? "[" COLOR_GREEN "OK" COLOR_END "]\n"
+ : "[" COLOR_YELLOW "WARNING" COLOR_END "]\n";
+ std::fputs(endMessage, stdout);
+ std::fflush(stdout);
+ m_progressMessage.clear();
+ m_step_warning = 0;
+}
+
+QByteArray ReportHandler::doneMessage()
+{
+ QByteArray result = "Done, " + m_prefix.toUtf8() + ' ' + timeStamp();
+ if (m_warningCount)
+ result += ", " + QByteArray::number(m_warningCount) + " warnings";
+ if (m_suppressedCount)
+ result += " (" + QByteArray::number(m_suppressedCount) + " known issues)";
+ return result;
+}
diff --git a/sources/shiboken6/ApiExtractor/reporthandler.h b/sources/shiboken6/ApiExtractor/reporthandler.h
new file mode 100644
index 000000000..b79adfa73
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/reporthandler.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef REPORTHANDLER_H
+#define REPORTHANDLER_H
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QString>
+
+Q_DECLARE_LOGGING_CATEGORY(lcShiboken)
+Q_DECLARE_LOGGING_CATEGORY(lcShibokenDoc)
+
+class ReportHandler
+{
+public:
+ enum DebugLevel { NoDebug, SparseDebug, MediumDebug, FullDebug };
+
+ static void install();
+ static void startTimer();
+
+ static DebugLevel debugLevel();
+ static void setDebugLevel(DebugLevel level);
+ static bool setDebugLevelFromArg(const QString &);
+
+ static int warningCount();
+
+ static int suppressedCount();
+
+ static void startProgress(const QByteArray &str);
+ static void endProgress();
+
+ static bool isDebug(DebugLevel level)
+ { return debugLevel() >= level; }
+
+ static bool isSilent();
+ static void setSilent(bool silent);
+
+ static void setPrefix(const QString &p);
+
+ static QByteArray doneMessage();
+
+private:
+ static void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
+};
+
+#endif // REPORTHANDLER_H
diff --git a/sources/shiboken6/ApiExtractor/smartpointertypeentry.h b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h
new file mode 100644
index 000000000..7b712fe35
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SMARTPOINTERTYPEENTRY_H
+#define SMARTPOINTERTYPEENTRY_H
+
+#include "complextypeentry.h"
+
+class SmartPointerTypeEntryPrivate;
+
+struct SmartPointerInstantiation
+{
+ QString name; // user defined name
+ TypeEntryCPtr typeEntry;
+};
+
+class SmartPointerTypeEntry : public ComplexTypeEntry
+{
+public:
+ using Instantiations = QList<SmartPointerInstantiation>;
+
+ explicit SmartPointerTypeEntry(const QString &entryName,
+ const QString &getterName,
+ TypeSystem::SmartPointerType type,
+ const QString &refCountMethodName,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ TypeSystem::SmartPointerType smartPointerType() const;
+
+ QString getter() const;
+
+ QString refCountMethodName() const;
+
+ QString valueCheckMethod() const;
+ void setValueCheckMethod(const QString &);
+ QString nullCheckMethod() const;
+ void setNullCheckMethod(const QString &);
+ QString resetMethod() const;
+ void setResetMethod(const QString &);
+
+ TypeEntry *clone() const override;
+
+ const Instantiations &instantiations() const;
+ void setInstantiations(const Instantiations &i);
+ bool matchesInstantiation(const TypeEntryCPtr &e) const;
+
+ QString getTargetName(const AbstractMetaType &metaType) const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ SmartPointerTypeEntry(SmartPointerTypeEntryPrivate *d);
+};
+
+#endif // SMARTPOINTERTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/sourcelocation.cpp b/sources/shiboken6/ApiExtractor/sourcelocation.cpp
new file mode 100644
index 000000000..003f201ac
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/sourcelocation.cpp
@@ -0,0 +1,75 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "sourcelocation.h"
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+SourceLocation::SourceLocation() = default;
+
+SourceLocation::SourceLocation(const QString &file, int l)
+ : m_fileName(file), m_lineNumber(l)
+{
+}
+
+bool SourceLocation::isValid() const
+{
+ return m_lineNumber >= 0 && !m_fileName.isEmpty();
+}
+
+QString SourceLocation::fileName() const
+{
+ return m_fileName;
+}
+
+void SourceLocation::setFileName(const QString &fileName)
+{
+ m_fileName = fileName;
+}
+
+int SourceLocation::lineNumber() const
+{
+ return m_lineNumber;
+}
+
+void SourceLocation::setLineNumber(int lineNumber)
+{
+ m_lineNumber = lineNumber;
+}
+
+QString SourceLocation::toString() const
+{
+ QString result;
+ QTextStream s(&result);
+ format(s);
+ return result;
+}
+
+template<class Stream>
+void SourceLocation::format(Stream &s) const
+{
+ if (isValid())
+ s << QDir::toNativeSeparators(m_fileName) << ':' << m_lineNumber << ':';
+ else
+ s << "<unknown>";
+}
+
+QTextStream &operator<<(QTextStream &s, const SourceLocation &l)
+{
+ if (l.isValid()) {
+ l.format(s);
+ s << '\t'; // ":\t" is used by ReportHandler for filtering suppressions
+ }
+ return s;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const SourceLocation &l)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ l.format(d);
+ return d;
+}
+#endif
diff --git a/sources/shiboken6/ApiExtractor/sourcelocation.h b/sources/shiboken6/ApiExtractor/sourcelocation.h
new file mode 100644
index 000000000..0b188dca3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/sourcelocation.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SOURCE_LOCATION_H
+#define SOURCE_LOCATION_H
+
+#include <QtCore/QString>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+
+class SourceLocation
+{
+public:
+ explicit SourceLocation(const QString &file, int l);
+ SourceLocation();
+
+ bool isValid() const;
+
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ int lineNumber() const;
+ void setLineNumber(int lineNumber);
+
+ QString toString() const;
+
+ template<class Stream>
+ void format(Stream &s) const;
+
+private:
+ QString m_fileName;
+ int m_lineNumber = 0;
+};
+
+QTextStream &operator<<(QTextStream &s, const SourceLocation &l);
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const SourceLocation &l);
+#endif
+
+#endif // SOURCE_LOCATION_H
diff --git a/sources/shiboken6/ApiExtractor/symbols.filter b/sources/shiboken6/ApiExtractor/symbols.filter
new file mode 100644
index 000000000..af6c744dd
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/symbols.filter
@@ -0,0 +1,7 @@
+{
+local:
+_ZSt*;
+_ZNSt*;
+_ZNSs*;
+_ZNKSt*;
+};
diff --git a/sources/shiboken6/ApiExtractor/templateargumententry.h b/sources/shiboken6/ApiExtractor/templateargumententry.h
new file mode 100644
index 000000000..9f2338022
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/templateargumententry.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TEMPLATEARGUMENTENTRY_H
+#define TEMPLATEARGUMENTENTRY_H
+
+#include "typesystem.h"
+
+class TemplateArgumentEntryPrivate;
+
+class TemplateArgumentEntry : public TypeEntry
+{
+public:
+ explicit TemplateArgumentEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ int ordinal() const;
+ void setOrdinal(int o);
+
+ TypeEntry *clone() const override;
+
+protected:
+ explicit TemplateArgumentEntry(TemplateArgumentEntryPrivate *d);
+};
+
+#endif // TEMPLATEARGUMENTENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt b/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt
new file mode 100644
index 000000000..76c014fbb
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt
@@ -0,0 +1,66 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(CMAKE_AUTORCC ON)
+
+macro(declare_test testname)
+ # gone: qt4_automoc("${testname}.cpp")
+ set(SOURCES "${testname}.cpp")
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testname}.h")
+ list(APPEND SOURCES "${testname}.h")
+ endif ()
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testname}.qrc")
+ list(APPEND SOURCES "${testname}.qrc")
+ endif ()
+
+ add_executable(${testname} ${SOURCES})
+ target_include_directories(${testname} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${apiextractor_SOURCE_DIR}
+ )
+ target_link_libraries(${testname} PRIVATE apiextractor Qt::Test)
+ add_test(${testname} ${testname})
+ if (INSTALL_TESTS)
+ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${testname}
+ DESTINATION share/apiextractor${apiextractor_SUFFIX}/tests)
+ endif()
+endmacro(declare_test testname)
+
+declare_test(testabstractmetaclass)
+declare_test(testabstractmetatype)
+declare_test(testaddfunction)
+declare_test(testarrayargument)
+declare_test(testcodeinjection)
+declare_test(testcontainer)
+declare_test(testconversionoperator)
+declare_test(testconversionruletag)
+declare_test(testctorinformation)
+declare_test(testdroptypeentries)
+declare_test(testdtorinformation)
+declare_test(testenum)
+declare_test(testextrainclude)
+declare_test(testfunctiontag)
+declare_test(testimplicitconversions)
+declare_test(testinserttemplate)
+declare_test(testmodifyfunction)
+declare_test(testmultipleinheritance)
+declare_test(testnamespace)
+declare_test(testnestedtypes)
+declare_test(testnumericaltypedef)
+declare_test(testprimitivetypetag)
+declare_test(testrefcounttag)
+declare_test(testreferencetopointer)
+declare_test(testremovefield)
+declare_test(testremoveimplconv)
+declare_test(testremoveoperatormethod)
+declare_test(testresolvetype)
+declare_test(testreverseoperators)
+declare_test(testtemplates)
+declare_test(testtoposort)
+declare_test(testvaluetypedefaultctortag)
+declare_test(testvoidarg)
+declare_test(testtyperevision)
+if (NOT DISABLE_DOCSTRINGS)
+ declare_test(testmodifydocumentation)
+endif()
+
diff --git a/sources/shiboken6/ApiExtractor/tests/a.xml b/sources/shiboken6/ApiExtractor/tests/a.xml
new file mode 100644
index 000000000..3c09d3800
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/a.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" ?>
+<!-- Sample for testModifyDocumentation -->
+<WebXML>
+ <document>
+ <class name="A">
+ <description>oi
+ <brief>Brief description</brief>
+ <para>Paragraph number 1</para>
+ <para>Paragraph number 2</para>
+ <para>Paragraph number 3</para>
+ </description>
+ </class>
+ </document>
+</WebXML>
diff --git a/sources/shiboken6/ApiExtractor/tests/injectedcode.txt b/sources/shiboken6/ApiExtractor/tests/injectedcode.txt
new file mode 100644
index 000000000..872898810
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/injectedcode.txt
@@ -0,0 +1,5 @@
+// Bla
+// @snippet label
+code line
+// @snippet label
+// Bla
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp
new file mode 100644
index 000000000..4b5da0c3a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp
@@ -0,0 +1,778 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testabstractmetaclass.h"
+#include "abstractmetabuilder.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <usingmember.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestAbstractMetaClass::testClassName()
+{
+ const char cppCode[] = "class ClassName {};";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="ClassName"/>
+</typesystem>)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes[0]->name(), u"ClassName");
+}
+
+void TestAbstractMetaClass::testClassNameUnderNamespace()
+{
+ const char cppCode[] = "namespace Namespace { class ClassName {}; }\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <namespace-type name="Namespace">
+ <value-type name="ClassName"/>
+ </namespace-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2); // 1 namespace + 1 class
+ if (classes.constFirst()->name() != u"ClassName")
+ qSwap(classes[0], classes[1]);
+
+ QCOMPARE(classes[0]->name(), u"ClassName");
+ QCOMPARE(classes[0]->qualifiedCppName(), u"Namespace::ClassName");
+ QCOMPARE(classes[1]->name(), u"Namespace");
+ QVERIFY(classes[1]->isNamespace());
+
+ // Check ctors info
+ QVERIFY(classes[0]->hasConstructors());
+ QCOMPARE(classes[0]->functions().size(), 2); // default ctor + copy ctor
+
+ auto ctors = classes[0]->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.constFirst()->minimalSignature() != u"ClassName()")
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 0);
+ QCOMPARE(ctors[0]->minimalSignature(), u"ClassName()");
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), u"ClassName(Namespace::ClassName)");
+
+ QVERIFY(!classes[0]->hasPrivateDestructor());
+ QVERIFY(classes[0]->isCopyConstructible()); // implicit default copy ctor
+
+ // This method is buggy and nobody wants to fix it or needs it fixed :-/
+ // QVERIFY(classes[0]->hasNonPrivateConstructor());
+}
+
+static AbstractMetaFunctionCList virtualFunctions(const AbstractMetaClassCPtr &c)
+{
+ AbstractMetaFunctionCList result;
+ const auto &functions = c->functions();
+ for (const auto &f : functions) {
+ if (f->isVirtual())
+ result.append(f);
+ }
+ return result;
+}
+
+void TestAbstractMetaClass::testVirtualMethods()
+{
+ const char cppCode[] =R"CPP(
+class A {
+public:
+ virtual int pureVirtual() const = 0;
+};
+class B : public A {};
+class C : public B {
+public:
+ int pureVirtual() const override { return 0; }
+};
+class F final : public C {
+public:
+ int pureVirtual() const final { return 1; }
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <primitive-type name='int'/>
+ <object-type name='A'/>
+ <object-type name='B'/>
+ <object-type name='C'/>
+ <object-type name='F'/>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 4);
+ const auto a = AbstractMetaClass::findClass(classes, "A");
+ const auto b = AbstractMetaClass::findClass(classes, "B");
+ const auto c = AbstractMetaClass::findClass(classes, "C");
+ const auto f = AbstractMetaClass::findClass(classes, "F");
+ QVERIFY(f);
+
+ QCOMPARE(a->baseClass(), nullptr);
+ QCOMPARE(b->baseClass(), a);
+ QCOMPARE(c->baseClass(), b);
+ QCOMPARE(f->baseClass(), c);
+
+ QCOMPARE(a->functions().size(), 2); // default ctor + the pure virtual method
+ QCOMPARE(b->functions().size(), 2);
+ QCOMPARE(c->functions().size(), 2);
+ QCOMPARE(f->functions().size(), 2);
+ QVERIFY(f->attributes().testFlag(AbstractMetaClass::FinalCppClass));
+
+ // implementing class, ownclass, declaringclass
+ const auto ctorA = a->queryFunctions(FunctionQueryOption::Constructors).constFirst();
+ const auto ctorB = b->queryFunctions(FunctionQueryOption::Constructors).constFirst();
+ const auto ctorC = c->queryFunctions(FunctionQueryOption::Constructors).constFirst();
+ QVERIFY(ctorA->isConstructor());
+ QVERIFY(!ctorA->isVirtual());
+ QVERIFY(ctorB->isConstructor());
+ QVERIFY(!ctorB->isVirtual());
+ QVERIFY(ctorC->isConstructor());
+ QVERIFY(!ctorC->isVirtual());
+ QCOMPARE(ctorA->implementingClass(), a);
+ QCOMPARE(ctorA->ownerClass(), a);
+ QCOMPARE(ctorA->declaringClass(), a);
+
+ const auto virtualFunctionsA = virtualFunctions(a);
+ const auto virtualFunctionsB = virtualFunctions(b);
+ const auto virtualFunctionsC = virtualFunctions(c);
+ const auto virtualFunctionsF = virtualFunctions(f);
+ QCOMPARE(virtualFunctionsA.size(), 1); // Add a pureVirtualMethods method !?
+ QCOMPARE(virtualFunctionsB.size(), 1);
+ QCOMPARE(virtualFunctionsC.size(), 1);
+ QCOMPARE(virtualFunctionsF.size(), 1);
+
+ const auto funcA = virtualFunctionsA.constFirst();
+ const auto funcB = virtualFunctionsB.constFirst();
+ const auto funcC = virtualFunctionsC.constFirst();
+ const auto funcF = virtualFunctionsF.constFirst();
+
+ QCOMPARE(funcA->ownerClass(), a);
+ QVERIFY(funcC->isVirtual());
+ QCOMPARE(funcB->ownerClass(), b);
+ QCOMPARE(funcC->ownerClass(), c);
+ QVERIFY(funcC->cppAttributes().testFlag(FunctionAttribute::Override));
+ QVERIFY(funcF->cppAttributes().testFlag(FunctionAttribute::Final));
+
+ QCOMPARE(funcA->declaringClass(), a);
+ QCOMPARE(funcB->declaringClass(), a);
+ QCOMPARE(funcC->declaringClass(), a);
+
+ // The next two tests could return null, because it makes more sense.
+ // But we have too many code written relying on this behaviour where
+ // implementingClass is equals to declaringClass on pure virtual functions
+ QCOMPARE(funcA->implementingClass(), a);
+ QCOMPARE(funcB->implementingClass(), a);
+ QCOMPARE(funcC->implementingClass(), c);
+}
+
+void TestAbstractMetaClass::testVirtualBase()
+{
+ const char cppCode[] =R"CPP(
+class Base {
+public:
+ virtual ~Base() = default;
+};
+class Derived : public Base {};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <object-type name='Base'/>
+ <object-type name='Derived'/>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto base = AbstractMetaClass::findClass(classes, "Base");
+ QVERIFY(base);
+ QVERIFY(base->isPolymorphic());
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QVERIFY(derived);
+ QVERIFY(derived->isPolymorphic());
+}
+
+void TestAbstractMetaClass::testDefaultValues()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ class B {};\n\
+ void method(B b = B());\n\
+ };\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <value-type name='A'>
+ <value-type name='B'/>
+ </value-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto candidates = classA->queryFunctionsByName(u"method"_s);
+ QCOMPARE(candidates.size(), 1);
+ const auto &method = candidates.constFirst();
+ const AbstractMetaArgument &arg = method->arguments().constFirst();
+ QCOMPARE(arg.defaultValueExpression(), arg.originalDefaultValueExpression());
+}
+
+void TestAbstractMetaClass::testModifiedDefaultValues()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ class B {};\n\
+ void method(B b = B());\n\
+ };\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <value-type name='A'>
+ <modify-function signature='method(A::B)'>
+ <modify-argument index='1'>
+ <replace-default-expression with='Hello'/>
+ </modify-argument>
+ </modify-function>
+ <value-type name='B'/>
+ </value-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto methodMatches = classA->queryFunctionsByName(u"method"_s);
+ QCOMPARE(methodMatches.size(), 1);
+ const auto method = methodMatches.constFirst();
+ const AbstractMetaArgument &arg = method->arguments().constFirst();
+ QCOMPARE(arg.defaultValueExpression(), u"Hello");
+ QCOMPARE(arg.originalDefaultValueExpression(), u"A::B()");
+}
+
+void TestAbstractMetaClass::testInnerClassOfAPolymorphicOne()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ class B {};\n\
+ virtual void method();\n\
+ };\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <object-type name='A'>
+ <value-type name='B'/>
+ </object-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QVERIFY(classA->isPolymorphic());
+ const auto classB = AbstractMetaClass::findClass(classes, "A::B");
+ QVERIFY(classB);
+ QVERIFY(!classB->isPolymorphic());
+}
+
+void TestAbstractMetaClass::testForwardDeclaredInnerClass()
+{
+ const char cppCode[] ="\
+ class A {\n\
+ class B;\n\
+ };\n\
+ class A::B {\n\
+ public:\n\
+ void foo();\n\
+ };\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <value-type name='A'>
+ <value-type name='B'/>
+ </value-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto classB = AbstractMetaClass::findClass(classes, "A::B");
+ QVERIFY(classB);
+ const auto fooF = classB->findFunction("foo");
+ QVERIFY(fooF);
+}
+
+void TestAbstractMetaClass::testSpecialFunctions()
+{
+ const char cppCode[] ="\
+ struct A {\n\
+ A();\n\
+ A(const A&);\n\
+ A &operator=(const A&);\n\
+ };\n\
+ struct B {\n\
+ B();\n\
+ B(const B &);\n\
+ B &operator=(B);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ QCOMPARE(ctors.constFirst()->functionType(), AbstractMetaFunction::ConstructorFunction);
+ QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction);
+ auto assigmentOps = classA->queryFunctionsByName(u"operator="_s);
+ QCOMPARE(assigmentOps.size(), 1);
+ QCOMPARE(assigmentOps.constFirst()->functionType(),
+ AbstractMetaFunction::AssignmentOperatorFunction);
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ ctors = classB->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ QCOMPARE(ctors.constFirst()->functionType(), AbstractMetaFunction::ConstructorFunction);
+ QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction);
+ assigmentOps = classA->queryFunctionsByName(u"operator="_s);
+ QCOMPARE(assigmentOps.size(), 1);
+ QCOMPARE(assigmentOps.constFirst()->functionType(), AbstractMetaFunction::AssignmentOperatorFunction);
+}
+
+void TestAbstractMetaClass::testClassDefaultConstructors()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ \n\
+ struct B {\n\
+ B();\n\
+ private: \n\
+ B(const B&);\n\
+ };\n\
+ \n\
+ struct C {\n\
+ C(const C&);\n\
+ };\n\
+ \n\
+ struct D {\n\
+ private: \n\
+ D(const D&);\n\
+ };\n\
+ \n\
+ struct E {\n\
+ private: \n\
+ ~E();\n\
+ };\n\
+ \n\
+ struct F {\n\
+ F(int, int);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ <value-type name='C'/>\n\
+ <object-type name='D'/>\n\
+ <object-type name='E'/>\n\
+ <value-type name='F'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 6);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 2);
+
+ auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.constFirst()->minimalSignature() != u"A()")
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 0);
+ QCOMPARE(ctors[0]->minimalSignature(), u"A()");
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), u"A(A)");
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QCOMPARE(classB->functions().size(), 2);
+ QCOMPARE(classB->functions().constFirst()->minimalSignature(), u"B()");
+
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(classC);
+ QCOMPARE(classC->functions().size(), 1);
+ QCOMPARE(classC->functions().constFirst()->minimalSignature(), u"C(C)");
+
+ const auto classD = AbstractMetaClass::findClass(classes, "D");
+ QVERIFY(classD);
+ QCOMPARE(classD->functions().size(), 1);
+ QCOMPARE(classD->functions().constFirst()->minimalSignature(), u"D(D)");
+ QVERIFY(classD->functions().constFirst()->isPrivate());
+
+ const auto classE = AbstractMetaClass::findClass(classes, "E");
+ QVERIFY(classE);
+ QVERIFY(classE->hasPrivateDestructor());
+ QCOMPARE(classE->functions().size(), 0);
+
+ const auto classF = AbstractMetaClass::findClass(classes, "F");
+ QVERIFY(classF);
+
+ ctors = classF->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.constFirst()->minimalSignature() != u"F(int,int)")
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 2);
+ QCOMPARE(ctors[0]->minimalSignature(), u"F(int,int)");
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), u"F(F)");
+}
+
+void TestAbstractMetaClass::testClassInheritedDefaultConstructors()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ A();\n\
+ private: \n\
+ A(const A&);\n\
+ };\n\
+ struct B : public A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.constFirst()->minimalSignature() != u"A()")
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 0);
+ QCOMPARE(ctors[0]->minimalSignature(), u"A()");
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), u"A(A)");
+ QVERIFY(ctors[1]->isPrivate());
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+
+ ctors = classB->queryFunctions(FunctionQueryOption::Constructors);
+ QCOMPARE(ctors.size(), 1);
+ QCOMPARE(ctors.constFirst()->arguments().size(), 0);
+ QCOMPARE(ctors.constFirst()->minimalSignature(), u"B()");
+}
+
+void TestAbstractMetaClass::testAbstractClassDefaultConstructors()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ virtual void method() = 0;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ const auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors);
+ QCOMPARE(ctors.size(), 1);
+ QCOMPARE(ctors.constFirst()->arguments().size(), 0);
+ QCOMPARE(ctors.constFirst()->minimalSignature(), u"A()");
+}
+
+void TestAbstractMetaClass::testObjectTypesMustNotHaveCopyConstructors()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ const auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors);
+ QCOMPARE(ctors.size(), 1);
+ QCOMPARE(ctors.constFirst()->arguments().size(), 0);
+ QCOMPARE(ctors.constFirst()->minimalSignature(), u"A()");
+}
+
+void TestAbstractMetaClass::testIsPolymorphic()
+{
+ const char cppCode[] = "\
+ class A\n\
+ {\n\
+ public:\n\
+ A();\n\
+ inline bool abc() const { return false; }\n\
+ };\n\
+ \n\
+ class B : public A\n\
+ {\n\
+ public:\n\
+ B();\n\
+ inline bool abc() const { return false; }\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='bool'/>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto b = AbstractMetaClass::findClass(classes, "A");
+
+ QVERIFY(!b->isPolymorphic());
+ const auto a = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(!a->isPolymorphic());
+}
+
+void TestAbstractMetaClass::testClassTypedefedBaseClass()
+{
+ const char cppCode[] =R"CPP(
+class Base {
+};
+
+using BaseAlias1 = Base;
+using BaseAlias2 = BaseAlias1;
+
+class Derived : public BaseAlias2 {
+};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <object-type name='Base'/>
+ <object-type name='Derived'/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto base = AbstractMetaClass::findClass(classes, "Base");
+ QVERIFY(base);
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QVERIFY(derived);
+ QCOMPARE(derived->baseClasses().value(0), base);
+}
+
+void TestAbstractMetaClass::testFreeOperators_data()
+{
+ QTest::addColumn<QByteArray>("code");
+
+ const QByteArray classHeader(R"CPP(
+class Value
+{
+public:
+ Value(int v) : m_value(v) {}
+ int value() const { return m_value; }
+)CPP");
+
+ const QByteArray classFooter(R"CPP(
+private:
+ int m_value;
+};
+)CPP");
+
+ const QByteArray multOperatorSignature("Value operator*(const Value &v1, const Value &v2)");
+ const QByteArray multOperatorBody("{ return Value(v1.value() * v2.value()); }");
+ const QByteArray multOperator = multOperatorSignature + '\n' + multOperatorBody;
+
+ QTest::newRow("free")
+ << (classHeader + classFooter + "\ninline " + multOperator);
+ QTest::newRow("free-friend-declared")
+ << (classHeader + "\n friend " + multOperatorSignature + ";\n" + classFooter
+ + "\ninline " + multOperator);
+ QTest::newRow("hidden friend")
+ << (classHeader + " friend inline " + multOperator + classFooter);
+};
+
+void TestAbstractMetaClass::testFreeOperators()
+{
+ QFETCH(QByteArray, code);
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <primitive-type name="int"/>
+ <value-type name="Value"/>
+ </typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(code.constData(), xmlCode));
+ QVERIFY(builder);
+ const auto classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QVERIFY(classes.constFirst()->hasArithmeticOperatorOverload());
+ FunctionQueryOptions opts(FunctionQueryOption::OperatorOverloads);
+ QCOMPARE(classes.constFirst()->queryFunctions(opts).size(), 1);
+}
+
+void TestAbstractMetaClass::testUsingMembers()
+{
+ const char cppCode[] =R"CPP(
+class Base {
+public:
+ explicit Base(int);
+
+protected:
+ void member();
+};
+
+class Derived : public Base {
+public:
+ using Base::Base;
+ using Base::member;
+};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='Derived'/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto base = AbstractMetaClass::findClass(classes, "Base");
+ QVERIFY(base);
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QVERIFY(derived);
+ const auto usingMembers = derived->usingMembers();
+ QCOMPARE(usingMembers.size(), 2);
+ for (const auto &um : usingMembers) {
+ QCOMPARE(um.access, Access::Public);
+ QCOMPARE(um.baseClass, base);
+ QVERIFY(um.memberName == u"Base" || um.memberName == u"member");
+ }
+}
+
+void TestAbstractMetaClass::testUsingTemplateMembers_data()
+{
+ const QByteArray cppCode(R"CPP(
+struct Value {
+ int value = 0;
+};
+
+template <class T> class List {
+public:
+ List();
+ void append(const T &t);
+};
+
+class ValueList : public List<Value> {
+public:
+ void append(const Value &v1, const Value &v2);
+)CPP");
+
+ QTest::addColumn<QByteArray>("code");
+ QTest::newRow("simple")
+ << (cppCode + "using List::append;\n};\n");
+ QTest::newRow("with-template-params")
+ << (cppCode + "using List<Value>::append;\n};\n");
+}
+
+void TestAbstractMetaClass::testUsingTemplateMembers()
+{
+ QFETCH(QByteArray, code);
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <value-type name='Value'/>
+ <container-type name='List' type='list'/>
+ <value-type name='ValueList'/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(code.constData(), xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto valueList = AbstractMetaClass::findClass(classes, "ValueList");
+ QVERIFY(valueList);
+ auto list = valueList->templateBaseClass();
+ QVERIFY(valueList->isUsingMember(list, u"append"_s, Access::Public));
+ QCOMPARE(valueList->queryFunctionsByName(u"append"_s).size(), 2);
+}
+
+void TestAbstractMetaClass::testGenerateFunctions()
+{
+ const char cppCode[] = R"CPP(
+class TestClass {
+public:
+ TestClass();
+
+ void alpha(int);
+ void beta(int);
+ void beta(double);
+ void gamma(int);
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <object-type name='TestClass' generate-functions='beta(double);gamma'/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto tc = AbstractMetaClass::findClass(classes, "TestClass");
+ // Verify that the constructor and 2 functions are generated.
+ const auto &functions = tc->functions();
+ QCOMPARE(functions.size(), 5);
+ const auto generateCount =
+ std::count_if(functions.cbegin(), functions.cend(),
+ [](const auto &af) { return af->generateBinding(); });
+ QCOMPARE(generateCount, 3);
+}
+
+QTEST_APPLESS_MAIN(TestAbstractMetaClass)
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h
new file mode 100644
index 000000000..a6bd2bf06
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTABSTRACTMETACLASS_H
+#define TESTABSTRACTMETACLASS_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestAbstractMetaClass : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testClassName();
+ void testClassNameUnderNamespace();
+ void testVirtualMethods();
+ void testVirtualBase();
+ void testDefaultValues();
+ void testModifiedDefaultValues();
+ void testInnerClassOfAPolymorphicOne();
+ void testForwardDeclaredInnerClass();
+ void testSpecialFunctions();
+ void testClassDefaultConstructors();
+ void testClassInheritedDefaultConstructors();
+ void testAbstractClassDefaultConstructors();
+ void testObjectTypesMustNotHaveCopyConstructors();
+ void testIsPolymorphic();
+ void testClassTypedefedBaseClass();
+ void testFreeOperators_data();
+ void testFreeOperators();
+ void testUsingMembers();
+ void testUsingTemplateMembers_data();
+ void testUsingTemplateMembers();
+ void testGenerateFunctions();
+};
+
+#endif // TESTABSTRACTMETACLASS_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp
new file mode 100644
index 000000000..2c320c874
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp
@@ -0,0 +1,229 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testabstractmetatype.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <typesystem.h>
+#include <parser/codemodel.h>
+#include <typeparser.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestAbstractMetaType::parsing_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("output");
+ QTest::newRow("primitive")
+ << QString::fromLatin1("int") << QString::fromLatin1("int");
+ QTest::newRow("ref")
+ << QString::fromLatin1("int &") << QString::fromLatin1("int&");
+ QTest::newRow("pointer")
+ << QString::fromLatin1("int **") << QString::fromLatin1("int**");
+ QTest::newRow("const ref")
+ << QString::fromLatin1("const int &") << QString::fromLatin1("const int&");
+ QTest::newRow("const pointer")
+ << QString::fromLatin1("const int **") << QString::fromLatin1("const int**");
+ QTest::newRow("const pointer const")
+ << QString::fromLatin1("const int *const*") << QString::fromLatin1("const int*const*");
+}
+
+void TestAbstractMetaType::parsing()
+{
+ QFETCH(QString, input);
+ QFETCH(QString, output);
+ QString errorMessage;
+ const TypeInfo ti = TypeParser::parse(input, &errorMessage);
+ QVERIFY2(errorMessage.isEmpty(), qPrintable(errorMessage));
+ const QString actual = ti.toString();
+ QCOMPARE(actual, output);
+}
+
+void TestAbstractMetaType::testConstCharPtrType()
+{
+ const char cppCode[] = "const char* justAtest();\n";
+ const char xmlCode[] = "<typesystem package=\"Foo\">\n\
+ <primitive-type name='char'/>\n\
+ <function signature='justAtest()' />\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ QCOMPARE(builder->globalFunctions().size(), 1);
+ const auto func = builder->globalFunctions().constFirst();
+ AbstractMetaType rtype = func->type();
+ // Test properties of const char*
+ QVERIFY(!rtype.isVoid());
+ QCOMPARE(rtype.package(), u"Foo");
+ QCOMPARE(rtype.name(), u"char");
+ QVERIFY(rtype.isConstant());
+ QVERIFY(!rtype.isArray());
+ QVERIFY(!rtype.isContainer());
+ QVERIFY(!rtype.isObject());
+ QVERIFY(!rtype.isPrimitive()); // const char* differs from char, so it's not considered a primitive type by apiextractor
+ QVERIFY(rtype.isNativePointer());
+ QCOMPARE(rtype.referenceType(), NoReference);
+ QVERIFY(!rtype.isValue());
+ QVERIFY(!rtype.isValuePointer());
+}
+
+void TestAbstractMetaType::testApiVersionSupported()
+{
+ const char cppCode[] = "class foo {}; class foo2 {};\n\
+ void justAtest(); void justAtest3();\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <value-type name='foo' since='0.1'/>\n\
+ <value-type name='foo2' since='1.0'/>\n\
+ <value-type name='foo3' since='1.1'/>\n\
+ <function signature='justAtest()' since='0.1'/>\n\
+ <function signature='justAtest2()' since='1.1'/>\n\
+ <function signature='justAtest3()'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"1.0"_s));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+
+
+ QCOMPARE(builder->globalFunctions().size(), 2);
+}
+
+
+void TestAbstractMetaType::testApiVersionNotSupported()
+{
+ const char cppCode[] = "class object {};\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <value-type name='object' since='0.1'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"0.1"_s));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+}
+
+void TestAbstractMetaType::testCharType()
+{
+ const char cppCode[] = "char justAtest(); class A {};\n";
+ const char xmlCode[] = "<typesystem package=\"Foo\">\n\
+ <primitive-type name='char'/>\n\
+ <value-type name='A'/>\n\
+ <function signature='justAtest()'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes.constFirst()->package(), u"Foo");
+
+ const auto functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 1);
+ const auto func = functions.constFirst();
+ AbstractMetaType rtype = func->type();
+ // Test properties of const char*
+ QVERIFY(!rtype.isVoid());
+ QCOMPARE(rtype.package(), u"Foo");
+ QCOMPARE(rtype.name(), u"char");
+ QVERIFY(!rtype.isConstant());
+ QVERIFY(!rtype.isArray());
+ QVERIFY(!rtype.isContainer());
+ QVERIFY(!rtype.isObject());
+ QVERIFY(rtype.isPrimitive());
+ QVERIFY(!rtype.isNativePointer());
+ QCOMPARE(rtype.referenceType(), NoReference);
+ QVERIFY(!rtype.isValue());
+ QVERIFY(!rtype.isValuePointer());
+}
+
+void TestAbstractMetaType::testTypedef()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ void someMethod();\n\
+ };\n\
+ typedef A B;\n\
+ typedef B C;\n";
+ const char xmlCode[] = "<typesystem package=\"Foo\">\n\
+ <value-type name='C' />\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto c = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(c);
+ QVERIFY(c->isTypeDef());
+}
+
+void TestAbstractMetaType::testTypedefWithTemplates()
+{
+ const char cppCode[] = "\
+ template<typename T>\n\
+ class A {};\n\
+ \n\
+ class B {};\n\
+ typedef A<B> C;\n\
+ \n\
+ void func(C c);\n";
+ const char xmlCode[] = "<typesystem package=\"Foo\">\n\
+ <container-type name='A' type='list'/>\n\
+ <value-type name='B' />\n\
+ <function signature='func(A&lt;B&gt;)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 1);
+ const auto function = functions.constFirst();
+ AbstractMetaArgumentList args = function->arguments();
+ QCOMPARE(args.size(), 1);
+ const AbstractMetaArgument &arg = args.constFirst();
+ AbstractMetaType metaType = arg.type();
+ QCOMPARE(metaType.cppSignature(), u"A<B>");
+}
+
+
+void TestAbstractMetaType::testObjectTypeUsedAsValue()
+{
+ const char cppCode[] = "\
+ class A {\n\
+ void method(A);\n\
+ };\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto overloads = classA->queryFunctionsByName(u"method"_s);
+ QCOMPARE(overloads.size(), 1);
+ const auto method = overloads.constFirst();
+ QVERIFY(method);
+ AbstractMetaArgumentList args = method->arguments();
+ QCOMPARE(args.size(), 1);
+ const AbstractMetaArgument &arg = args.constFirst();
+ AbstractMetaType metaType = arg.type();
+ QCOMPARE(metaType.cppSignature(), u"A");
+ QVERIFY(metaType.isValue());
+ QVERIFY(metaType.typeEntry()->isObject());
+}
+
+QTEST_APPLESS_MAIN(TestAbstractMetaType)
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h
new file mode 100644
index 000000000..fdcf0c787
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTABSTRACTMETATYPE_H
+#define TESTABSTRACTMETATYPE_H
+
+#include <QtCore/QObject>
+
+class TestAbstractMetaType : public QObject
+{
+ Q_OBJECT
+private slots:
+ void parsing_data();
+ void parsing();
+ void testConstCharPtrType();
+ void testCharType();
+ void testTypedef();
+ void testTypedefWithTemplates();
+ void testApiVersionSupported();
+ void testApiVersionNotSupported();
+ void testObjectTypeUsedAsValue();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp
new file mode 100644
index 000000000..a891e1e28
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp
@@ -0,0 +1,522 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testaddfunction.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <codesnip.h>
+#include <addedfunction.h>
+#include <addedfunction_p.h>
+#include <complextypeentry.h>
+#include <primitivetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+static constexpr auto voidT = "void"_L1;
+
+void TestAddFunction::testParsingFuncNameAndConstness()
+{
+ // generic test...
+ static constexpr auto sig1 = "func(type1, const type2, const type3* const)"_L1;
+ QString errorMessage;
+ auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage);
+ QVERIFY2(f1, qPrintable(errorMessage));
+ QCOMPARE(f1->name(), u"func");
+ QCOMPARE(f1->arguments().size(), 3);
+ TypeInfo retval = f1->returnType();
+ QCOMPARE(retval.qualifiedName(), QStringList{voidT});
+ QCOMPARE(retval.indirections(), 0);
+ QCOMPARE(retval.isConstant(), false);
+ QCOMPARE(retval.referenceType(), NoReference);
+
+ // test with a ugly template as argument and other ugly stuff
+ static constexpr auto sig2 =
+ " _fu__nc_ ( type1, const type2, const Abc<int& , C<char*> * >"
+ " * *@my_name@, const type3* const ) const "_L1;
+ auto f2 = AddedFunction::createAddedFunction(sig2,
+ u"const Abc<int& , C<char*> * > * *"_s,
+ &errorMessage);
+ QVERIFY2(f2, qPrintable(errorMessage));
+ QCOMPARE(f2->name(), u"_fu__nc_");
+ const auto &args = f2->arguments();
+ QCOMPARE(args.size(), 4);
+ retval = f2->returnType();
+ QCOMPARE(retval.qualifiedName(), QStringList{u"Abc"_s});
+ QCOMPARE(retval.instantiations().size(), 2);
+ QCOMPARE(retval.toString(), u"const Abc<int&, C<char*>*>**");
+ QCOMPARE(retval.indirections(), 2);
+ QCOMPARE(retval.isConstant(), true);
+ QCOMPARE(retval.referenceType(), NoReference);
+ QVERIFY(args.at(0).name.isEmpty());
+ QVERIFY(args.at(1).name.isEmpty());
+
+ QCOMPARE(args.at(2).name, u"my_name");
+ auto arg2Type = args.at(2).typeInfo;
+ QCOMPARE(arg2Type.qualifiedName(), QStringList{u"Abc"_s});
+ QCOMPARE(arg2Type.instantiations().size(), 2);
+ QCOMPARE(arg2Type.toString(), u"const Abc<int&, C<char*>*>**");
+ QCOMPARE(arg2Type.indirections(), 2);
+ QCOMPARE(arg2Type.isConstant(), true);
+ QCOMPARE(arg2Type.referenceType(), NoReference);
+
+ QVERIFY(args.at(3).name.isEmpty());
+
+ // function with no args.
+ auto f3 = AddedFunction::createAddedFunction("func()"_L1, voidT, &errorMessage);
+ QVERIFY2(f3, qPrintable(errorMessage));
+ QCOMPARE(f3->name(), u"func");
+ QCOMPARE(f3->arguments().size(), 0);
+
+ // const call operator
+ auto f4 = AddedFunction::createAddedFunction("operator()(int)const"_L1,
+ "int"_L1, &errorMessage);
+ QVERIFY2(f4, qPrintable(errorMessage));
+ QCOMPARE(f4->name(), u"operator()");
+ QCOMPARE(f4->arguments().size(), 1);
+ QVERIFY(f4->isConstant());
+}
+
+void TestAddFunction::testAddFunction()
+{
+ const char cppCode[] = R"CPP(
+struct B {};
+struct A {
+ void a(int);
+};)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <primitive-type name='float'/>
+ <value-type name='B'/>
+ <value-type name='A'>
+ <add-function signature='b(int, float = 4.6, const B&amp;)' return-type='int' access='protected'/>
+ <add-function signature='operator()(int)' return-type='int' access='public'/>
+ </value-type>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ auto *typeDb = TypeDatabase::instance();
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ // default ctor, default copy ctor, func a() and the added functions
+ QCOMPARE(classA->functions().size(), 5);
+
+ auto addedFunc = classA->findFunction("b");
+ QVERIFY(addedFunc);
+ QCOMPARE(addedFunc->access(), Access::Protected);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
+ QVERIFY(addedFunc->isUserAdded());
+ QCOMPARE(addedFunc->ownerClass(), classA);
+ QCOMPARE(addedFunc->implementingClass(), classA);
+ QCOMPARE(addedFunc->declaringClass(), classA);
+ QVERIFY(!addedFunc->isVirtual());
+ QVERIFY(!addedFunc->isSignal());
+ QVERIFY(!addedFunc->isSlot());
+ QVERIFY(!addedFunc->isStatic());
+
+ AbstractMetaType returnType = addedFunc->type();
+ QCOMPARE(returnType.typeEntry(), typeDb->findPrimitiveType(u"int"_s));
+ const AbstractMetaArgumentList &args = addedFunc->arguments();
+ QCOMPARE(args.size(), 3);
+ QCOMPARE(args.at(0).type().typeEntry(), returnType.typeEntry());
+ QCOMPARE(args.at(1).defaultValueExpression(), u"4.6");
+ QCOMPARE(args.at(2).type().typeEntry(), typeDb->findType(u"B"_s));
+
+ auto addedCallOperator = classA->findFunction("operator()");
+ QVERIFY(addedCallOperator);
+}
+
+void TestAddFunction::testAddFunctionConstructor()
+{
+ const char cppCode[] = "struct A { A() {} };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='A(int)'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 3); // default and added ctors
+ const auto addedFunc = classA->functions().constLast();
+ QCOMPARE(addedFunc->access(), Access::Public);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::ConstructorFunction);
+ QCOMPARE(addedFunc->arguments().size(), 1);
+ QVERIFY(addedFunc->isUserAdded());
+ QVERIFY(addedFunc->isVoid());
+}
+
+void TestAddFunction::testAddFunctionTagDefaultValues()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func()'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ // default ctor, default copy ctor and the added function
+ QCOMPARE(classA->functions().size(), 3);
+ const auto addedFunc = classA->functions().constLast();
+ QCOMPARE(addedFunc->access(), Access::Public);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
+ QVERIFY(addedFunc->isUserAdded());
+ QVERIFY(addedFunc->isVoid());
+}
+
+void TestAddFunction::testAddFunctionCodeSnippets()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func()'>\n\
+ <inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->functions().constLast();
+ QVERIFY(addedFunc->hasInjectedCode());
+}
+
+void TestAddFunction::testAddFunctionWithoutParenteses()
+{
+ static constexpr auto sig1 = "func"_L1;
+ QString errorMessage;
+ auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage);
+ QVERIFY2(f1, qPrintable(errorMessage));
+ QCOMPARE(f1->name(), u"func");
+ QCOMPARE(f1->arguments().size(), 0);
+ QCOMPARE(f1->isConstant(), false);
+
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func'>\n\
+ <inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction(sig1);
+ QVERIFY(addedFunc);
+ QVERIFY(addedFunc->hasInjectedCode());
+ const auto snips = addedFunc->injectedCodeSnips(TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode);
+ QCOMPARE(snips.size(), 1);
+}
+
+void TestAddFunction::testAddFunctionWithDefaultArgs()
+{
+ static constexpr auto sig1 = "func"_L1;
+ QString errorMessage;
+ auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage);
+ QVERIFY2(f1, qPrintable(errorMessage));
+ QCOMPARE(f1->name(), u"func");
+ QCOMPARE(f1->arguments().size(), 0);
+ QCOMPARE(f1->isConstant(), false);
+
+ const char cppCode[] = "struct A { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func(int, int)'>\n\
+ <modify-argument index='2'>\n\
+ <replace-default-expression with='2'/>\n\
+ </modify-argument>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction(sig1);
+ QVERIFY(addedFunc);
+ const AbstractMetaArgument &arg = addedFunc->arguments().at(1);
+ QCOMPARE(arg.defaultValueExpression(), u"2");
+}
+
+void TestAddFunction::testAddFunctionAtModuleLevel()
+{
+ const char cppCode[] = "struct A { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'/>\n\
+ <add-function signature='func(int, int)'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ auto *typeDb = TypeDatabase::instance();
+
+ AddedFunctionList addedFuncs = typeDb->findGlobalUserFunctions(u"func"_s);
+
+ QCOMPARE(addedFuncs.size(), 1);
+
+ auto &mods = addedFuncs.constFirst()->modifications();
+
+ QCOMPARE(mods.size(), 1);
+ QVERIFY(mods.constFirst().isCodeInjection());
+ CodeSnip snip = mods.constFirst().snips().constFirst();
+ QCOMPARE(snip.code().trimmed(), u"custom_code();");
+}
+
+void TestAddFunction::testAddFunctionWithVarargs()
+{
+ QString errorMessage;
+ auto f1 = AddedFunction::createAddedFunction("func(int,char,...)"_L1, voidT,
+ &errorMessage);
+ QVERIFY2(f1, qPrintable(errorMessage));
+ QCOMPARE(f1->name(), u"func");
+ QCOMPARE(f1->arguments().size(), 3);
+ QVERIFY(!f1->isConstant());
+
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='char'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func(int,char,...)'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("func");
+ QVERIFY(addedFunc);
+ const AbstractMetaArgument &arg = addedFunc->arguments().constLast();
+ QVERIFY(arg.type().isVarargs());
+ QVERIFY(arg.type().typeEntry()->isVarargs());
+}
+
+void TestAddFunction::testAddStaticFunction()
+{
+ const char cppCode[] = "struct A { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func(int, int)' static='yes'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("func");
+ QVERIFY(addedFunc);
+ QVERIFY(addedFunc->isStatic());
+}
+
+void TestAddFunction::testAddGlobalFunction()
+{
+ const char cppCode[] = "struct A { };struct B {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'/>\n\
+ <add-function signature='globalFunc(int, int)' static='yes'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <add-function signature='globalFunc2(int, int)' static='yes'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ const auto globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 2);
+ const auto classB = AbstractMetaClass::findClass(builder->classes(), "B");
+ QVERIFY(classB);
+ QVERIFY(!classB->findFunction("globalFunc"));
+ QVERIFY(!classB->findFunction("globalFunc2"));
+ QVERIFY(!globalFuncs[0]->injectedCodeSnips().isEmpty());
+ QVERIFY(!globalFuncs[1]->injectedCodeSnips().isEmpty());
+}
+
+void TestAddFunction::testAddFunctionWithApiVersion()
+{
+ const char cppCode[] = "";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <add-function signature='globalFunc(int, int)' static='yes' since='1.3'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <add-function signature='globalFunc2(int, int)' static='yes' since='0.1'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"0.1"_s));
+ QVERIFY(builder);
+ const auto globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 1);
+}
+
+void TestAddFunction::testModifyAddedFunction()
+{
+ const char cppCode[] = "class Foo { };\n";
+ const char xmlCode[] = R"(
+<typesystem package='Package'>
+ <primitive-type name='float'/>
+ <primitive-type name='int'/>
+ <value-type name='Foo'>
+ <add-function signature='method(float, int)'>
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>
+ <modify-argument index='2' rename='varName'>
+ <replace-default-expression with='0'/>
+ </modify-argument>
+ </add-function>
+ </value-type>
+</typesystem>
+)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto foo = AbstractMetaClass::findClass(classes, "Foo");
+ const auto method = foo->findFunction("method");
+ QVERIFY(method);
+ QCOMPARE(method->arguments().size(), 2);
+ const AbstractMetaArgument &arg = method->arguments().at(1);
+ QCOMPARE(arg.defaultValueExpression(), u"0");
+ QCOMPARE(arg.name(), u"varName");
+ QCOMPARE(method->argumentName(2), u"varName");
+}
+
+void TestAddFunction::testAddFunctionOnTypedef()
+{
+ const char cppCode[] = "template<class T> class Foo { }; typedef Foo<int> FooInt;\n";
+ const char xmlCode[] = "\
+ <typesystem package='Package'>\n\
+ <value-type name='FooInt'>\n\
+ <add-function signature='FooInt(PySequence)'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <add-function signature='method()'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto foo = AbstractMetaClass::findClass(classes, "FooInt");
+ QVERIFY(foo);
+ QVERIFY(foo->hasNonPrivateConstructor());
+ const auto &lst = foo->queryFunctions(FunctionQueryOption::AnyConstructor);
+ for (const auto &f : lst)
+ QVERIFY(f->signature().startsWith(f->name()));
+ QCOMPARE(lst.size(), 2);
+ const auto method = foo->findFunction("method");
+ QVERIFY(method);
+}
+
+void TestAddFunction::testAddFunctionWithTemplateArg()
+{
+ const char cppCode[] = "template<class T> class Foo { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Package'>\n\
+ <primitive-type name='int'/>\n\
+ <container-type name='Foo' type='list'/>\n\
+ <add-function signature='func(Foo&lt;int>)'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ QCOMPARE(builder->globalFunctions().size(), 1);
+ const auto func = builder->globalFunctions().constFirst();
+ const AbstractMetaArgument &arg = func->arguments().constFirst();
+ QCOMPARE(arg.type().instantiations().size(), 1);
+}
+
+// Test splitting of <add-function> parameter lists.
+
+Q_DECLARE_METATYPE(AddedFunctionParser::Argument)
+
+using Arguments = AddedFunctionParser::Arguments;
+
+void TestAddFunction::testAddFunctionTypeParser_data()
+{
+ QTest::addColumn<QString>("parameterList");
+ QTest::addColumn<Arguments>("expected");
+
+ QTest::newRow("empty")
+ << QString() << Arguments{};
+
+ QTest::newRow("1-arg")
+ << QString::fromLatin1("int @a@=42")
+ << Arguments{{u"int"_s, u"a"_s, u"42"_s}};
+
+ QTest::newRow("2-args")
+ << QString::fromLatin1("double @d@, int @a@=42")
+ << Arguments{{u"double"_s, u"d"_s, {}},
+ {u"int"_s, u"a"_s, u"42"_s}};
+
+ QTest::newRow("template-var_args")
+ << QString::fromLatin1("const QList<X,Y> &@list@ = QList<X,Y>{1,2}, int @b@=5, ...")
+ << Arguments{{u"const QList<X,Y> &"_s, u"list"_s, u"QList<X,Y>{1,2}"_s},
+ {u"int"_s, u"b"_s, u"5"_s},
+ {u"..."_s, {}, {}}};
+}
+
+void TestAddFunction::testAddFunctionTypeParser()
+{
+
+ QFETCH(QString, parameterList);
+ QFETCH(Arguments, expected);
+
+ const auto actual = AddedFunctionParser::splitParameters(parameterList);
+ QCOMPARE(actual, expected);
+}
+
+QTEST_APPLESS_MAIN(TestAddFunction)
diff --git a/sources/shiboken6/ApiExtractor/tests/testaddfunction.h b/sources/shiboken6/ApiExtractor/tests/testaddfunction.h
new file mode 100644
index 000000000..77339609f
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testaddfunction.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTADDFUNCTION_H
+#define TESTADDFUNCTION_H
+#include <QtCore/QObject>
+
+class TestAddFunction : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testParsingFuncNameAndConstness();
+ void testAddFunction();
+ void testAddFunctionConstructor();
+ void testAddFunctionTagDefaultValues();
+ void testAddFunctionCodeSnippets();
+ void testAddFunctionWithoutParenteses();
+ void testAddFunctionWithDefaultArgs();
+ void testAddFunctionAtModuleLevel();
+ void testAddFunctionWithVarargs();
+ void testAddStaticFunction();
+ void testAddGlobalFunction();
+ void testAddFunctionWithApiVersion();
+ void testModifyAddedFunction();
+ void testAddFunctionOnTypedef();
+ void testAddFunctionWithTemplateArg();
+ void testAddFunctionTypeParser_data();
+ void testAddFunctionTypeParser();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp b/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp
new file mode 100644
index 000000000..6e1820bed
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp
@@ -0,0 +1,155 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testarrayargument.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetaenum.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <primitivetypeentry.h>
+#include <parser/enumvalue.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestArrayArgument::testArrayArgumentWithSizeDefinedByInteger()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ enum SomeEnum { Value0, Value1, NValues };\n\
+ void method(double[3]);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <object-type name='A'>\n\
+ <enum-type name='SomeEnum'/>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst();
+ QVERIFY(arg.type().isArray());
+ QCOMPARE(arg.type().arrayElementCount(), 3);
+ QCOMPARE(arg.type().arrayElementType()->name(), u"double");
+}
+
+static QString functionMinimalSignature(const AbstractMetaClassCPtr &c, const QString &name)
+{
+ const auto f = c->findFunction(name);
+ return f ? f->minimalSignature() : QString();
+}
+
+void TestArrayArgument::testArraySignature()
+{
+ const char cppCode[] ="\
+ struct A {\n\
+ void mi1(int arg[5]);\n\
+ void mi1c(const int arg[5]);\n\
+ void mi1cu(const int arg[]);\n\
+ void mc1cu(const char arg[]);\n\
+ void mc1cup(const char *arg[]);\n\
+ void muc2(unsigned char *arg[2][3]);\n\
+ void mc2c(const char *arg[5][6]);\n\
+ void mc2cu(const char arg[][2]);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='char'/>\n\
+ <primitive-type name='unsigned char'/>\n\
+ <primitive-type name='int'/>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QCOMPARE(functionMinimalSignature(classA, u"mi1"_s),
+ u"mi1(int[5])");
+ QCOMPARE(functionMinimalSignature(classA, u"mi1c"_s),
+ u"mi1c(const int[5])");
+ QCOMPARE(functionMinimalSignature(classA, u"mi1cu"_s),
+ u"mi1cu(const int[])");
+ QCOMPARE(functionMinimalSignature(classA, u"mc1cu"_s),
+ u"mc1cu(const char*)");
+ QCOMPARE(functionMinimalSignature(classA, u"mc1cup"_s),
+ u"mc1cup(const char*[])");
+ QCOMPARE(functionMinimalSignature(classA, u"muc2"_s),
+ u"muc2(unsigned char*[2][3])");
+ QCOMPARE(functionMinimalSignature(classA, u"mc2c"_s),
+ u"mc2c(const char*[5][6])");
+ QCOMPARE(functionMinimalSignature(classA, u"mc2cu"_s),
+ u"mc2cu(const char[][2])");
+}
+
+void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValue()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ enum SomeEnum { Value0, Value1, NValues };\n\
+ void method(double[NValues]);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <object-type name='A'>\n\
+ <enum-type name='SomeEnum'/>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ auto someEnum = classA->findEnum(u"SomeEnum"_s);
+ QVERIFY(someEnum.has_value());
+ auto nvalues = classA->findEnumValue(u"NValues"_s);
+ QVERIFY(nvalues.has_value());
+
+ const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst();
+ QVERIFY(arg.type().isArray());
+ QCOMPARE(arg.type().arrayElementCount(), nvalues->value().value());
+ QCOMPARE(arg.type().arrayElementType()->name(), u"double");
+};
+
+void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnum()
+{
+ const char cppCode[] = "\
+ enum SomeEnum { Value0, Value1, NValues };\n\
+ struct A {\n\
+ void method(double[NValues]);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <enum-type name='SomeEnum'/>\n\
+ <object-type name='A'>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ AbstractMetaEnum someEnum = builder->globalEnums().constFirst();
+ auto nvalues = someEnum.findEnumValue(u"NValues");
+ QVERIFY(nvalues.has_value());
+
+ const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst();
+ QVERIFY(arg.type().isArray());
+ QCOMPARE(arg.type().arrayElementCount(), nvalues->value().value());
+ QCOMPARE(arg.type().arrayElementType()->name(), u"double");
+};
+
+QTEST_APPLESS_MAIN(TestArrayArgument)
diff --git a/sources/shiboken6/ApiExtractor/tests/testarrayargument.h b/sources/shiboken6/ApiExtractor/tests/testarrayargument.h
new file mode 100644
index 000000000..75ef0f792
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testarrayargument.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTARRAYARGUMENT_H
+#define TESTARRAYARGUMENT_H
+#include <QtCore/QObject>
+
+class TestArrayArgument : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testArrayArgumentWithSizeDefinedByInteger();
+ void testArraySignature();
+ void testArrayArgumentWithSizeDefinedByEnumValue();
+ void testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnum();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp
new file mode 100644
index 000000000..4829e6c33
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp
@@ -0,0 +1,164 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testcodeinjection.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <codesnip.h>
+#include <modifications.h>
+#include <textstream.h>
+#include <complextypeentry.h>
+#include <valuetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestCodeInjections::testReadFile_data()
+{
+ QTest::addColumn<QString>("filePath");
+ QTest::addColumn<QString>("snippet");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("utf8")
+ << QString::fromLatin1(":/utf8code.txt")
+ << QString()
+ << QString::fromUtf8("\xC3\xA1\xC3\xA9\xC3\xAD\xC3\xB3\xC3\xBA");
+
+ QTest::newRow("snippet")
+ << QString::fromLatin1(":/injectedcode.txt")
+ << QString::fromLatin1("label")
+ << QString::fromLatin1("code line");
+}
+
+void TestCodeInjections::testReadFile()
+{
+ QFETCH(QString, filePath);
+ QFETCH(QString, snippet);
+ QFETCH(QString, expected);
+
+ const char cppCode[] = "struct A {};\n";
+ int argc = 0;
+ char *argv[] = {nullptr};
+ QCoreApplication app(argc, argv);
+
+ QString attribute = u"file='"_s + filePath + u'\'';
+ if (!snippet.isEmpty())
+ attribute += u" snippet='"_s + snippet + u'\'';
+
+ QString xmlCode = u"\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <conversion-rule class='target' "_s + attribute + u"/>\n\
+ <inject-code class='target' "_s + attribute + u"/>\n\
+ <value-type name='B'/>\n\
+ </value-type>\n\
+ </typesystem>\n"_s;
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().constData()));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QCOMPARE(classA->typeEntry()->codeSnips().size(), 1);
+ QString code = classA->typeEntry()->codeSnips().constFirst().code();
+ QVERIFY(code.indexOf(expected) != -1);
+ QVERIFY(classA->typeEntry()->isValue());
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(classA->typeEntry());
+ code = vte->targetConversionRule();
+ QVERIFY(code.indexOf(expected) != -1);
+}
+
+void TestCodeInjections::testInjectWithValidApiVersion()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <inject-code class='target' since='1.0'>\n\
+ test Inject code\n\
+ </inject-code>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"1.0"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QCOMPARE(classA->typeEntry()->codeSnips().size(), 1);
+}
+
+void TestCodeInjections::testInjectWithInvalidApiVersion()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <inject-code class='target' since='1.0'>\n\
+ test Inject code\n\
+ </inject-code>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"0.1"_s));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QCOMPARE(classA->typeEntry()->codeSnips().size(), 0);
+}
+
+void TestCodeInjections::testTextStream()
+{
+ StringStream str(TextStream::Language::Cpp);
+ str << "void foo(int a, int b) {\n" << indent
+ << "if (a == b)\n" << indent << "return a;\n" << outdent
+ << "#if Q_OS_WIN\nprint()\n#endif\nreturn a + b;\n" << outdent
+ << "}\n\n// A table\n|"
+ << AlignedField("bla", 40, QTextStream::AlignRight) << "|\n|"
+ << AlignedField("bla", 40, QTextStream::AlignLeft) << "|\n|"
+ << AlignedField(QString(), 40, QTextStream::AlignLeft) << "|\n";
+ str << "\n2nd table\n|" << AlignedField("bla", 3, QTextStream::AlignLeft)
+ << '|' << AlignedField(QString{}, 0, QTextStream::AlignLeft) << "|\n";
+
+constexpr auto expected = R"(void foo(int a, int b) {
+ if (a == b)
+ return a;
+#if Q_OS_WIN
+ print()
+#endif
+ return a + b;
+}
+
+// A table
+| bla|
+|bla |
+| |
+
+2nd table
+|bla||
+)"_L1;
+
+ QCOMPARE(str.toString(), expected);
+}
+
+void TestCodeInjections::testTextStreamRst()
+{
+ // Test that sphinx error: "Inline strong start-string without end-string."
+ // is avoided, that is, characters following a formatting end are escaped.
+
+ StringStream str;
+ str << rstBold << "QObject" << rstBoldOff << "'s properties..."
+ << rstItalic << "some italic" << rstItalicOff << " followed by space.";
+
+ static const char16_t expected[] =
+ uR"(**QObject**\'s properties...*some italic* followed by space.)";
+
+ QCOMPARE(str.toString(), expected);
+}
+
+QTEST_APPLESS_MAIN(TestCodeInjections)
diff --git a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h
new file mode 100644
index 000000000..a164ea36e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCODEINJECTIONS_H
+#define TESTCODEINJECTIONS_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestCodeInjections : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testReadFile_data();
+ void testReadFile();
+ void testInjectWithValidApiVersion();
+ void testInjectWithInvalidApiVersion();
+ void testTextStream();
+ void testTextStreamRst();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.qrc b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.qrc
new file mode 100644
index 000000000..fd7616bd2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource>
+ <file>utf8code.txt</file>
+ <file>injectedcode.txt</file>
+ </qresource>
+</RCC>
diff --git a/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp b/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp
new file mode 100644
index 000000000..0bb72b3c1
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp
@@ -0,0 +1,84 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testcontainer.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+#include <containertypeentry.h>
+
+void TestContainer::testContainerType()
+{
+ const char cppCode[] = "\
+ namespace std {\n\
+ template<class T>\n\
+ class list {\n\
+ T get(int x) { return 0; }\n\
+ };\n\
+ }\n\
+ class A : public std::list<int> {\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='std' generate='no' />\n\
+ <container-type name='std::list' type='list' />\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ //search for class A
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ auto baseContainer = classA->typeEntry()->baseContainerType();
+ QVERIFY(baseContainer);
+ QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(baseContainer.get())->containerKind(),
+ ContainerTypeEntry::ListContainer);
+}
+
+void TestContainer::testListOfValueType()
+{
+ const char cppCode[] = "\
+ namespace std {\n\
+ template<class T>\n\
+ class list {\n\
+ T get(int x) { return 0; }\n\
+ };\n\
+ }\n\
+ class ValueType {};\n\
+ class A : public std::list<ValueType> {\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='std' generate='no'/>\n\
+ <container-type name='std::list' type='list'/>\n\
+ <value-type name='ValueType'/>\n\
+ <value-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->templateBaseClassInstantiations().size(), 1);
+ const AbstractMetaType templateInstanceType =
+ classA->templateBaseClassInstantiations().constFirst();
+
+ QCOMPARE(templateInstanceType.indirections(), 0);
+ QVERIFY(!templateInstanceType.typeEntry()->isObject());
+ QVERIFY(templateInstanceType.typeEntry()->isValue());
+ QCOMPARE(templateInstanceType.referenceType(), NoReference);
+ QVERIFY(!templateInstanceType.isObject());
+ QVERIFY(!templateInstanceType.isValuePointer());
+ QVERIFY(templateInstanceType.isValue());
+}
+
+QTEST_APPLESS_MAIN(TestContainer)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testcontainer.h b/sources/shiboken6/ApiExtractor/tests/testcontainer.h
new file mode 100644
index 000000000..3fd23c3f0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcontainer.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCONTAINER_H
+#define TESTCONTAINER_H
+#include <QtCore/QObject>
+
+class TestContainer : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testContainerType();
+ void testListOfValueType();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp
new file mode 100644
index 000000000..8f2b277af
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp
@@ -0,0 +1,178 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testconversionoperator.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestConversionOperator::testConversionOperator()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ };\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n\
+ struct C {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='C'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QVERIFY(classC);
+ QCOMPARE(classA->functions().size(), 2);
+ QCOMPARE(classB->functions().size(), 3);
+ QCOMPARE(classC->functions().size(), 3);
+ QCOMPARE(classA->externalConversionOperators().size(), 2);
+
+ AbstractMetaFunctionCPtr convOp;
+ for (const auto &func : classB->functions()) {
+ if (func->isConversionOperator()) {
+ convOp = func;
+ break;
+ }
+ }
+ QVERIFY(convOp);
+ QVERIFY(classA->externalConversionOperators().contains(convOp));
+}
+
+void TestConversionOperator::testConversionOperatorOfDiscardedClass()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ };\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' />\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->externalConversionOperators().size(), 0);
+}
+
+void TestConversionOperator::testRemovedConversionOperator()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ };\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' />\n\
+ <value-type name='B'>\n\
+ <modify-function signature='operator A() const' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QCOMPARE(classA->functions().size(), 2);
+ QCOMPARE(classB->functions().size(), 3);
+ QCOMPARE(classA->externalConversionOperators().size(), 0);
+ QCOMPARE(classA->implicitConversions().size(), 0);
+}
+
+void TestConversionOperator::testConversionOperatorReturningReference()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ operator A&() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QCOMPARE(classA->functions().size(), 2);
+ QCOMPARE(classB->functions().size(), 3);
+ QCOMPARE(classA->externalConversionOperators().size(), 1);
+ QCOMPARE(classA->externalConversionOperators().constFirst()->type().cppSignature(),
+ u"A");
+ QCOMPARE(classA->externalConversionOperators().constFirst()->ownerClass()->name(),
+ u"B");
+ QCOMPARE(classA->implicitConversions().size(), 1);
+ QCOMPARE(classA->implicitConversions().constFirst()->type().cppSignature(),
+ u"A");
+ QCOMPARE(classA->implicitConversions().constFirst()->ownerClass()->name(),
+ u"B");
+}
+
+void TestConversionOperator::testConversionOperatorReturningConstReference()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ operator const A&() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QCOMPARE(classA->functions().size(), 2);
+ QCOMPARE(classB->functions().size(), 3);
+ QCOMPARE(classA->externalConversionOperators().size(), 1);
+ QCOMPARE(classA->externalConversionOperators().constFirst()->type().cppSignature(),
+ u"A"_s);
+ QCOMPARE(classA->externalConversionOperators().constFirst()->ownerClass()->name(),
+ u"B"_s);
+ QCOMPARE(classA->implicitConversions().size(), 1);
+ QCOMPARE(classA->implicitConversions().constFirst()->type().cppSignature(),
+ u"A"_s);
+ QCOMPARE(classA->implicitConversions().constFirst()->ownerClass()->name(),
+ u"B"_s);
+}
+
+QTEST_APPLESS_MAIN(TestConversionOperator)
diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h
new file mode 100644
index 000000000..68288d240
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCONVERSIONOPERATOR_H
+#define TESTCONVERSIONOPERATOR_H
+#include <QtCore/QObject>
+
+class TestConversionOperator : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testConversionOperator();
+ void testConversionOperatorOfDiscardedClass();
+ void testRemovedConversionOperator();
+ void testConversionOperatorReturningReference();
+ void testConversionOperatorReturningConstReference();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp
new file mode 100644
index 000000000..b5efd92a6
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp
@@ -0,0 +1,240 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testconversionruletag.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <complextypeentry.h>
+#include <customconversion.h>
+#include <primitivetypeentry.h>
+#include <valuetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtCore/QFile>
+#include <QtCore/QTemporaryFile>
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestConversionRuleTag::testConversionRuleTagWithFile()
+{
+ // FIXME PYSIDE7 remove
+ // temp file used later
+ constexpr auto conversionData = "Hi! I'm a conversion rule."_L1;
+ QTemporaryFile file;
+ QVERIFY(file.open());
+ QCOMPARE(file.write(conversionData.constData()), conversionData.size());
+ file.close();
+
+ const char cppCode[] = "struct A {};\n";
+ QString xmlCode = u"\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <conversion-rule class='target' file='"_s + file.fileName() + u"'/>\n\
+ </value-type>\n\
+ </typesystem>\n"_s;
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().data()));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto typeEntry = classA->typeEntry();
+ QVERIFY(typeEntry->isValue());
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry);
+ QVERIFY(vte->hasTargetConversionRule());
+ QCOMPARE(vte->targetConversionRule(), conversionData);
+}
+
+void TestConversionRuleTag::testConversionRuleTagReplace()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ A();\n\
+ A(const char*, int);\n\
+ };\n\
+ struct B {\n\
+ A createA();\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='char'/>\n\
+ <primitive-type name='A'>\n\
+ <conversion-rule>\n\
+ <native-to-target>\n\
+ DoThis();\n\
+ return ConvertFromCppToPython(%IN);\n\
+ </native-to-target>\n\
+ <target-to-native>\n\
+ <add-conversion type='TargetNone' check='%IN == Target_None'>\n\
+ DoThat();\n\
+ DoSomething();\n\
+ %OUT = A();\n\
+ </add-conversion>\n\
+ <add-conversion type='B' check='CheckIfInputObjectIsB(%IN)'>\n\
+ %OUT = %IN.createA();\n\
+ </add-conversion>\n\
+ <add-conversion type='String' check='String_Check(%IN)'>\n\
+ %OUT = new A(String_AsString(%IN), String_GetSize(%IN));\n\
+ </add-conversion>\n\
+ </target-to-native>\n\
+ </conversion-rule>\n\
+ </primitive-type>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ auto *typeDb = TypeDatabase::instance();
+ auto typeA = typeDb->findPrimitiveType(u"A"_s);
+ QVERIFY(typeA);
+
+ QVERIFY(typeA->hasCustomConversion());
+ auto conversion = typeA->customConversion();
+
+ QCOMPARE(typeA, conversion->ownerType());
+ QCOMPARE(conversion->nativeToTargetConversion().simplified(),
+ u"DoThis(); return ConvertFromCppToPython(%IN);");
+
+ QVERIFY(conversion->replaceOriginalTargetToNativeConversions());
+ QVERIFY(conversion->hasTargetToNativeConversions());
+ QCOMPARE(conversion->targetToNativeConversions().size(), 3);
+
+ QVERIFY(!conversion->targetToNativeConversions().isEmpty());
+ auto toNative = conversion->targetToNativeConversions().at(0);
+ QCOMPARE(toNative.sourceTypeName(), u"TargetNone");
+ QVERIFY(toNative.isCustomType());
+ QCOMPARE(toNative.sourceType(), nullptr);
+ QCOMPARE(toNative.sourceTypeCheck(), u"%IN == Target_None");
+ QCOMPARE(toNative.conversion().simplified(),
+ u"DoThat(); DoSomething(); %OUT = A();");
+
+ QVERIFY(conversion->targetToNativeConversions().size() > 1);
+ toNative = conversion->targetToNativeConversions().at(1);
+ QCOMPARE(toNative.sourceTypeName(), u"B");
+ QVERIFY(!toNative.isCustomType());
+ auto typeB = typeDb->findType(u"B"_s);
+ QVERIFY(typeB);
+ QCOMPARE(toNative.sourceType(), typeB);
+ QCOMPARE(toNative.sourceTypeCheck(), u"CheckIfInputObjectIsB(%IN)");
+ QCOMPARE(toNative.conversion().trimmed(), u"%OUT = %IN.createA();");
+
+ QVERIFY(conversion->targetToNativeConversions().size() > 2);
+ toNative = conversion->targetToNativeConversions().at(2);
+ QCOMPARE(toNative.sourceTypeName(), u"String");
+ QVERIFY(toNative.isCustomType());
+ QCOMPARE(toNative.sourceType(), nullptr);
+ QCOMPARE(toNative.sourceTypeCheck(), u"String_Check(%IN)");
+ QCOMPARE(toNative.conversion().trimmed(),
+ u"%OUT = new A(String_AsString(%IN), String_GetSize(%IN));");
+}
+
+void TestConversionRuleTag::testConversionRuleTagAdd()
+{
+ const char cppCode[] = "\
+ struct Date {\n\
+ Date();\n\
+ Date(int, int, int);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='Date'>\n\
+ <conversion-rule>\n\
+ <target-to-native replace='no'>\n\
+ <add-conversion type='TargetDate' check='TargetDate_Check(%IN)'>\n\
+if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n\
+%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));\n\
+ </add-conversion>\n\
+ </target-to-native>\n\
+ </conversion-rule>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "Date");
+ QVERIFY(classA);
+
+ QVERIFY(classA->typeEntry()->isValue());
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(classA->typeEntry());
+ QVERIFY(vte->hasCustomConversion());
+ auto conversion = vte->customConversion();
+
+ QCOMPARE(conversion->nativeToTargetConversion(), QString());
+
+ QVERIFY(!conversion->replaceOriginalTargetToNativeConversions());
+ QVERIFY(conversion->hasTargetToNativeConversions());
+ QCOMPARE(conversion->targetToNativeConversions().size(), 1);
+
+ QVERIFY(!conversion->targetToNativeConversions().isEmpty());
+ const auto &toNative = conversion->targetToNativeConversions().constFirst();
+ QCOMPARE(toNative.sourceTypeName(), u"TargetDate");
+ QVERIFY(toNative.isCustomType());
+ QCOMPARE(toNative.sourceType(), nullptr);
+ QCOMPARE(toNative.sourceTypeCheck(), u"TargetDate_Check(%IN)");
+ QCOMPARE(toNative.conversion().trimmed(),
+ uR"(if (!TargetDateTimeAPI) TargetDateTime_IMPORT;
+%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));)");
+}
+
+void TestConversionRuleTag::testConversionRuleTagWithInsertTemplate()
+{
+ const char cppCode[] = "struct A {};";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <!-- single line -->\n\
+ <template name='native_to_target'>return ConvertFromCppToPython(%IN);</template>\n\
+ <!-- multi-line -->\n\
+ <template name='target_to_native'>\n\
+%OUT = %IN.createA();\n\
+ </template>\n\
+ <primitive-type name='A'>\n\
+ <conversion-rule>\n\
+ <native-to-target>\n\
+ <insert-template name='native_to_target'/>\n\
+ </native-to-target>\n\
+ <target-to-native>\n\
+ <add-conversion type='TargetType'>\n\
+ <insert-template name='target_to_native'/>\n\
+ </add-conversion>\n\
+ </target-to-native>\n\
+ </conversion-rule>\n\
+ </primitive-type>\n\
+ </typesystem>\n";
+
+ const char nativeToTargetExpected[] =
+ "// TEMPLATE - native_to_target - START\n"
+ "return ConvertFromCppToPython(%IN);\n"
+ "// TEMPLATE - native_to_target - END";
+
+ const char targetToNativeExpected[] =
+ "// TEMPLATE - target_to_native - START\n"
+ "%OUT = %IN.createA();\n"
+ "// TEMPLATE - target_to_native - END";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ auto *typeDb = TypeDatabase::instance();
+ auto typeA = typeDb->findPrimitiveType(u"A"_s);
+ QVERIFY(typeA);
+
+ QVERIFY(typeA->hasCustomConversion());
+ auto conversion = typeA->customConversion();
+
+ QCOMPARE(typeA, conversion->ownerType());
+ QCOMPARE(conversion->nativeToTargetConversion().trimmed(),
+ QLatin1StringView(nativeToTargetExpected));
+
+ QVERIFY(conversion->hasTargetToNativeConversions());
+ QCOMPARE(conversion->targetToNativeConversions().size(), 1);
+
+ QVERIFY(!conversion->targetToNativeConversions().isEmpty());
+ const auto &toNative = conversion->targetToNativeConversions().constFirst();
+ QCOMPARE(toNative.conversion().trimmed(),
+ QLatin1StringView(targetToNativeExpected));
+}
+
+QTEST_APPLESS_MAIN(TestConversionRuleTag)
diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h
new file mode 100644
index 000000000..64d496cc3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCONVERSIONRULE_H
+#define TESTCONVERSIONRULE_H
+
+#include <QtCore/QObject>
+
+class TestConversionRuleTag : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testConversionRuleTagWithFile();
+ void testConversionRuleTagReplace();
+ void testConversionRuleTagAdd();
+ void testConversionRuleTagWithInsertTemplate();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp b/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp
new file mode 100644
index 000000000..c3a3ebef0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testctorinformation.h"
+#include "abstractmetabuilder.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestCtorInformation::testCtorIsPrivate()
+{
+ const char cppCode[] = "class Control { public: Control() {} };\n\
+ class Subject { private: Subject() {} };\n\
+ class CtorLess { };\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <value-type name='Control'/>\n\
+ <object-type name='Subject'/>\n\
+ <value-type name='CtorLess'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(klass->hasNonPrivateConstructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasNonPrivateConstructor());
+ klass = AbstractMetaClass::findClass(classes, "CtorLess");
+ QVERIFY(klass);
+ QVERIFY(klass->hasNonPrivateConstructor());
+}
+
+void TestCtorInformation::testHasNonPrivateCtor()
+{
+ const char cppCode[] = "template<typename T>\n\
+ struct Base { Base(double) {} };\n\
+ typedef Base<int> Derived;\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='double'/>\n\
+ <object-type name='Base' generate='no'/>\n\
+ <object-type name='Derived'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto base = AbstractMetaClass::findClass(classes, "Base");
+ QCOMPARE(base->hasNonPrivateConstructor(), true);
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QCOMPARE(derived->hasNonPrivateConstructor(), true);
+}
+
+QTEST_APPLESS_MAIN(TestCtorInformation)
diff --git a/sources/shiboken6/ApiExtractor/tests/testctorinformation.h b/sources/shiboken6/ApiExtractor/tests/testctorinformation.h
new file mode 100644
index 000000000..58f1648e4
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testctorinformation.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCTORINFORMATION_H
+#define TESTCTORINFORMATION_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestCtorInformation: public QObject
+{
+ Q_OBJECT
+private slots:
+ void testCtorIsPrivate();
+ void testHasNonPrivateCtor();
+};
+
+#endif // TESTCTORINFORMATION_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp
new file mode 100644
index 000000000..16f50e69d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp
@@ -0,0 +1,228 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testdroptypeentries.h"
+#include "testutil.h"
+#include <abstractmetaenum.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+#include <conditionalstreamreader.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+static const char cppCode[] = "\
+ struct ValueA {};\n\
+ struct ValueB {};\n\
+ struct ObjectA {};\n\
+ struct ObjectB {};\n\
+ namespace NamespaceA {\n\
+ struct InnerClassA {};\n\
+ namespace InnerNamespaceA {}\n\
+ }\n\
+ namespace NamespaceB {}\n\
+ enum EnumA { Value0 };\n\
+ enum EnumB { Value1 };\n\
+ void funcA();\n\
+ void funcB();\n";
+
+static const char xmlCode[] = "\
+<typesystem package='Foo'>\n\
+ <value-type name='ValueA'/>\n\
+ <value-type name='ValueB'/>\n\
+ <object-type name='ObjectA'/>\n\
+ <object-type name='ObjectB'/>\n\
+ <namespace-type name='NamespaceA'>\n\
+ <value-type name='InnerClassA'/>\n\
+ <namespace-type name='InnerNamespaceA'/>\n\
+ </namespace-type>\n\
+ <namespace-type name='NamespaceB'/>\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ <function signature='funcA()'/>\n\
+ <function signature='funcB()'/>\n\
+</typesystem>\n";
+
+void TestDropTypeEntries::testDropEntries()
+{
+ const QStringList droppedEntries{u"Foo.ValueB"_s,
+ u"ObjectB"_s, // Check whether module can be omitted
+ u"Foo.NamespaceA.InnerClassA"_s,
+ u"Foo.NamespaceB"_s, u"Foo.EnumB"_s,
+ u"Foo.funcB()"_s,
+ u"Foo.NamespaceA.InnerNamespaceA"_s};
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false,
+ QString(), droppedEntries));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(AbstractMetaClass::findClass(classes, "ValueA"));
+ QVERIFY(!AbstractMetaClass::findClass(classes, "ValueB"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "ObjectA"));
+ QVERIFY(!AbstractMetaClass::findClass(classes, "ObjectB"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA"));
+ QVERIFY(!AbstractMetaClass::findClass(classes, "NamespaceA::InnerClassA"));
+ QVERIFY(!AbstractMetaClass::findClass(classes, "NamespaceB"));
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 1);
+ QCOMPARE(globalEnums.constFirst().name(), u"EnumA");
+
+ auto *td = TypeDatabase::instance();
+ QVERIFY(td->findType(u"funcA"_s));
+ QVERIFY(!td->findType(u"funcB"_s));
+}
+
+void TestDropTypeEntries::testDontDropEntries()
+{
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(AbstractMetaClass::findClass(classes, "ValueA"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "ValueB"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "ObjectA"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "ObjectB"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA::InnerClassA"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceB"));
+
+ QCOMPARE(builder->globalEnums().size(), 2);
+
+ auto *td = TypeDatabase::instance();
+ QVERIFY(td->findType(u"funcA"_s));
+ QVERIFY(td->findType(u"funcB"_s));
+}
+
+static const char cppCode2[] = "\
+ struct ValueA {\n\
+ void func();\n\
+ };\n";
+
+static const char xmlCode2[] = R"(
+<typesystem package='Foo'>
+ <value-type name='ValueA'>
+ <modify-function signature='func()' remove='all'/>
+ </value-type>
+</typesystem>
+)";
+
+void TestDropTypeEntries::testDropEntryWithChildTags()
+{
+ QStringList droppedEntries(u"Foo.ValueA"_s);
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false,
+ QString(), droppedEntries));
+ QVERIFY(builder);
+ QVERIFY(!AbstractMetaClass::findClass(builder->classes(), "ValueA"));
+}
+
+
+void TestDropTypeEntries::testDontDropEntryWithChildTags()
+{
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false));
+ QVERIFY(builder);
+ QVERIFY(AbstractMetaClass::findClass(builder->classes(), "ValueA"));
+}
+
+void TestDropTypeEntries::testConditionalParsing_data()
+{
+ const QString xml = R"(<?xml version="1.0" encoding="UTF-8"?>
+<root>
+ <tag1>text</tag1>
+ <?if keyword1?>
+ <tag2>text</tag2>
+ <?if keyword2?>
+ <tag3>text</tag3>
+ <?endif?>
+ <?if keyword1 !keyword2?>
+ <tag4>text</tag4>
+ <?endif?>
+ <?endif?>
+ <tag5>text</tag5>
+ <?if !keyword99?> <!-- Exclusion only -->
+ <tag6>text</tag6>
+ <?endif?>
+</root>)"_L1;
+
+ constexpr auto root = "root"_L1;
+ constexpr auto tag1 = "tag1"_L1;
+ constexpr auto tag2 = "tag2"_L1;
+ constexpr auto tag3 = "tag3"_L1;
+ constexpr auto tag4 = "tag4"_L1;
+ constexpr auto tag5 = "tag5"_L1;
+ constexpr auto tag6 = "tag6"_L1;
+ constexpr auto keyword1 = "keyword1"_L1;
+ constexpr auto keyword2 = "keyword2"_L1;
+
+ QTest::addColumn<QString>("xml");
+ QTest::addColumn<QStringList>("keywords");
+ QTest::addColumn<QStringList>("expectedTags");
+
+ QTest::newRow("no-keywords")
+ << xml << QStringList{} << QStringList{root, tag1, tag5, tag6};
+
+ QTest::newRow("skip-nested-condition")
+ << xml << QStringList{keyword1}
+ << QStringList{root, tag1, tag2, tag4, tag5, tag6};
+
+ QTest::newRow("both/check-not")
+ << xml << QStringList{keyword1, keyword2}
+ << QStringList{root, tag1, tag2, tag3, tag5, tag6};
+}
+
+// Parse XML and return a list of tags encountered
+static QStringList parseXml(const QString &xml, const QStringList &keywords)
+{
+ QStringList tags;
+ ConditionalStreamReader reader(xml);
+ reader.setConditions(keywords);
+ while (!reader.atEnd()) {
+ auto t = reader.readNext();
+ switch (t) {
+ case QXmlStreamReader::StartElement:
+ tags.append(reader.name().toString());
+ break;
+ default:
+ break;
+ }
+ }
+ return tags;
+}
+
+void TestDropTypeEntries::testConditionalParsing()
+{
+ QFETCH(QString, xml);
+ QFETCH(QStringList, keywords);
+ QFETCH(QStringList, expectedTags);
+
+ const QStringList actualTags = parseXml(xml, keywords);
+ QCOMPARE(actualTags, expectedTags);
+}
+
+void TestDropTypeEntries::testEntityParsing()
+{
+ const QString xml = R"(<?xml version="1.0" encoding="UTF-8"?>
+<root>
+ <?entity testentity word1 word2?>
+ <text>bla &testentity;</text>
+</root>)"_L1;
+
+ QString actual;
+ ConditionalStreamReader reader(xml);
+ while (!reader.atEnd()) {
+ auto t = reader.readNext();
+ switch (t) {
+ case QXmlStreamReader::Characters:
+ actual.append(reader.text());
+ default:
+ break;
+ }
+ }
+ QVERIFY2(!reader.hasError(), qPrintable(reader.errorString()));
+ QCOMPARE(actual.trimmed(), u"bla word1 word2");
+}
+
+QTEST_APPLESS_MAIN(TestDropTypeEntries)
diff --git a/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h
new file mode 100644
index 000000000..98717bd21
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTDROPTYPEENTRIES_H
+#define TESTDROPTYPEENTRIES_H
+
+#include <QtCore/QObject>
+
+class TestDropTypeEntries : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testDropEntries();
+ void testDontDropEntries();
+ void testDropEntryWithChildTags();
+ void testDontDropEntryWithChildTags();
+ void testConditionalParsing_data();
+ void testConditionalParsing();
+ void testEntityParsing();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp
new file mode 100644
index 000000000..2152d39de
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp
@@ -0,0 +1,158 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testdtorinformation.h"
+#include "abstractmetabuilder.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestDtorInformation::testDtorIsPrivate()
+{
+ const char cppCode[] = R"(class Control {
+public:
+ ~Control() {}
+};
+class Subject {
+private:
+ ~Subject() {}
+};
+)";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="Control"/>
+ <value-type name="Subject"/>
+</typesystem>)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasPrivateDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->hasPrivateDestructor());
+}
+
+void TestDtorInformation::testDtorIsProtected()
+{
+ const char cppCode[] = R"(class Control {
+public:
+ ~Control() {}
+};
+class Subject {
+protected:
+ ~Subject() {}
+};
+)";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="Control"/>
+ <value-type name="Subject"/>
+</typesystem>)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasProtectedDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->hasProtectedDestructor());
+}
+
+void TestDtorInformation::testDtorIsVirtual()
+{
+ const char cppCode[] = R"(class Control {
+public:
+ ~Control() {}
+};
+class Subject {
+protected:
+ virtual ~Subject() {}
+};
+)";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="Control"/>
+ <value-type name="Subject"/>
+</typesystem>)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasVirtualDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->hasVirtualDestructor());
+}
+
+void TestDtorInformation::testDtorFromBaseIsVirtual()
+{
+ const char cppCode[] = R"CPP(class ControlBase { public: ~ControlBase() {} };
+class Control : public ControlBase {};
+class SubjectBase { public: virtual ~SubjectBase() {} };
+class Subject : public SubjectBase {};
+)CPP";
+ const char xmlCode[] = R"XML(<typesystem package="Foo"><value-type name="ControlBase"/>
+<value-type name="Control"/>"
+<value-type name="SubjectBase"/>"
+<value-type name="Subject"/>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 4);
+
+ auto klass = AbstractMetaClass::findClass(classes, "ControlBase");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasVirtualDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasVirtualDestructor());
+
+ klass = AbstractMetaClass::findClass(classes, "SubjectBase");
+ QVERIFY(klass);
+ QVERIFY(klass->hasVirtualDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->hasVirtualDestructor());
+}
+
+void TestDtorInformation::testClassWithVirtualDtorIsPolymorphic()
+{
+ const char cppCode[] = R"(class Control {
+public:
+ virtual ~Control() {}
+};
+class Subject {
+protected:
+ virtual ~Subject() {}
+};
+)";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="Control"/>
+ <value-type name="Subject"/>
+</typesystem>)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(klass->isPolymorphic());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->isPolymorphic());
+}
+
+QTEST_APPLESS_MAIN(TestDtorInformation)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h
new file mode 100644
index 000000000..0f8cb59b3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTDTORINFORMATION_H
+#define TESTDTORINFORMATION_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestDtorInformation: public QObject
+{
+ Q_OBJECT
+private slots:
+ void testDtorIsPrivate();
+ void testDtorIsProtected();
+ void testDtorIsVirtual();
+ void testDtorFromBaseIsVirtual();
+ void testClassWithVirtualDtorIsPolymorphic();
+};
+
+#endif // TESTDTORINFORMATION_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testenum.cpp b/sources/shiboken6/ApiExtractor/tests/testenum.cpp
new file mode 100644
index 000000000..c7c2b8b3b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testenum.cpp
@@ -0,0 +1,577 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testenum.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetaenum.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetabuilder_p.h>
+#include <enumtypeentry.h>
+#include <flagstypeentry.h>
+#include <parser/enumvalue.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestEnum::testEnumCppSignature()
+{
+ const char cppCode[] = "\
+ enum GlobalEnum { A, B };\n\
+ \n\
+ struct A {\n\
+ enum ClassEnum { CA, CB };\n\
+ void method(ClassEnum);\n\
+ };\n\
+ void func(A::ClassEnum);\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <enum-type name='GlobalEnum'/>\n\
+ <value-type name='A'>\n\
+ <enum-type name='ClassEnum'/>\n\
+ </value-type>\n\
+ <function signature='func(A::ClassEnum)'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 1);
+ QCOMPARE(globalEnums.constFirst().name(), u"GlobalEnum");
+
+ // enum as parameter of a function
+ const auto functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 1);
+ QCOMPARE(functions.constFirst()->arguments().size(), 1);
+ QCOMPARE(functions.constFirst()->arguments().constFirst().type().cppSignature(),
+ u"A::ClassEnum");
+
+ // enum as parameter of a method
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QCOMPARE(classA->enums().size(), 1);
+ const auto funcs = classA->queryFunctionsByName(u"method"_s);
+ QVERIFY(!funcs.isEmpty());
+ const auto method = funcs.constFirst();
+ AbstractMetaArgument arg = method->arguments().constFirst();
+ QCOMPARE(arg.type().name(), u"ClassEnum");
+ QCOMPARE(arg.type().cppSignature(), u"A::ClassEnum");
+ QCOMPARE(functions.constFirst()->arguments().size(), 1);
+ arg = functions.constFirst()->arguments().constFirst();
+ QCOMPARE(arg.type().name(), u"ClassEnum");
+ QCOMPARE(arg.type().cppSignature(), u"A::ClassEnum");
+
+ AbstractMetaEnumList classEnums = classA->enums();
+ QVERIFY(!classEnums.isEmpty());
+ QCOMPARE(classEnums.constFirst().name(), u"ClassEnum");
+ auto e = AbstractMetaClass::findEnumValue(classes, u"CA"_s);
+ QVERIFY(e.has_value());
+ e = AbstractMetaClass::findEnumValue(classes, u"ClassEnum::CA"_s);
+ QVERIFY(e.has_value());
+}
+
+void TestEnum::testEnumWithApiVersion()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ enum ClassEnum { EnumA, EnumB };\n\
+ enum ClassEnum2 { EnumC, EnumD };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <enum-type name='ClassEnum' since='0.1'/>\n\
+ <enum-type name='ClassEnum2' since='0.2'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes[0]->enums().size(), 1);
+}
+
+void TestEnum::testAnonymousEnum()
+{
+ const char cppCode[] = "\
+ enum { Global0, Global1 };\n\
+ struct A {\n\
+ enum { A0, A1 };\n\
+ enum { isThis = true, isThat = false };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <!-- Uses the first value of the enum to identify it. -->\n\
+ <enum-type identified-by-value='Global0'/>\n\
+ <value-type name='A'>\n\
+ <!-- Uses the second value of the enum to identify it. -->\n\
+ <enum-type identified-by-value='A1'/>\n\
+ <enum-type identified-by-value='isThis'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 1);
+ QCOMPARE(globalEnums.constFirst().typeEntry()->qualifiedCppName(),
+ u"Global0");
+ QVERIFY(globalEnums.constFirst().isAnonymous());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes[0]->enums().size(), 2);
+
+ auto anonEnumA1 = classes[0]->findEnum(u"A1"_s);
+ QVERIFY(anonEnumA1.has_value());
+ QVERIFY(anonEnumA1->isAnonymous());
+ QCOMPARE(anonEnumA1->typeEntry()->qualifiedCppName(), u"A::A1");
+
+ AbstractMetaEnumValue enumValueA0 = anonEnumA1->values().constFirst();
+ QCOMPARE(enumValueA0.name(), u"A0");
+ QCOMPARE(enumValueA0.value().value(), 0);
+ QCOMPARE(enumValueA0.stringValue(), QString());
+
+ AbstractMetaEnumValue enumValueA1 = anonEnumA1->values().constLast();
+ QCOMPARE(enumValueA1.name(), u"A1");
+ QCOMPARE(enumValueA1.value().value(), 1);
+ QCOMPARE(enumValueA1.stringValue(), QString());
+
+ auto anonEnumIsThis = classes[0]->findEnum(u"isThis"_s);
+ QVERIFY(anonEnumIsThis.has_value());
+ QVERIFY(anonEnumIsThis->isAnonymous());
+ QCOMPARE(anonEnumIsThis->typeEntry()->qualifiedCppName(), u"A::isThis");
+
+ AbstractMetaEnumValue enumValueIsThis = anonEnumIsThis->values().constFirst();
+ QCOMPARE(enumValueIsThis.name(), u"isThis");
+ QCOMPARE(enumValueIsThis.value().value(), static_cast<int>(true));
+ QCOMPARE(enumValueIsThis.stringValue(), u"true");
+
+ AbstractMetaEnumValue enumValueIsThat = anonEnumIsThis->values().constLast();
+ QCOMPARE(enumValueIsThat.name(), u"isThat");
+ QCOMPARE(enumValueIsThat.value().value(), static_cast<int>(false));
+ QCOMPARE(enumValueIsThat.stringValue(), u"false");
+}
+
+void TestEnum::testGlobalEnums()
+{
+ const char cppCode[] = "\
+ enum EnumA { A0, A1 };\n\
+ enum EnumB { B0 = 2, B1 = 0x4 };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 2);
+
+ AbstractMetaEnum enumA = globalEnums.constFirst();
+ QCOMPARE(enumA.typeEntry()->qualifiedCppName(), u"EnumA");
+
+ AbstractMetaEnumValue enumValueA0 = enumA.values().constFirst();
+ QCOMPARE(enumValueA0.name(), u"A0");
+ QCOMPARE(enumValueA0.value().value(), 0);
+ QCOMPARE(enumValueA0.stringValue(), QString());
+
+ AbstractMetaEnumValue enumValueA1 = enumA.values().constLast();
+ QCOMPARE(enumValueA1.name(), u"A1");
+ QCOMPARE(enumValueA1.value().value(), 1);
+ QCOMPARE(enumValueA1.stringValue(), QString());
+
+ AbstractMetaEnum enumB = globalEnums.constLast();
+ QCOMPARE(enumB.typeEntry()->qualifiedCppName(), u"EnumB");
+
+ AbstractMetaEnumValue enumValueB0 = enumB.values().constFirst();
+ QCOMPARE(enumValueB0.name(), u"B0");
+ QCOMPARE(enumValueB0.value().value(), 2);
+ QCOMPARE(enumValueB0.stringValue(), u"2");
+
+ AbstractMetaEnumValue enumValueB1 = enumB.values().constLast();
+ QCOMPARE(enumValueB1.name(), u"B1");
+ QCOMPARE(enumValueB1.value().value(), 4);
+ QCOMPARE(enumValueB1.stringValue(), u"0x4");
+}
+
+void TestEnum::testEnumValueFromNeighbourEnum()
+{
+ const char cppCode[] = "\
+ namespace A {\n\
+ enum EnumA { ValueA0, ValueA1 };\n\
+ enum EnumB { ValueB0 = A::ValueA1, ValueB1 = ValueA0 };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <namespace-type name='A'>\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes[0]->enums().size(), 2);
+
+ auto enumA = classes[0]->findEnum(u"EnumA"_s);
+ QVERIFY(enumA.has_value());
+ QCOMPARE(enumA->typeEntry()->qualifiedCppName(), u"A::EnumA");
+
+ AbstractMetaEnumValue enumValueA0 = enumA->values().constFirst();
+ QCOMPARE(enumValueA0.name(), u"ValueA0");
+ QCOMPARE(enumValueA0.value().value(), 0);
+ QCOMPARE(enumValueA0.stringValue(), QString());
+
+ AbstractMetaEnumValue enumValueA1 = enumA->values().constLast();
+ QCOMPARE(enumValueA1.name(), u"ValueA1");
+ QCOMPARE(enumValueA1.value().value(), 1);
+ QCOMPARE(enumValueA1.stringValue(), QString());
+
+ auto enumB = classes[0]->findEnum(u"EnumB"_s);
+ QVERIFY(enumB.has_value());
+ QCOMPARE(enumB->typeEntry()->qualifiedCppName(), u"A::EnumB");
+
+ AbstractMetaEnumValue enumValueB0 = enumB->values().constFirst();
+ QCOMPARE(enumValueB0.name(), u"ValueB0");
+ QCOMPARE(enumValueB0.value().value(), 1);
+ QCOMPARE(enumValueB0.stringValue(), u"A::ValueA1");
+
+ AbstractMetaEnumValue enumValueB1 = enumB->values().constLast();
+ QCOMPARE(enumValueB1.name(), u"ValueB1");
+ QCOMPARE(enumValueB1.value().value(), 0);
+ QCOMPARE(enumValueB1.stringValue(), u"ValueA0");
+}
+
+void TestEnum::testEnumValueFromExpression()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ enum EnumA : unsigned {\n\
+ ValueA0 = 3u,\n\
+ ValueA1 = ~3u,\n\
+ ValueA2 = 0xffffffff,\n\
+ ValueA3 = 0xf0,\n\
+ ValueA4 = 8 |ValueA3,\n\
+ ValueA5 = ValueA3|32,\n\
+ ValueA6 = ValueA3 >> 1,\n\
+ ValueA7 = ValueA3 << 1\n\
+ };\n\
+ enum EnumB : int {\n\
+ ValueB0 = ~3,\n\
+ };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ auto enumA = classA->findEnum(u"EnumA"_s);
+ QVERIFY(enumA.has_value());
+ QVERIFY(!enumA->isSigned());
+ QCOMPARE(enumA->typeEntry()->qualifiedCppName(), u"A::EnumA");
+
+ AbstractMetaEnumValue valueA0 = enumA->values().at(0);
+ QCOMPARE(valueA0.name(), u"ValueA0");
+ QCOMPARE(valueA0.stringValue(), u"3u");
+ QCOMPARE(valueA0.value().unsignedValue(), 3u);
+
+ AbstractMetaEnumValue valueA1 = enumA->values().at(1);
+ QCOMPARE(valueA1.name(), u"ValueA1");
+ QCOMPARE(valueA1.stringValue(), u"~3u");
+ QCOMPARE(valueA1.value().unsignedValue(), ~3u);
+
+ AbstractMetaEnumValue valueA2 = enumA->values().at(2);
+ QCOMPARE(valueA2.name(), u"ValueA2");
+ QCOMPARE(valueA2.stringValue(), u"0xffffffff");
+ QCOMPARE(valueA2.value().unsignedValue(), 0xffffffffu);
+
+ AbstractMetaEnumValue valueA3 = enumA->values().at(3);
+ QCOMPARE(valueA3.name(), u"ValueA3");
+ QCOMPARE(valueA3.stringValue(), u"0xf0");
+ QCOMPARE(valueA3.value().unsignedValue(), 0xf0u);
+
+ AbstractMetaEnumValue valueA4 = enumA->values().at(4);
+ QCOMPARE(valueA4.name(), u"ValueA4");
+ QCOMPARE(valueA4.stringValue(), u"8 |ValueA3");
+ QCOMPARE(valueA4.value().unsignedValue(), 8|0xf0u);
+
+ AbstractMetaEnumValue valueA5 = enumA->values().at(5);
+ QCOMPARE(valueA5.name(), u"ValueA5");
+ QCOMPARE(valueA5.stringValue(), u"ValueA3|32");
+ QCOMPARE(valueA5.value().unsignedValue(), 0xf0u|32);
+
+ AbstractMetaEnumValue valueA6 = enumA->values().at(6);
+ QCOMPARE(valueA6.name(), u"ValueA6");
+ QCOMPARE(valueA6.stringValue(), u"ValueA3 >> 1");
+ QCOMPARE(valueA6.value().unsignedValue(), 0xf0u >> 1);
+
+ AbstractMetaEnumValue valueA7 = enumA->values().at(7);
+ QCOMPARE(valueA7.name(), u"ValueA7");
+ QCOMPARE(valueA7.stringValue(), u"ValueA3 << 1");
+ QCOMPARE(valueA7.value().unsignedValue(), 0xf0u << 1);
+
+ const auto enumB = classA->findEnum(u"EnumB"_s);
+ QVERIFY(enumB.has_value());
+ QVERIFY(enumB->isSigned());
+ QCOMPARE(enumB->typeEntry()->qualifiedCppName(), u"A::EnumB");
+ QCOMPARE(enumB->values().size(), 1);
+ const AbstractMetaEnumValue valueB0 = enumB->values().at(0);
+ QCOMPARE(valueB0.name(), u"ValueB0");
+ QCOMPARE(valueB0.stringValue(), u"~3");
+ QCOMPARE(valueB0.value().value(), ~3);
+}
+
+void TestEnum::testPrivateEnum()
+{
+ const char cppCode[] = "\
+ class A {\n\
+ private:\n\
+ enum PrivateEnum { Priv0 = 0x0f, Priv1 = 0xf0 };\n\
+ public:\n\
+ enum PublicEnum { Pub0 = Priv0, Pub1 = A::Priv1 };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <enum-type name='PublicEnum'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->enums().size(), 2);
+
+ auto privateEnum = classA->findEnum(u"PrivateEnum"_s);
+ QVERIFY(privateEnum.has_value());
+ QVERIFY(privateEnum->isPrivate());
+ QCOMPARE(privateEnum->typeEntry()->qualifiedCppName(), u"A::PrivateEnum");
+
+ auto publicEnum = classA->findEnum(u"PublicEnum"_s);
+ QVERIFY(publicEnum.has_value());
+ QCOMPARE(publicEnum->typeEntry()->qualifiedCppName(), u"A::PublicEnum");
+
+ AbstractMetaEnumValue pub0 = publicEnum->values().constFirst();
+ QCOMPARE(pub0.name(), u"Pub0");
+ QCOMPARE(pub0.value().value(), 0x0f);
+ QCOMPARE(pub0.stringValue(), u"Priv0");
+
+ AbstractMetaEnumValue pub1 = publicEnum->values().constLast();
+ QCOMPARE(pub1.name(), u"Pub1");
+ QCOMPARE(pub1.value().value(), 0xf0);
+ QCOMPARE(pub1.stringValue(), u"A::Priv1");
+}
+
+void TestEnum::testTypedefEnum()
+{
+ const char cppCode[] = "\
+ typedef enum EnumA {\n\
+ A0,\n\
+ A1,\n\
+ } EnumA;\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <enum-type name='EnumA'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 1);
+
+ AbstractMetaEnum enumA = globalEnums.constFirst();
+ QCOMPARE(enumA.typeEntry()->qualifiedCppName(), u"EnumA");
+
+ AbstractMetaEnumValue enumValueA0 = enumA.values().constFirst();
+ QCOMPARE(enumValueA0.name(), u"A0");
+ QCOMPARE(enumValueA0.value().value(), 0);
+ QCOMPARE(enumValueA0.stringValue(), u"");
+
+ AbstractMetaEnumValue enumValueA1 = enumA.values().constLast();
+ QCOMPARE(enumValueA1.name(), u"A1");
+ QCOMPARE(enumValueA1.value().value(), 1);
+ QCOMPARE(enumValueA1.stringValue(), QString());
+}
+
+// Helper classes and functions for testing enum default value fixing.
+// Put the AbstractMetaBuilder into test fixture struct to avoid having
+// to re-parse for each data row.
+
+struct EnumDefaultValuesFixture
+{
+ std::shared_ptr<AbstractMetaBuilder> builder;
+
+ AbstractMetaType globalEnum;
+ AbstractMetaType testEnum;
+ AbstractMetaType testOptions;
+};
+
+Q_DECLARE_METATYPE(EnumDefaultValuesFixture)
+Q_DECLARE_METATYPE(AbstractMetaType)
+
+static int populateDefaultValuesFixture(EnumDefaultValuesFixture *fixture)
+{
+ static const char cppCode[] =R"(
+enum GlobalEnum { GE1, GE2 };
+namespace Test1
+{
+namespace Test2
+{
+ enum Enum1 { E1, E2 };
+ enum Option { O1, O2 };
+} // namespace Test2
+} // namespace Test1
+)";
+ static const char xmlCode[] = R"(
+<typesystem package="Foo">
+ <enum-type name='GlobalEnum'/>
+ <namespace-type name='Test1'>
+ <namespace-type name='Test2'>
+ <enum-type name='Enum1'/>
+ <enum-type name='Option' flags='Options'/>
+ </namespace-type>
+ </namespace-type>
+</typesystem>
+)";
+
+ fixture->builder.reset(TestUtil::parse(cppCode, xmlCode, false));
+ if (!fixture->builder)
+ return -1;
+
+ const auto globalEnums = fixture->builder->globalEnums();
+ if (globalEnums.size() != 1)
+ return -2;
+
+ fixture->globalEnum = AbstractMetaType(globalEnums.constFirst().typeEntry());
+ fixture->globalEnum.decideUsagePattern();
+
+ AbstractMetaClassCPtr testNamespace;
+ for (const auto &c : fixture->builder->classes()) {
+ if (c->name() == u"Test2") {
+ testNamespace = c;
+ break;
+ }
+ }
+ if (!testNamespace)
+ return -3;
+
+ const auto namespaceEnums = testNamespace->enums();
+ if (namespaceEnums.size() != 2)
+ return -4;
+ QList<EnumTypeEntryCPtr > enumTypeEntries{
+ std::static_pointer_cast<const EnumTypeEntry>(namespaceEnums.at(0).typeEntry()),
+ std::static_pointer_cast<const EnumTypeEntry>(namespaceEnums.at(1).typeEntry())};
+ if (enumTypeEntries.constFirst()->flags())
+ std::swap(enumTypeEntries[0], enumTypeEntries[1]);
+ fixture->testEnum = AbstractMetaType(enumTypeEntries.at(0));
+ fixture->testEnum.decideUsagePattern();
+ fixture->testOptions = AbstractMetaType(enumTypeEntries.at(1)->flags());
+ fixture->testOptions.decideUsagePattern();
+ return 0;
+}
+
+void TestEnum::testEnumDefaultValues_data()
+{
+ EnumDefaultValuesFixture fixture;
+ const int setupOk = populateDefaultValuesFixture(&fixture);
+
+ QTest::addColumn<EnumDefaultValuesFixture>("fixture");
+ QTest::addColumn<int>("setupOk"); // To verify setup
+ QTest::addColumn<AbstractMetaType>("metaType"); // Type and parameters for fixup
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("expected");
+
+ // Global should just remain unmodified
+ QTest::newRow("global") << fixture << setupOk
+ << fixture.globalEnum << "GE1" << "GE1";
+ QTest::newRow("global-int") << fixture << setupOk
+ << fixture.globalEnum << "42" << "42";
+ QTest::newRow("global-hex-int") << fixture << setupOk
+ << fixture.globalEnum << "0x10" << "0x10";
+ QTest::newRow("global-int-cast") << fixture << setupOk
+ << fixture.globalEnum << "GlobalEnum(-1)" << "GlobalEnum(-1)";
+
+ // Namespaced enum as number should remain unmodified
+ QTest::newRow("namespace-enum-int") << fixture << setupOk
+ << fixture.testEnum << "42" << "42";
+ QTest::newRow("namespace-enum-hex-int") << fixture << setupOk
+ << fixture.testEnum << "0x10" << "0x10";
+ // Partial qualification of namespaced enum
+ QTest::newRow("namespace-enum-qualified") << fixture << setupOk
+ << fixture.testEnum << "Enum1::E1" << "Test1::Test2::Enum1::E1";
+ // Unqualified namespaced enums
+ QTest::newRow("namespace-enum-unqualified") << fixture << setupOk
+ << fixture.testEnum << "E1" << "Test1::Test2::Enum1::E1";
+ // Namespaced enums cast from int should be qualified by scope
+ QTest::newRow("namespace-enum-int-cast") << fixture << setupOk
+ << fixture.testEnum << "Enum1(-1)" << "Test1::Test2::Enum1(-1)";
+
+ // Namespaced option as number should remain unmodified
+ QTest::newRow("namespace-option-int") << fixture << setupOk
+ << fixture.testOptions << "0x10" << "0x10";
+ QTest::newRow("namespace-option-expression") << fixture << setupOk
+ << fixture.testOptions << "0x10 | 0x20" << "0x10 | 0x20";
+ QTest::newRow("namespace-option-expression1") << fixture << setupOk
+ << fixture.testOptions << "0x10 | Test1::Test2::Option::O1"
+ << "0x10 | Test1::Test2::Option::O1";
+ QTest::newRow("namespace-option-expression2") << fixture << setupOk
+ << fixture.testOptions << "0x10 | O1" << "0x10 | Test1::Test2::Option::O1";
+ // Complicated expressions - should remain unmodified
+ QTest::newRow("namespace-option-expression-paren") << fixture << setupOk
+ << fixture.testOptions << "0x10 | (0x20 | 0x40 | O1)"
+ << "0x10 | (0x20 | 0x40 | O1)";
+
+ // Option: Cast Enum from int should be qualified
+ QTest::newRow("namespace-option-int-cast") << fixture << setupOk
+ << fixture.testOptions << "Option(0x10)" << "Test1::Test2::Option(0x10)";
+ // Option: Cast Flags from int should be qualified
+ QTest::newRow("namespace-options-int-cast") << fixture << setupOk
+ << fixture.testOptions << "Options(0x10 | 0x20)" << "Test1::Test2::Options(0x10 | 0x20)";
+ QTest::newRow("namespace-option-cast-expression1") << fixture << setupOk
+ << fixture.testOptions << "Test1::Test2::Options(0x10 | Test1::Test2::Option::O1)"
+ << "Test1::Test2::Options(0x10 | Test1::Test2::Option::O1)";
+ QTest::newRow("namespace-option-cast-expression2") << fixture << setupOk
+ << fixture.testOptions << "Options(0x10 | O1)"
+ << "Test1::Test2::Options(0x10 | Test1::Test2::Option::O1)";
+}
+
+void TestEnum::testEnumDefaultValues()
+{
+ QFETCH(EnumDefaultValuesFixture, fixture);
+ QFETCH(int, setupOk);
+ QFETCH(AbstractMetaType, metaType);
+ QFETCH(QString, input);
+ QFETCH(QString, expected);
+ QCOMPARE(setupOk, 0);
+ const QString actual = fixture.builder->fixEnumDefault(metaType, input);
+ QCOMPARE(actual, expected);
+}
+
+QTEST_APPLESS_MAIN(TestEnum)
diff --git a/sources/shiboken6/ApiExtractor/tests/testenum.h b/sources/shiboken6/ApiExtractor/tests/testenum.h
new file mode 100644
index 000000000..452755490
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testenum.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTENUM_H
+#define TESTENUM_H
+
+#include <QtCore/QObject>
+
+class TestEnum : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testEnumCppSignature();
+ void testEnumWithApiVersion();
+ void testAnonymousEnum();
+ void testGlobalEnums();
+ void testEnumValueFromNeighbourEnum();
+ void testEnumValueFromExpression();
+ void testPrivateEnum();
+ void testTypedefEnum();
+ void testEnumDefaultValues_data();
+ void testEnumDefaultValues();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp b/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp
new file mode 100644
index 000000000..fcc409a42
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testextrainclude.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <complextypeentry.h>
+#include <typesystemtypeentry.h>
+
+void TestExtraInclude::testClassExtraInclude()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <extra-includes>\n\
+ <include file-name='header.h' location='global'/>\n\
+ </extra-includes>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ QList<Include> includes = classA->typeEntry()->extraIncludes();
+ QCOMPARE(includes.size(), 1);
+ QCOMPARE(includes.constFirst().name(), u"header.h");
+}
+
+void TestExtraInclude::testGlobalExtraIncludes()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <extra-includes>\n\
+ <include file-name='header1.h' location='global'/>\n\
+ <include file-name='header2.h' location='global'/>\n\
+ </extra-includes>\n\
+ <value-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(AbstractMetaClass::findClass(classes, "A"));
+
+ auto *td = TypeDatabase::instance();
+ TypeSystemTypeEntryCPtr module = td->defaultTypeSystemType();
+ QVERIFY(module);
+ QCOMPARE(module->name(), u"Foo");
+
+ QList<Include> includes = module->extraIncludes();
+ QCOMPARE(includes.size(), 2);
+ QCOMPARE(includes.constFirst().name(), u"header1.h");
+ QCOMPARE(includes.constLast().name(), u"header2.h");
+}
+
+QTEST_APPLESS_MAIN(TestExtraInclude)
diff --git a/sources/shiboken6/ApiExtractor/tests/testextrainclude.h b/sources/shiboken6/ApiExtractor/tests/testextrainclude.h
new file mode 100644
index 000000000..6bcb57993
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testextrainclude.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTEXTRAINCLUDE_H
+#define TESTEXTRAINCLUDE_H
+
+#include <QtCore/QObject>
+
+class TestExtraInclude : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testClassExtraInclude();
+ void testGlobalExtraIncludes();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp
new file mode 100644
index 000000000..18eaf5774
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testfunctiontag.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <modifications.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestFunctionTag::testFunctionTagForSpecificSignature()
+{
+ const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='float'/>\n\
+ <function signature='globalFunction(int)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ TypeEntryCPtr func = TypeDatabase::instance()->findType(u"globalFunction"_s);
+ QVERIFY(func);
+ QCOMPARE(builder->globalFunctions().size(), 1);
+}
+
+void TestFunctionTag::testFunctionTagForAllSignatures()
+{
+ const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='float'/>\n\
+ <function signature='globalFunction(int)'/>\n\
+ <function signature='globalFunction(float)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ TypeEntryCPtr func = TypeDatabase::instance()->findType(u"globalFunction"_s);
+ QVERIFY(func);
+ QCOMPARE(builder->globalFunctions().size(), 2);
+}
+
+void TestFunctionTag::testRenameGlobalFunction()
+{
+ const char cppCode[] = "void global_function_with_ugly_name();\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <function signature='global_function_with_ugly_name()' rename='smooth'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ TypeEntryCPtr func = TypeDatabase::instance()->findType(u"global_function_with_ugly_name"_s);
+ QVERIFY(func);
+
+ QCOMPARE(builder->globalFunctions().size(), 1);
+ const auto metaFunc = builder->globalFunctions().constFirst();
+
+ QVERIFY(metaFunc);
+ QCOMPARE(metaFunc->modifications().size(), 1);
+ QVERIFY(metaFunc->modifications().constFirst().isRenameModifier());
+ QCOMPARE(metaFunc->modifications().constFirst().renamedToName(),
+ u"smooth");
+
+ QCOMPARE(metaFunc->name(), u"smooth");
+ QCOMPARE(metaFunc->originalName(), u"global_function_with_ugly_name");
+ QCOMPARE(metaFunc->minimalSignature(), u"global_function_with_ugly_name()");
+}
+
+QTEST_APPLESS_MAIN(TestFunctionTag)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h
new file mode 100644
index 000000000..7c60cb4e0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTFUNCTIONTAG_H
+#define TESTFUNCTIONTAG_H
+
+#include <QtCore/QObject>
+
+class TestFunctionTag : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testFunctionTagForSpecificSignature();
+ void testFunctionTagForAllSignatures();
+ void testRenameGlobalFunction();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp
new file mode 100644
index 000000000..899d00ad4
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp
@@ -0,0 +1,142 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testimplicitconversions.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+#include <QtTest/QTest>
+
+void TestImplicitConversions::testWithPrivateCtors()
+{
+ const char cppCode[] = "\
+ class B;\n\
+ class C;\n\
+ class A {\n\
+ A(const B&);\n\
+ public:\n\
+ A(const C&);\n\
+ };\n\
+ class B {};\n\
+ class C {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='C'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ const auto implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 1);
+ QCOMPARE(implicitConvs.constFirst()->arguments().constFirst().type().typeEntry(),
+ classC->typeEntry());
+}
+
+void TestImplicitConversions::testWithModifiedVisibility()
+{
+ const char cppCode[] = "\
+ class B;\n\
+ class A {\n\
+ public:\n\
+ A(const B&);\n\
+ };\n\
+ class B {};\n";
+ const char xmlCode[] = R"(
+<typesystem package='Foo'>
+ <value-type name='A'>
+ <modify-function signature='A(const B&amp;)' access='private'/>
+ </value-type>
+ <value-type name='B'/>
+</typesystem>
+)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 1);
+ QCOMPARE(implicitConvs.constFirst()->arguments().constFirst().type().typeEntry(),
+ classB->typeEntry());
+}
+
+
+void TestImplicitConversions::testWithAddedCtor()
+{
+ const char cppCode[] = "\
+ class B;\n\
+ class A {\n\
+ public:\n\
+ A(const B&);\n\
+ };\n\
+ class B {};\n\
+ class C {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <custom-type name='TARGETLANGTYPE'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='A(const C&amp;)'/>\n\
+ </value-type>\n\
+ <value-type name='B'>\n\
+ <add-function signature='B(TARGETLANGTYPE*)'/>\n\
+ </value-type>\n\
+ <value-type name='C'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ auto implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 2);
+
+ // Added constructors with custom types should never result in implicit converters.
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ implicitConvs = classB->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 0);
+}
+
+void TestImplicitConversions::testWithExternalConversionOperator()
+{
+ const char cppCode[] = "\
+ class A {};\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\n\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 1);
+ const auto &externalConvOps = classA->externalConversionOperators();
+ QCOMPARE(externalConvOps.size(), 1);
+
+ AbstractMetaFunctionCPtr convOp;
+ for (const auto &func : classB->functions()) {
+ if (func->isConversionOperator())
+ convOp = func;
+ }
+ QVERIFY(convOp);
+ QCOMPARE(implicitConvs.constFirst(), convOp);
+}
+
+QTEST_APPLESS_MAIN(TestImplicitConversions)
diff --git a/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h
new file mode 100644
index 000000000..e0678c5f5
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTIMPLICITCONVERSIONS_H
+#define TESTIMPLICITCONVERSIONS_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestImplicitConversions : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testWithPrivateCtors();
+ void testWithModifiedVisibility();
+ void testWithAddedCtor();
+ void testWithExternalConversionOperator();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp
new file mode 100644
index 000000000..23cf0f9ea
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp
@@ -0,0 +1,63 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testinserttemplate.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <codesnip.h>
+#include <modifications.h>
+#include <complextypeentry.h>
+#include <typesystemtypeentry.h>
+
+void TestInsertTemplate::testInsertTemplateOnClassInjectCode()
+{
+ const char cppCode[] = "struct A{};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <template name='code_template'>\n\
+ code template content\n\
+ </template>\n\
+ <value-type name='A'>\n\
+ <inject-code class='native'>\n\
+ <insert-template name='code_template'/>\n\
+ </inject-code>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->typeEntry()->codeSnips().size(), 1);
+ QString code = classA->typeEntry()->codeSnips().constFirst().code();
+ QVERIFY(code.contains(u"code template content"));
+}
+
+void TestInsertTemplate::testInsertTemplateOnModuleInjectCode()
+{
+ const char cppCode[] = "";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <template name='code_template'>\n\
+ code template content\n\
+ </template>\n\
+ <inject-code class='native'>\n\
+ <insert-template name='code_template'/>\n\
+ </inject-code>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(classes.isEmpty());
+
+ TypeSystemTypeEntryCPtr module = TypeDatabase::instance()->defaultTypeSystemType();
+ QVERIFY(module);
+ QCOMPARE(module->name(), u"Foo");
+ QCOMPARE(module->codeSnips().size(), 1);
+ QString code = module->codeSnips().constFirst().code().trimmed();
+ QVERIFY(code.contains(u"code template content"));
+}
+
+QTEST_APPLESS_MAIN(TestInsertTemplate)
diff --git a/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h
new file mode 100644
index 000000000..f4f67abc0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTINSERTTEMPLATE_H
+#define TESTINSERTTEMPLATE_H
+
+#include <QtCore/QObject>
+
+class TestInsertTemplate : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testInsertTemplateOnClassInjectCode();
+ void testInsertTemplateOnModuleInjectCode();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp
new file mode 100644
index 000000000..9cf2e0cc7
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp
@@ -0,0 +1,117 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testmodifydocumentation.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <abstractmetafunction.h>
+#include <documentation.h>
+#include <modifications.h>
+#include <complextypeentry.h>
+#include <qtdocparser.h>
+
+#include <qtcompat.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTemporaryDir>
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestModifyDocumentation::testModifyDocumentation()
+{
+ const char cppCode[] = "struct B { void b(); }; class A {};\n";
+ const char xmlCode[] =
+R"(<typesystem package="Foo">
+ <value-type name='B'>
+ <modify-function signature='b()' remove='all'/>
+ </value-type>
+ <value-type name='A'>
+ <modify-documentation xpath='description/brief'>&lt;brief>Modified Brief&lt;/brief></modify-documentation>
+ <modify-documentation xpath='description/para[3]'>&lt;para>Some changed contents here&lt;/para></modify-documentation>
+ </value-type>
+</typesystem>
+)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+ DocModificationList docMods = classA->typeEntry()->docModifications();
+ QCOMPARE(docMods.size(), 2);
+ QCOMPARE(docMods[0].code().trimmed(), u"<brief>Modified Brief</brief>");
+ QCOMPARE(docMods[0].signature(), QString());
+ QCOMPARE(docMods[1].code().trimmed(), u"<para>Some changed contents here</para>");
+ QCOMPARE(docMods[1].signature(), QString());
+
+ // Create a temporary directory for the documentation file since libxml2
+ // cannot handle Qt resources.
+ QTemporaryDir tempDir(QDir::tempPath() + u"/shiboken_testmodifydocXXXXXX"_s);
+ QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString()));
+ constexpr auto docFileName = "a.xml"_L1;
+ QVERIFY(QFile::copy(u":/"_s + docFileName, tempDir.filePath(docFileName)));
+
+ QtDocParser docParser;
+ docParser.setDocumentationDataDirectory(tempDir.path());
+ docParser.fillDocumentation(classA);
+
+ const Documentation &doc = classA->documentation();
+ const QString actualDocSimplified = doc.detailed().simplified();
+ const QString actualBriefSimplified = doc.brief().simplified();
+ QVERIFY(!actualDocSimplified.isEmpty());
+
+const char expectedDoc[] =
+R"(<?xml version="1.0"?>
+<description>oi
+<para>Paragraph number 1</para>
+<para>Paragraph number 2</para>
+<para>Some changed contents here</para>
+</description>
+)";
+ const QString expectedDocSimplified = QString::fromLatin1(expectedDoc).simplified();
+ // Check whether the first modification worked.
+ QVERIFY(actualBriefSimplified.contains(u"Modified Brief"));
+
+#ifndef HAVE_LIBXSLT
+ // QtXmlPatterns is unable to handle para[3] in style sheets,
+ // this only works in its XPath search.
+ QEXPECT_FAIL("", "QtXmlPatterns cannot handle para[3] (QTBUG-66925)", Abort);
+#endif
+ QCOMPARE(actualDocSimplified, expectedDocSimplified);
+}
+
+void TestModifyDocumentation::testInjectAddedFunctionDocumentation()
+{
+ const char cppCode[] ="class A {};\n";
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <value-type name='A'>
+ <add-function signature="foo(int@parameter_name@)">
+ <inject-documentation format="target" mode="append">
+ Injected documentation of added function foo.
+ </inject-documentation>
+ </add-function>
+ </value-type>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+ const auto f = classA->findFunction("foo");
+ QVERIFY(f);
+ QVERIFY(f->isUserAdded());
+ auto docMods = f->addedFunctionDocModifications();
+ QCOMPARE(docMods.size(), 1);
+ const QString code = docMods.constFirst().code();
+ QVERIFY(code.contains(u"Injected documentation of added function foo."));
+}
+
+// We expand QTEST_MAIN macro but using QCoreApplication instead of QApplication
+// because this test needs an event loop but can't use QApplication to avoid a crash
+// on our ARMEL/FRAMANTLE buildbot
+int main(int argc, char** argv)
+{
+ QCoreApplication app(argc, argv);
+ TestModifyDocumentation tc;
+ return QTest::qExec(&tc, argc, argv);
+}
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h
new file mode 100644
index 000000000..c1cc8f480
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTMODIFYDOCUMENTATION_H
+#define TESTMODIFYDOCUMENTATION_H
+
+#include <QtCore/QObject>
+
+class TestModifyDocumentation : public QObject
+{
+Q_OBJECT
+private slots:
+ void testModifyDocumentation();
+ void testInjectAddedFunctionDocumentation();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.qrc b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.qrc
new file mode 100644
index 000000000..76b1bfc61
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource>
+ <file>a.xml</file>
+ </qresource>
+</RCC>
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp
new file mode 100644
index 000000000..a7d40f70a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp
@@ -0,0 +1,480 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testmodifyfunction.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetabuilder_p.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <modifications.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestModifyFunction::testRenameArgument_data()
+{
+ QTest::addColumn<QByteArray>("pattern");
+ QTest::newRow("fixed_string") << QByteArrayLiteral("method(int)");
+ QTest::newRow("regular_expression") << QByteArrayLiteral("^method.*");
+}
+
+void TestModifyFunction::testRenameArgument()
+{
+ QFETCH(QByteArray, pattern);
+
+ const char cppCode[] = "\
+ struct A {\n\
+ void method(int=0);\n\
+ };\n";
+ const char xmlCode1[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <object-type name='A'>\n\
+ <modify-function signature='";
+ const char xmlCode2[] = R"('>
+ <modify-argument index='1' rename='otherArg'/>
+ </modify-function>
+ </object-type>
+ </typesystem>
+)";
+
+ const QByteArray xmlCode = QByteArray(xmlCode1) + pattern + QByteArray(xmlCode2);
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.constData(), false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto func = classA->findFunction("method");
+ QVERIFY(func);
+
+ QCOMPARE(func->argumentName(1), u"otherArg");
+}
+
+void TestModifyFunction::testOwnershipTransfer()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ virtual A* method();\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A' />\n\
+ <object-type name='B'>\n\
+ <modify-function signature='method()'>\n\
+ <modify-argument index='return'>\n\
+ <define-ownership owner='c++'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto func = classB->findFunction("method");
+ QVERIFY(func);
+
+ QCOMPARE(func->argumentTargetOwnership(func->ownerClass(), 0),
+ TypeSystem::CppOwnership);
+}
+
+
+void TestModifyFunction::invalidateAfterUse()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ virtual void call(int *a);\n\
+ };\n\
+ struct B : A {\n\
+ };\n\
+ struct C : B {\n\
+ virtual void call2(int *a);\n\
+ };\n\
+ struct D : C {\n\
+ virtual void call2(int *a);\n\
+ };\n\
+ struct E : D {\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <object-type name='A'>\n\
+ <modify-function signature='call(int*)'>\n\
+ <modify-argument index='1' invalidate-after-use='true'/>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ <object-type name='B' />\n\
+ <object-type name='C'>\n\
+ <modify-function signature='call2(int*)'>\n\
+ <modify-argument index='1' invalidate-after-use='true'/>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ <object-type name='D'>\n\
+ <modify-function signature='call2(int*)'>\n\
+ <modify-argument index='1' invalidate-after-use='true'/>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ <object-type name='E' />\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ auto func = classB->findFunction("call");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(classC);
+ func = classC->findFunction("call");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ func = classC->findFunction("call2");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ AbstractMetaClassCPtr classD = AbstractMetaClass::findClass(classes, "D");
+ QVERIFY(classD);
+ func = classD->findFunction("call");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ func = classD->findFunction("call2");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ const auto classE = AbstractMetaClass::findClass(classes, "E");
+ QVERIFY(classE);
+ func = classE->findFunction("call");
+ QVERIFY(func);
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ func = classE->findFunction("call2");
+ QVERIFY(func);
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+}
+
+void TestModifyFunction::testWithApiVersion()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ virtual A* method();\n\
+ virtual B* methodB();\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A' />\n\
+ <object-type name='B'>\n\
+ <modify-function signature='method()' since='0.1'>\n\
+ <modify-argument index='return'>\n\
+ <define-ownership owner='c++'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ <modify-function signature='methodB()' since='0.2'>\n\
+ <modify-argument index='return'>\n\
+ <define-ownership owner='c++'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ auto func = classB->findFunction("method");
+
+ auto returnOwnership = func->argumentTargetOwnership(func->ownerClass(), 0);
+ QCOMPARE(returnOwnership, TypeSystem::CppOwnership);
+
+ func = classB->findFunction("methodB");
+ returnOwnership = func->argumentTargetOwnership(func->ownerClass(), 0);
+ QVERIFY(returnOwnership != TypeSystem::CppOwnership);
+}
+
+// Modifications on class/typesystem level are tested below
+// in testScopedModifications().
+void TestModifyFunction::testAllowThread()
+{
+ const char cppCode[] =R"CPP(\
+struct A {
+ void f1();
+ void f2();
+ void f3();
+ int getter1() const;
+ int getter2() const;
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='A'>
+ <modify-function signature='f2()' allow-thread='auto'/>
+ <modify-function signature='f3()' allow-thread='no'/>
+ <modify-function signature='getter2()const' allow-thread='yes'/>
+ </object-type>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ // Nothing specified, true
+ const auto f1 = classA->findFunction("f1");
+ QVERIFY(f1);
+ QVERIFY(!f1->allowThread());
+
+ // 'auto' specified, should be false for nontrivial function
+ const auto f2 = classA->findFunction("f2");
+ QVERIFY(f2);
+ QVERIFY(f2->allowThread());
+
+ // 'no' specified, should be false
+ const auto f3 = classA->findFunction("f3");
+ QVERIFY(f3);
+ QVERIFY(!f3->allowThread());
+
+ // Nothing specified, should be false for simple getter
+ const auto getter1 = classA->findFunction("getter1");
+ QVERIFY(getter1);
+ QVERIFY(!getter1->allowThread());
+
+ // Forced to true simple getter
+ const auto getter2 = classA->findFunction("getter2");
+ QVERIFY(getter2);
+ QVERIFY(getter2->allowThread()); // Forced to true simple getter
+}
+
+void TestModifyFunction::testGlobalFunctionModification()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ void function(A* a = 0);\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='A'/>\n\
+ <function signature='function(A*)'>\n\
+ <modify-function signature='function(A*)'>\n\
+ <modify-argument index='1'>\n\
+ <replace-type modified-type='A'/>\n\
+ <replace-default-expression with='A()'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </function>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ QCOMPARE(builder->globalFunctions().size(), 1);
+
+ auto *td = TypeDatabase::instance();
+ FunctionModificationList mods = td->globalFunctionModifications({u"function(A*)"_s});
+ QCOMPARE(mods.size(), 1);
+ const QList<ArgumentModification> &argMods = mods.constFirst().argument_mods();
+ QCOMPARE(argMods.size(), 1);
+ ArgumentModification argMod = argMods.constFirst();
+ QCOMPARE(argMod.replacedDefaultExpression(), u"A()");
+
+ QVERIFY(!builder->globalFunctions().isEmpty());
+ const auto func = builder->globalFunctions().constFirst();
+ QCOMPARE(func->arguments().size(), 1);
+ const AbstractMetaArgument &arg = func->arguments().constFirst();
+ QCOMPARE(arg.type().cppSignature(), u"A *");
+ QCOMPARE(arg.originalDefaultValueExpression(), u"0");
+ QCOMPARE(arg.defaultValueExpression(), u"A()");
+}
+
+// Tests modifications of exception handling and allow-thread
+// on various levels.
+void TestModifyFunction::testScopedModifications_data()
+{
+ QTest::addColumn<QByteArray>("cppCode");
+ QTest::addColumn<QByteArray>("xmlCode");
+ QTest::addColumn<bool>("expectedGenerateUnspecified");
+ QTest::addColumn<bool>("expectedGenerateNonThrowing");
+ QTest::addColumn<bool>("expectedGenerateThrowing");
+ QTest::addColumn<bool>("expectedAllowThread");
+
+ const QByteArray cppCode = R"CPP(
+struct Base {
+};
+
+struct A : public Base {
+ void unspecified();
+ void nonThrowing() noexcept;
+# if __cplusplus >= 201703L // C++ 17
+ void throwing() noexcept(false);
+#else
+ void throwing() throw(int);
+#endif
+};
+)CPP";
+
+ // Default: Off
+ QTest::newRow("none")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package= 'Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << false << false << false // exception
+ << false; // allowthread
+
+ // Modify one function
+ QTest::newRow("modify-function1")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'>
+ <modify-function signature='throwing()' exception-handling='auto-on'/>
+ </object-type>
+</typesystem>)XML")
+ << false << false << true // exception
+ << false; // allowthread
+
+ // Flip defaults by modifying functions
+ QTest::newRow("modify-function2")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'>
+ <modify-function signature='unspecified()' exception-handling='auto-on'/>
+ <modify-function signature='throwing()' exception-handling='no'/>
+ </object-type>
+</typesystem>)XML")
+ << true << false << false // exception
+ << false; // allowthread
+
+ // Activate on type system level
+ QTest::newRow("typesystem-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo' exception-handling='auto-on' allow-thread='no'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << true << false << true // exception
+ << false; // allowthread
+
+ // Activate on class level
+ QTest::newRow("class-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A' exception-handling='auto-on' allow-thread='no'/>
+</typesystem>)XML")
+ << true << false << true // exception
+ << false; // allowthread
+
+ // Activate on base class level
+ QTest::newRow("baseclass-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base' exception-handling='auto-on' allow-thread='no'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << true << false << true // exception
+ << false; // allowthread
+
+ // Override value on class level
+ QTest::newRow("override-class-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A' exception-handling='auto-on'>
+ <modify-function signature='throwing()' exception-handling='no'/>
+ </object-type>
+</typesystem>)XML")
+ << true << false << false // exception
+ << false; // allowthread
+}
+
+void TestModifyFunction::testScopedModifications()
+{
+ QFETCH(QByteArray, cppCode);
+ QFETCH(QByteArray, xmlCode);
+ QFETCH(bool, expectedGenerateUnspecified);
+ QFETCH(bool, expectedGenerateNonThrowing);
+ QFETCH(bool, expectedGenerateThrowing);
+ QFETCH(bool, expectedAllowThread);
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode.constData(), xmlCode.constData(), false));
+ QVERIFY(builder);
+
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ auto f = classA->findFunction("unspecified");
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Unknown);
+ QCOMPARE(f->generateExceptionHandling(), expectedGenerateUnspecified);
+ QCOMPARE(f->allowThread(), expectedAllowThread);
+
+ f = classA->findFunction("nonThrowing");
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::NoExcept);
+ QCOMPARE(f->generateExceptionHandling(), expectedGenerateNonThrowing);
+
+ f = classA->findFunction("throwing");
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Throws);
+ QCOMPARE(f->generateExceptionHandling(), expectedGenerateThrowing);
+}
+
+void TestModifyFunction::testSnakeCaseRenaming_data()
+{
+ QTest::addColumn<QLatin1StringView>("name");
+ QTest::addColumn<QLatin1StringView>("expected");
+ QTest::newRow("s1")
+ << "snakeCaseFunc"_L1 << "snake_case_func"_L1;
+ QTest::newRow("s2")
+ << "SnakeCaseFunc"_L1 << "snake_case_func"_L1;
+ QTest::newRow("consecutive-uppercase")
+ << "snakeCAseFunc"_L1 << "snakeCAseFunc"_L1;
+}
+
+void TestModifyFunction::testSnakeCaseRenaming()
+{
+ QFETCH(QLatin1StringView, name);
+ QFETCH(QLatin1StringView, expected);
+
+ const QString actual = AbstractMetaBuilder::getSnakeCaseName(name);
+ QCOMPARE(actual, expected);
+}
+
+QTEST_APPLESS_MAIN(TestModifyFunction)
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h
new file mode 100644
index 000000000..8a4f5d826
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTABSTRACTMETACLASS_H
+#define TESTABSTRACTMETACLASS_H
+
+#include <QtCore/QObject>
+
+class TestModifyFunction : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testOwnershipTransfer();
+ void testWithApiVersion();
+ void testAllowThread();
+ void testRenameArgument_data();
+ void testRenameArgument();
+ void invalidateAfterUse();
+ void testGlobalFunctionModification();
+ void testScopedModifications_data();
+ void testScopedModifications();
+ void testSnakeCaseRenaming_data();
+ void testSnakeCaseRenaming();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp
new file mode 100644
index 000000000..1cf4c8e0f
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testmultipleinheritance.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestMultipleInheritance::testVirtualClass()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ virtual ~A();\n\
+ virtual void theBug();\n\
+ };\n\
+ struct B {\n\
+ virtual ~B();\n\
+ };\n\
+ struct C : A, B {\n\
+ };\n\
+ struct D : C {\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A' />\n\
+ <object-type name='B' />\n\
+ <object-type name='C' />\n\
+ <object-type name='D' />\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 4);
+
+ const auto classD = AbstractMetaClass::findClass(classes, "D");
+ bool functionFound = false;
+ for (const auto &f : classD->functions()) {
+ if (f->name() == u"theBug") {
+ functionFound = true;
+ break;
+ }
+ }
+ QVERIFY(functionFound);
+
+}
+
+QTEST_APPLESS_MAIN(TestMultipleInheritance)
diff --git a/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h
new file mode 100644
index 000000000..ec9935305
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTMULTIPLEINHERITANCE_H
+#define TESTMULTIPLEINHERITANCE_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestMultipleInheritance : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testVirtualClass();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp b/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp
new file mode 100644
index 000000000..3773e614a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp
@@ -0,0 +1,77 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testnamespace.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <abstractmetaenum.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void NamespaceTest::testNamespaceMembers()
+{
+ const char cppCode[] = "\
+ namespace Namespace\n\
+ {\n\
+ enum Option {\n\
+ OpZero,\n\
+ OpOne\n\
+ };\n\
+ void foo(Option opt);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='Namespace'>\n\
+ <enum-type name='Option' />\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto ns = AbstractMetaClass::findClass(classes, "Namespace");
+ QVERIFY(ns);
+ auto metaEnum = ns->findEnum(u"Option"_s);
+ QVERIFY(metaEnum.has_value());
+ const auto func = ns->findFunction("foo");
+ QVERIFY(func);
+}
+
+void NamespaceTest::testNamespaceInnerClassMembers()
+{
+ const char cppCode[] = "\
+ namespace OuterNamespace\n\
+ {\n\
+ namespace InnerNamespace {\n\
+ struct SomeClass {\n\
+ void method();\n\
+ };\n\
+ };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='OuterNamespace'>\n\
+ <namespace-type name='InnerNamespace'>\n\
+ <value-type name='SomeClass'/>\n\
+ </namespace-type>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto ons = AbstractMetaClass::findClass(classes, "OuterNamespace");
+ QVERIFY(ons);
+ const auto ins = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace");
+ QVERIFY(ins);
+ const auto sc = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace::SomeClass");
+ QVERIFY(sc);
+ const auto meth = sc->findFunction("method");
+ QVERIFY(meth);
+}
+
+QTEST_APPLESS_MAIN(NamespaceTest)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testnamespace.h b/sources/shiboken6/ApiExtractor/tests/testnamespace.h
new file mode 100644
index 000000000..af46bdea3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnamespace.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTNAMESPACE_H
+#define TESTNAMESPACE_H
+
+#include <QtCore/QObject>
+
+// The class is named 'NamespaceTest' to avoid clashes with Qt COIN using
+// '-qtnamespace TestNamespace'.
+class NamespaceTest : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testNamespaceMembers();
+ void testNamespaceInnerClassMembers();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp
new file mode 100644
index 000000000..10ca1a0f6
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp
@@ -0,0 +1,115 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testnestedtypes.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <codesnip.h>
+#include <modifications.h>
+#include <complextypeentry.h>
+#include <primitivetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestNestedTypes::testNestedTypesModifications()
+{
+ const char cppCode[] = "\
+ namespace OuterNamespace {\n\
+ namespace InnerNamespace {\n\
+ struct SomeClass {\n\
+ void method() {}\n\
+ };\n\
+ };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='OuterNamespace'>\n\
+ <namespace-type name='InnerNamespace'>\n\
+ <inject-code class='native'>custom_code1();</inject-code>\n\
+ <add-function signature='method()' return-type='OuterNamespace::InnerNamespace::SomeClass'>\n\
+ <inject-code class='target'>custom_code2();</inject-code>\n\
+ </add-function>\n\
+ <object-type name='SomeClass' target-lang-name='RenamedSomeClass'>\n\
+ <modify-function signature='method()' remove='all'/>\n\
+ </object-type>\n\
+ </namespace-type>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto ons = AbstractMetaClass::findClass(classes, "OuterNamespace");
+ QVERIFY(ons);
+
+ const auto ins = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace");
+ QVERIFY(ins);
+ QCOMPARE(ins->functions().size(), 1);
+ QCOMPARE(ins->typeEntry()->codeSnips().size(), 1);
+ CodeSnip snip = ins->typeEntry()->codeSnips().constFirst();
+ QCOMPARE(snip.code().trimmed(), u"custom_code1();");
+
+ const auto addedFunc = ins->functions().constFirst();
+ QVERIFY(addedFunc->isUserAdded());
+ QCOMPARE(addedFunc->access(), Access::Public);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
+ QCOMPARE(addedFunc->type().minimalSignature(),
+ u"OuterNamespace::InnerNamespace::SomeClass");
+
+ QCOMPARE(addedFunc->modifications().size(), 1);
+ QVERIFY(addedFunc->modifications().constFirst().isCodeInjection());
+ snip = addedFunc->modifications().constFirst().snips().constFirst();
+ QCOMPARE(snip.code().trimmed(), u"custom_code2();");
+
+ const auto sc =
+ AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace::SomeClass");
+ QVERIFY(sc);
+ QCOMPARE(sc->functions().size(), 2); // default constructor and removed method
+ const auto removedFunc = sc->functions().constLast();
+ QVERIFY(removedFunc->isModifiedRemoved());
+}
+
+
+void TestNestedTypes::testDuplicationOfNestedTypes()
+{
+ const char cppCode[] = "\
+ namespace Namespace {\n\
+ class SomeClass {};\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='Namespace'>\n\
+ <value-type name='SomeClass'>\n\
+ <add-function signature='createSomeClass(Namespace::SomeClass)'/>\n\
+ </value-type>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto nspace = AbstractMetaClass::findClass(classes, "Namespace");
+ QVERIFY(nspace);
+ const auto cls1 = AbstractMetaClass::findClass(classes, "SomeClass");
+ QVERIFY(cls1);
+ const auto cls2 = AbstractMetaClass::findClass(classes, "Namespace::SomeClass");
+ QVERIFY(cls2);
+ QCOMPARE(cls1, cls2);
+ QCOMPARE(cls1->name(), u"SomeClass");
+ QCOMPARE(cls1->qualifiedCppName(), u"Namespace::SomeClass");
+
+ auto t1 = TypeDatabase::instance()->findType(u"Namespace::SomeClass"_s);
+ QVERIFY(t1);
+ auto t2 = TypeDatabase::instance()->findType(u"SomeClass"_s);
+ QVERIFY(!t2);
+}
+
+QTEST_APPLESS_MAIN(TestNestedTypes)
diff --git a/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h
new file mode 100644
index 000000000..544ea05ab
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTNESTEDTYPES_H
+#define TESTNESTEDTYPES_H
+
+#include <QtCore/QObject>
+
+class TestNestedTypes : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testNestedTypesModifications();
+ void testDuplicationOfNestedTypes();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp
new file mode 100644
index 000000000..9eef7ec47
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp
@@ -0,0 +1,90 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testnumericaltypedef.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <typesystem.h>
+
+void TestNumericalTypedef::testNumericalTypedef()
+{
+ const char cppCode[] = "\
+ typedef double real;\n\
+ void funcDouble(double);\n\
+ void funcReal(real);\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <primitive-type name='real'/>\n\
+ <function signature='funcDouble(double)'/>\n\
+ <function signature='funcReal(real)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ QCOMPARE(builder->globalFunctions().size(), 2);
+ auto funcDouble = builder->globalFunctions().constFirst();
+ auto funcReal = builder->globalFunctions().constLast();
+ QVERIFY(funcReal);
+
+ if (funcDouble->name() == u"funcReal")
+ std::swap(funcDouble, funcReal);
+
+ QCOMPARE(funcDouble->minimalSignature(), u"funcDouble(double)");
+ QCOMPARE(funcReal->minimalSignature(), u"funcReal(real)");
+
+ const AbstractMetaType doubleType = funcDouble->arguments().constFirst().type();
+ QCOMPARE(doubleType.cppSignature(), u"double");
+ QVERIFY(doubleType.isPrimitive());
+ QVERIFY(isCppPrimitive(doubleType.typeEntry()));
+
+ const AbstractMetaType realType = funcReal->arguments().constFirst().type();
+ QCOMPARE(realType.cppSignature(), u"real");
+ QVERIFY(realType.isPrimitive());
+ QVERIFY(isCppPrimitive(realType.typeEntry()));
+}
+
+void TestNumericalTypedef::testUnsignedNumericalTypedef()
+{
+ const char cppCode[] = "\
+ typedef unsigned short custom_ushort;\n\
+ void funcUnsignedShort(unsigned short);\n\
+ void funcUShort(custom_ushort);\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='short'/>\n\
+ <primitive-type name='unsigned short'/>\n\
+ <primitive-type name='custom_ushort'/>\n\
+ <function signature='funcUnsignedShort(unsigned short)'/>\n\
+ <function signature='funcUShort(custom_ushort)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ QCOMPARE(builder->globalFunctions().size(), 2);
+ auto funcUnsignedShort = builder->globalFunctions().constFirst();
+ auto funcUShort = builder->globalFunctions().constLast();
+
+ if (funcUnsignedShort->name() == u"funcUShort")
+ std::swap(funcUnsignedShort, funcUShort);
+
+ QCOMPARE(funcUnsignedShort->minimalSignature(), u"funcUnsignedShort(unsigned short)");
+ QCOMPARE(funcUShort->minimalSignature(), u"funcUShort(custom_ushort)");
+
+ const AbstractMetaType unsignedShortType = funcUnsignedShort->arguments().constFirst().type();
+ QCOMPARE(unsignedShortType.cppSignature(), u"unsigned short");
+ QVERIFY(unsignedShortType.isPrimitive());
+ QVERIFY(isCppPrimitive(unsignedShortType.typeEntry()));
+
+ const AbstractMetaType ushortType = funcUShort->arguments().constFirst().type();
+ QCOMPARE(ushortType.cppSignature(), u"custom_ushort");
+ QVERIFY(ushortType.isPrimitive());
+ QVERIFY(isCppPrimitive(ushortType.typeEntry()));
+}
+
+QTEST_APPLESS_MAIN(TestNumericalTypedef)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h
new file mode 100644
index 000000000..32f549836
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTNUMERICALTYPEDEF_H
+#define TESTNUMERICALTYPEDEF_H
+
+#include <QtCore/QObject>
+
+class TestNumericalTypedef : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testNumericalTypedef();
+ void testUnsignedNumericalTypedef();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp
new file mode 100644
index 000000000..99cced09d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testprimitivetypetag.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <primitivetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestPrimitiveTypeTag::testPrimitiveTypeDefaultConstructor()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {};\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='A' default-constructor='A()'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+
+ auto typeEntry = TypeDatabase::instance()->findPrimitiveType(u"A"_s);
+ QVERIFY(typeEntry);
+ QVERIFY(typeEntry->hasDefaultConstructor());
+ QCOMPARE(typeEntry->defaultConstructor(), u"A()");
+}
+
+QTEST_APPLESS_MAIN(TestPrimitiveTypeTag)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h
new file mode 100644
index 000000000..3a0e05138
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTPRIMITIVETYPETAG_H
+#define TESTPRIMITIVETYPETAG_H
+
+#include <QtCore/QObject>
+
+class TestPrimitiveTypeTag : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testPrimitiveTypeDefaultConstructor();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp
new file mode 100644
index 000000000..f2e261624
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp
@@ -0,0 +1,84 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testrefcounttag.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <modifications.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestRefCountTag::testReferenceCountTag()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ void keepObject(B* b);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'>\n\
+ <modify-function signature='keepObject(B*)'>\n\
+ <modify-argument index='1'>\n\
+ <reference-count action='add'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto func = classB->findFunction("keepObject");
+ QVERIFY(func);
+ const auto refCount =
+ func->modifications().constFirst().argument_mods().constFirst().referenceCounts().constFirst();
+ QCOMPARE(refCount.action, ReferenceCount::Add);
+}
+
+void TestRefCountTag::testWithApiVersion()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ void keepObject(B*, B*);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'>\n\
+ <modify-function signature='keepObject(B*, B*)'>\n\
+ <modify-argument index='1' since='0.1'>\n\
+ <reference-count action='add'/>\n\
+ </modify-argument>\n\
+ <modify-argument index='2' since='0.2'>\n\
+ <reference-count action='add'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto func = classB->findFunction("keepObject");
+ QVERIFY(func);
+ const auto refCount =
+ func->modifications().constFirst().argument_mods().constFirst().referenceCounts().constFirst();
+ QCOMPARE(refCount.action, ReferenceCount::Add);
+
+ QCOMPARE(func->modifications().size(), 1);
+}
+
+
+QTEST_APPLESS_MAIN(TestRefCountTag)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h
new file mode 100644
index 000000000..6093c6f7b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREFCOUNTTAG_H
+#define TESTREFCOUNTTAG_H
+
+#include <QtCore/QObject>
+
+class TestRefCountTag : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testReferenceCountTag();
+ void testWithApiVersion();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp
new file mode 100644
index 000000000..ae85c5a86
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testreferencetopointer.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <typesystem.h>
+
+void TestReferenceToPointer::testReferenceToPointerArgument()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ void dummy(A*&);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ const auto func = classB->findFunction("dummy");
+ QVERIFY(func);
+ QCOMPARE(func->arguments().constFirst().type().minimalSignature(), u"A*&");
+}
+
+QTEST_APPLESS_MAIN(TestReferenceToPointer)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h
new file mode 100644
index 000000000..2a7b34807
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREFERENCETOPOINTER_H
+#define TESTREFERENCETOPOINTER_H
+
+#include <QtCore/QObject>
+
+class TestReferenceToPointer : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testReferenceToPointerArgument();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp b/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp
new file mode 100644
index 000000000..2cc82071b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp
@@ -0,0 +1,76 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testremovefield.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafield.h>
+#include <abstractmetafunction.h>
+#include <abstractmetatype.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+using namespace Qt::StringLiterals;
+
+void TestRemoveField::testRemoveField()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ int fieldA;\n\
+ int fieldB;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <modify-field name='fieldB' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->fields().size(), 1);
+ const AbstractMetaField &fieldA = classA->fields().constFirst();
+ QCOMPARE(fieldA.name(), u"fieldA");
+}
+
+// Verify that 'static constexpr' fields are seen as static/const and
+// appear fully qualified for function parameter default values.
+void TestRemoveField::testConstExprField()
+{
+ const char cppCode[] = R"(
+struct A {
+ static constexpr int constExprField = 44;
+
+ void f(int iParam=constExprField);
+};
+)";
+
+ const char xmlCode[] = R"(
+<typesystem package="Foo">
+ <value-type name='A'/>
+</typesystem>
+)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto &fields = classA->fields();
+ QCOMPARE(fields.size(), 1);
+ QVERIFY(fields.constFirst().isStatic());
+ QVERIFY(fields.constFirst().type().isConstant());
+ const auto function = classA->findFunction("f"_L1);
+ QVERIFY(function);
+ const auto &arguments = function->arguments();
+ QCOMPARE(arguments.size(), 1);
+ QCOMPARE(arguments.constFirst().defaultValueExpression(), "A::constExprField"_L1);
+}
+
+QTEST_APPLESS_MAIN(TestRemoveField)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testremovefield.h b/sources/shiboken6/ApiExtractor/tests/testremovefield.h
new file mode 100644
index 000000000..05912d99e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremovefield.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREMOVEFIELD_H
+#define TESTREMOVEFIELD_H
+
+#include <QtCore/QObject>
+
+class TestRemoveField : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testRemoveField();
+ void testConstExprField();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp
new file mode 100644
index 000000000..87e318e95
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testremoveimplconv.h"
+#include "testutil.h"
+#include <QtTest/QTest>
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+
+// When a constructor able to trigger implicity conversions is removed
+// it should not appear in the implicity conversion list.
+void TestRemoveImplConv::testRemoveImplConv()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {};\n\
+ struct C {\n\
+ C(const A&);\n\
+ C(const B&);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='C'>\n\
+ <modify-function signature='C(const A&amp;)' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(classC);
+ const auto implConv = classC->implicitConversions();
+ QCOMPARE(implConv.size(), 1);
+ QCOMPARE(implConv.constFirst()->arguments().constFirst().type().typeEntry(),
+ classB->typeEntry());
+}
+
+QTEST_APPLESS_MAIN(TestRemoveImplConv)
diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h
new file mode 100644
index 000000000..d11d30633
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREMOVEIMPLCONV_H
+#define TESTREMOVEIMPLCONV_H
+
+#include <QtCore/QObject>
+
+class TestRemoveImplConv : public QObject
+{
+Q_OBJECT
+private slots:
+ void testRemoveImplConv();
+};
+
+#endif // TESTREMOVEIMPLCONV_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp
new file mode 100644
index 000000000..17a069b5e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp
@@ -0,0 +1,98 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testremoveoperatormethod.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestRemoveOperatorMethod::testRemoveOperatorMethod()
+{
+ const char cppCode[] = R"(#include <cstdint>
+
+struct Char {};
+struct ByteArray {};
+struct String {};
+
+struct A {
+ A& operator>>(char&);
+ A& operator>>(char*);
+ A& operator>>(short&);
+ A& operator>>(unsigned short&);
+ A& operator>>(int&);
+ A& operator>>(unsigned int&);
+ A& operator>>(int64_t&);
+ A& operator>>(uint64_t&);
+ A& operator>>(float&);
+ A& operator>>(double&);
+ A& operator>>(Char&);
+ A& operator>>(ByteArray&);
+ A& operator>>(String&);
+};
+)";
+
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='char'/>\n\
+ <primitive-type name='short'/>\n\
+ <primitive-type name='unsigned short'/>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='unsigned int'/>\n\
+ <primitive-type name='int64_t'/>\n\
+ <primitive-type name='uint64_t'/>\n\
+ <primitive-type name='float'/>\n\
+ <primitive-type name='double'/>\n\
+ <primitive-type name='Char'/>\n\
+ <primitive-type name='String'/>\n\
+ <value-type name='ByteArray'/>\n\
+ <object-type name='A'>\n\
+ <modify-function signature='operator&gt;&gt;(char&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(char*)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(short&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(unsigned short&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(int&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(unsigned int&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(int64_t&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(uint64_t&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(float&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(double&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(Char&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(String&amp;)' remove='all'/>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 14);
+ QStringList removedSignatures;
+ removedSignatures.append(u"operator>>(char&)"_s);
+ removedSignatures.append(u"operator>>(char*)"_s);
+ removedSignatures.append(u"operator>>(short&)"_s);
+ removedSignatures.append(u"operator>>(unsigned short&)"_s);
+ removedSignatures.append(u"operator>>(int&)"_s);
+ removedSignatures.append(u"operator>>(unsigned int&)"_s);
+ removedSignatures.append(u"operator>>(int64_t&)"_s);
+ removedSignatures.append(u"operator>>(uint64_t&)"_s);
+ removedSignatures.append(u"operator>>(float&)"_s);
+ removedSignatures.append(u"operator>>(double&)"_s);
+ removedSignatures.append(u"operator>>(Char&)"_s);
+ removedSignatures.append(u"operator>>(String&)"_s);
+ auto notRemoved = classA->functions().size();
+ for (const auto &f : classA->functions()) {
+ QCOMPARE(f->isModifiedRemoved(), bool(removedSignatures.contains(f->minimalSignature())));
+ notRemoved -= int(f->isModifiedRemoved());
+ }
+ QCOMPARE(notRemoved, 2);
+}
+
+QTEST_APPLESS_MAIN(TestRemoveOperatorMethod)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h
new file mode 100644
index 000000000..6ec335e0c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREMOVEOPERATORMETHOD_H
+#define TESTREMOVEOPERATORMETHOD_H
+
+#include <QtCore/QObject>
+
+class TestRemoveOperatorMethod : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testRemoveOperatorMethod();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp b/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp
new file mode 100644
index 000000000..67ebcc606
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp
@@ -0,0 +1,281 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testresolvetype.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetaenum.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+#include <enumtypeentry.h>
+#include <primitivetypeentry.h>
+#include <typedatabase.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestResolveType::initTestCase()
+{
+ // For enum lookup in testFixDefaultArguments()
+ AbstractMetaBuilder::setCodeModelTestMode(true);
+}
+
+void TestResolveType::testResolveReturnTypeFromParentScope()
+{
+ const char cppCode[] = "\n\
+ namespace A {\n\
+ struct B {\n\
+ struct C {};\n\
+ };\n\
+ struct D : public B::C {\n\
+ C* foo = 0;\n\
+ C* method();\n\
+ };\n\
+ };";
+ const char xmlCode[] = R"XML(
+ <typesystem package='Foo'>
+ <namespace-type name='A'>
+ <value-type name='B'>
+ <value-type name='C'/>
+ </value-type>
+ <value-type name='D'/>
+ </namespace-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classD = AbstractMetaClass::findClass(classes, "A::D");
+ QVERIFY(classD);
+ const auto meth = classD->findFunction("method");
+ QVERIFY(meth);
+ QVERIFY(meth);
+}
+
+// Helper classes and functions for testing default value fixing.
+// Put the AbstractMetaBuilder into test fixture struct to avoid having
+// to re-parse for each data row.
+
+struct DefaultValuesFixture
+{
+ std::shared_ptr<AbstractMetaBuilder> builder;
+
+ AbstractMetaType intType;
+ AbstractMetaType stringType;
+ AbstractMetaType classType;
+ AbstractMetaType listType;
+ AbstractMetaType enumType;
+ AbstractMetaClassCPtr klass{};
+};
+
+Q_DECLARE_METATYPE(DefaultValuesFixture)
+Q_DECLARE_METATYPE(AbstractMetaType)
+
+static int populateDefaultValuesFixture(DefaultValuesFixture *fixture)
+{
+ static const char cppCode[] =R"(
+#include <string>
+#include <list>
+
+namespace Namespace {
+class Test
+{
+public:
+ enum Enum { enumValue1, enumValue2 };
+
+ explicit Test(int x = INT_FIELD_1);
+ explicit Test(const std::string &t = std::string(CHAR_FIELD_1));
+
+ static void listFunc(std::list<Test> list = std::list<Test>());
+
+ static const int INT_FIELD_1 = 42;
+ static const char *CHAR_FIELD_1;
+ static const Enum DefaultValue = enumValue1;
+};
+} // Namespace
+)";
+ static const char xmlCode[] = R"(
+<typesystem package="Foo">
+ <namespace-type name='Namespace'>
+ <value-type name='Test'>
+ <enum-type name='Enum'/>
+ </value-type>
+ </namespace-type>
+ <container-type name="std::list" type="list"/>
+</typesystem>
+)";
+
+ fixture->builder.reset(TestUtil::parse(cppCode, xmlCode, false));
+ if (!fixture->builder)
+ return -1;
+
+ for (const auto &klass : fixture->builder->classes()) {
+ if (klass->name() == u"Test") {
+ fixture->klass = klass;
+ break;
+ }
+ }
+ if (!fixture->klass)
+ return -2;
+
+ fixture->classType = AbstractMetaType(fixture->klass->typeEntry());
+ fixture->classType.decideUsagePattern();
+
+ for (const auto &f : fixture->klass->findFunctions("Test")) {
+ if (f->functionType() == AbstractMetaFunction::ConstructorFunction
+ && f->arguments().size() == 1) {
+ const auto type = f->arguments().constFirst().type();
+ if (type.name() == u"int")
+ fixture->intType = type;
+ else
+ fixture->stringType = type;
+ }
+ }
+ if (fixture->intType.isVoid() || fixture->stringType.isVoid())
+ return -3;
+
+ auto listFunc = fixture->klass->findFunction("listFunc");
+ if (!listFunc || listFunc->arguments().size() != 1)
+ return -3;
+ fixture->listType = listFunc->arguments().constFirst().type();
+
+ fixture->enumType = AbstractMetaType(fixture->klass->enums().constFirst().typeEntry());
+ fixture->enumType.decideUsagePattern();
+
+ return 0;
+}
+
+void TestResolveType::testFixDefaultArguments_data()
+{
+ DefaultValuesFixture fixture;
+ const int setupOk = populateDefaultValuesFixture(&fixture);
+
+ QTest::addColumn<DefaultValuesFixture>("fixture");
+ QTest::addColumn<int>("setupOk"); // To verify setup
+ QTest::addColumn<AbstractMetaType>("metaType"); // Type and parameters for fixup
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("int") << fixture << setupOk
+ << fixture.intType << "1" << "1";
+ QTest::newRow("int-macro") << fixture << setupOk
+ << fixture.intType << "GL_MACRO" << "GL_MACRO";
+ QTest::newRow("int-enum") << fixture << setupOk
+ << fixture.intType << "enumValue1" << "Namespace::Test::Enum::enumValue1";
+
+ // Test expansion of container types
+ QString expected = u"std::list<Namespace::Test>()"_s;
+ QTest::newRow("list")
+ << fixture << setupOk << fixture.listType
+ << expected << expected;
+ QTest::newRow("partially qualified list")
+ << fixture << setupOk << fixture.listType
+ << "std::list<Test>()" << expected;
+
+ // Test field expansion
+ expected = u"Namespace::Test::INT_FIELD_1"_s;
+ QTest::newRow("qualified class field")
+ << fixture << setupOk << fixture.intType
+ << expected << expected;
+ QTest::newRow("partially qualified class field")
+ << fixture << setupOk << fixture.intType
+ << "Test::INT_FIELD_1" << expected;
+ QTest::newRow("unqualified class field")
+ << fixture << setupOk << fixture.intType
+ << "INT_FIELD_1" << expected;
+
+ // Test field expansion when constructing some class
+ expected = u"QLatin1String(Namespace::Test::CHAR_FIELD_1)"_s;
+ QTest::newRow("class from qualified class field")
+ << fixture << setupOk << fixture.classType
+ << expected << expected;
+ QTest::newRow("class from partially qualified class field")
+ << fixture << setupOk << fixture.classType
+ << "QLatin1String(Test::CHAR_FIELD_1)" << expected;
+ QTest::newRow("class from unqualified class field")
+ << fixture << setupOk << fixture.classType
+ << "QLatin1String(CHAR_FIELD_1)" << expected;
+
+ // Test field expansion when constructing class itself
+ expected = u"Namespace::Test(Namespace::Test::CHAR_FIELD_1)"_s;
+ QTest::newRow("self from qualified class field")
+ << fixture << setupOk << fixture.classType
+ << expected << expected;
+ QTest::newRow("self from partially qualified class field")
+ << fixture << setupOk << fixture.classType
+ << "Test(Test::CHAR_FIELD_1)" << expected;
+ QTest::newRow("self from unqualified class field")
+ << fixture << setupOk << fixture.classType
+ << "Test(CHAR_FIELD_1)" << expected;
+
+ // Test enum expansion when constructing class itself
+ expected = u"Namespace::Test(Namespace::Test::Enum::enumValue1)"_s;
+ QTest::newRow("self from qualified enum")
+ << fixture << setupOk << fixture.classType
+ << expected << expected;
+ QTest::newRow("self from enum")
+ << fixture << setupOk << fixture.classType
+ << "Test(enumValue1)" << expected;
+
+ // Don't qualify fields to "Test::Enum::DefaultValue"
+ QTest::newRow("enum from static field")
+ << fixture << setupOk << fixture.enumType
+ << "DefaultValue" << u"Namespace::Test::DefaultValue"_s;
+}
+
+void TestResolveType::testFixDefaultArguments()
+{
+ QFETCH(DefaultValuesFixture, fixture);
+ QFETCH(int, setupOk);
+ QFETCH(AbstractMetaType, metaType);
+ QFETCH(QString, input);
+ QFETCH(QString, expected);
+ QCOMPARE(setupOk, 0);
+ const QString actual = fixture.builder->fixDefaultValue(input, metaType, fixture.klass);
+ QCOMPARE(actual, expected);
+}
+
+// Verify that the typedefs of the C++ 11 integer types (int32_t, ...)
+// are seen by the C++ parser, otherwise they are handled as unknown
+// primitive types, causing invalid code to be generated.
+// (see BuilderPrivate::visitHeader(),
+// sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp).
+void TestResolveType::testCppTypes()
+{
+ static const char cppCode[] =R"(
+#include <cstdint>
+
+class Test
+{
+public:
+ explicit Test(int32_t v);
+};
+)";
+ static const char xmlCode[] = R"(
+<typesystem package="Foo">
+ <value-type name='Test'/>
+ <primitive-type name='int32_t'/>
+</typesystem>
+)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto testClass = AbstractMetaClass::findClass(classes, "Test");
+ QVERIFY(testClass);
+
+ auto *tdb = TypeDatabase::instance();
+ auto int32TEntry = tdb->findType(u"int32_t"_s);
+ QVERIFY2(int32TEntry, "int32_t not found");
+ QVERIFY(int32TEntry->isPrimitive());
+ auto int32T = std::static_pointer_cast<const PrimitiveTypeEntry>(int32TEntry);
+ auto basicType = basicReferencedTypeEntry(int32T);
+ QVERIFY2(basicType != int32T,
+ "Typedef for int32_t not found. Check the system include paths.");
+}
+
+QTEST_APPLESS_MAIN(TestResolveType)
diff --git a/sources/shiboken6/ApiExtractor/tests/testresolvetype.h b/sources/shiboken6/ApiExtractor/tests/testresolvetype.h
new file mode 100644
index 000000000..a07855eab
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testresolvetype.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTRESOLVETYPE_H
+#define TESTRESOLVETYPE_H
+
+#include <QtCore/QObject>
+
+class TestResolveType : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void initTestCase();
+
+ void testResolveReturnTypeFromParentScope();
+ void testFixDefaultArguments_data();
+ void testFixDefaultArguments();
+ void testCppTypes();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp
new file mode 100644
index 000000000..f4eecff2c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp
@@ -0,0 +1,129 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testreverseoperators.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+#include <clangparser/compilersupport.h>
+
+#include <algorithm>
+
+void TestReverseOperators::testReverseSum()
+{
+ const char cppCode[] = "struct A {\n\
+ A& operator+(int);\n\
+ };\n\
+ A& operator+(int, const A&);";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int' />\n\
+ <value-type name='A' />\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 4);
+
+ AbstractMetaFunctionCPtr reverseOp;
+ AbstractMetaFunctionCPtr normalOp;
+ for (const auto &func : classA->functions()) {
+ if (func->name() == u"operator+") {
+ if (func->isReverseOperator())
+ reverseOp = func;
+ else
+ normalOp = func;
+ }
+ }
+
+ QVERIFY(normalOp);
+ QVERIFY(!normalOp->isReverseOperator());
+ QCOMPARE(normalOp->arguments().size(), 1);
+ QVERIFY(reverseOp);
+ QVERIFY(reverseOp->isReverseOperator());
+ QCOMPARE(reverseOp->arguments().size(), 1);
+}
+
+void TestReverseOperators::testReverseSumWithAmbiguity()
+{
+ const char cppCode[] = "\n\
+ struct A { A operator+(int); };\n\
+ A operator+(int, const A&);\n\
+ struct B {};\n\
+ B operator+(const A&, const B&);\n\
+ B operator+(const B&, const A&);\n\
+ ";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int' />\n\
+ <value-type name='A' />\n\
+ <value-type name='B' />\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 4);
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QCOMPARE(classB->functions().size(), 4);
+
+ AbstractMetaFunctionCPtr reverseOp;
+ AbstractMetaFunctionCPtr normalOp;
+ for (const auto &func : classB->functions()) {
+ if (func->name() == u"operator+") {
+ if (func->isReverseOperator())
+ reverseOp = func;
+ else
+ normalOp = func;
+ }
+ }
+ QVERIFY(normalOp);
+ QVERIFY(!normalOp->isReverseOperator());
+ QCOMPARE(normalOp->arguments().size(), 1);
+ QCOMPARE(normalOp->minimalSignature(), u"operator+(B,A)");
+ QVERIFY(reverseOp);
+ QVERIFY(reverseOp->isReverseOperator());
+ QCOMPARE(reverseOp->arguments().size(), 1);
+ QCOMPARE(reverseOp->minimalSignature(), u"operator+(A,B)");
+}
+
+void TestReverseOperators::testSpaceshipOperator()
+{
+ const char cppCode[] = R"(
+ class Test {
+ public:
+ explicit Test(int v);
+ int operator<=>(const Test &rhs) const = default;
+ };)";
+ const char xmlCode[] = R"(
+ <typesystem package="Foo">
+ <value-type name='Test'/>
+ </typesystem>)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false,
+ {}, {}, LanguageLevel::Cpp20));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto testClass = AbstractMetaClass::findClass(classes, "Test");
+ QVERIFY(testClass);
+ const auto &functions = testClass->functions();
+ // 6 operators should be synthesized
+ const auto count = std::count_if(functions.cbegin(), functions.cend(),
+ [](const AbstractMetaFunctionCPtr &f) {
+ return f->isComparisonOperator();
+ });
+ QCOMPARE(count, 6);
+}
+
+QTEST_APPLESS_MAIN(TestReverseOperators)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h
new file mode 100644
index 000000000..fb8d97c97
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREVERSEOPERATORS_H
+#define TESTREVERSEOPERATORS_H
+#include <QtCore/QObject>
+
+class TestReverseOperators : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testReverseSum();
+ void testReverseSumWithAmbiguity();
+ void testSpaceshipOperator();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp
new file mode 100644
index 000000000..ea37c6255
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp
@@ -0,0 +1,628 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testtemplates.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafield.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+#include <containertypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QTextStream>
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestTemplates::testTemplateWithNamespace()
+{
+ const char cppCode[] = R"CPP(
+template<typename T> struct QList {};
+struct Url {
+ void name();
+};
+namespace Internet {
+ struct Url{};
+ struct Bookmarks {
+ QList<Url> list();
+ };
+};
+)CPP";
+
+ const char xmlCode0[] = R"XML(
+<typesystem package='Package.Network'>
+ <value-type name='Url'/>
+</typesystem>)XML";
+
+ QTemporaryFile file;
+ QVERIFY(file.open());
+ file.write(xmlCode0);
+ file.close();
+
+ QString xmlCode1 = QString::fromLatin1(R"XML(
+<typesystem package='Package.Internet'>
+ <load-typesystem name='%1' generate='no'/>
+ <container-type name='QList' type='list'/>
+ <namespace-type name='Internet' generate='no'>
+ <value-type name='Url'/>
+ <value-type name='Bookmarks'/>
+ </namespace-type>
+</typesystem>)XML").arg(file.fileName());
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classB = AbstractMetaClass::findClass(classes, "Bookmarks");
+ QVERIFY(classB);
+ const auto func = classB->findFunction("list");
+ QVERIFY(func);
+ AbstractMetaType funcType = func->type();
+ QVERIFY(!funcType.isVoid());
+ QCOMPARE(funcType.cppSignature(), u"QList<Internet::Url>");
+}
+
+void TestTemplates::testTemplateOnContainers()
+{
+ const char cppCode[] = R"CPP(
+struct Base {};
+template<typename T> struct QList {};
+namespace Namespace {
+ enum SomeEnum { E1, E2 };
+ template<SomeEnum type> struct A {
+ A<type> foo(const QList<A<type> >& a);
+ };
+ typedef A<E1> B;
+}
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package="Package">
+ <container-type name='QList' type='list'/>
+ <namespace-type name='Namespace'>
+ <enum-type name='SomeEnum'/>
+ <object-type name='A' generate='no'/>
+ <object-type name='B'/>
+ </namespace-type>
+ <object-type name='Base'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QVERIFY(!classB->baseClass());
+ QVERIFY(classB->baseClassName().isEmpty());
+ const auto func = classB->findFunction("foo");
+ QVERIFY(func);
+ AbstractMetaType argType = func->arguments().constFirst().type();
+ QCOMPARE(argType.instantiations().size(), 1);
+ QCOMPARE(argType.typeEntry()->qualifiedCppName(), u"QList");
+
+ const AbstractMetaType &instance1 = argType.instantiations().constFirst();
+ QCOMPARE(instance1.instantiations().size(), 1);
+ QCOMPARE(instance1.typeEntry()->qualifiedCppName(), u"Namespace::A");
+
+ const AbstractMetaType &instance2 = instance1.instantiations().constFirst();
+ QCOMPARE(instance2.instantiations().size(), 0);
+ QCOMPARE(instance2.typeEntry()->qualifiedCppName(), u"Namespace::E1");
+}
+
+void TestTemplates::testTemplateValueAsArgument()
+{
+ const char cppCode[] = R"CPP(
+template<typename T> struct List {};
+void func(List<int> arg) {}
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <primitive-type name='int'/>
+ <container-type name='List' type='list'/>
+ <function signature='func(List&lt;int&gt;)'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ const auto globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 1);
+
+ const auto func = globalFuncs.constFirst();
+ QCOMPARE(func->minimalSignature(), u"func(List<int>)");
+ QCOMPARE(func->arguments().constFirst().type().cppSignature(),
+ u"List<int>");
+}
+
+void TestTemplates::testTemplatePointerAsArgument()
+{
+ const char cppCode[] = R"CPP(
+template<typename T> struct List {};
+void func(List<int>* arg) {}
+)CPP";
+
+ const char xmlCode[] = R"XML(
+ <typesystem package='Package'>
+ <primitive-type name='int'/>
+ <container-type name='List' type='list'/>
+ <function signature='func(List&lt;int&gt;*)'/>
+ </typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaFunctionCList globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 1);
+
+ const auto func = globalFuncs.constFirst();
+ QCOMPARE(func->minimalSignature(), u"func(List<int>*)");
+ QCOMPARE(func->arguments().constFirst().type().cppSignature(),
+ u"List<int> *");
+}
+
+void TestTemplates::testTemplateReferenceAsArgument()
+{
+ const char cppCode[] = R"CPP(
+template<typename T> struct List {};
+void func(List<int>& arg) {}
+ )CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <primitive-type name='int'/>
+ <container-type name='List' type='list'/>
+ <function signature='func(List&lt;int&gt;&amp;)'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ const auto globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 1);
+
+ const auto func = globalFuncs.constFirst();
+ QCOMPARE(func->minimalSignature(), u"func(List<int>&)");
+ QCOMPARE(func->arguments().constFirst().type().cppSignature(),
+ u"List<int> &");
+}
+
+void TestTemplates::testTemplateParameterFixup()
+{
+ const char cppCode[] = R"CPP(
+template<typename T>
+struct List {
+ struct Iterator {};
+ void append(List l);
+ void erase(List::Iterator it);
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+ <typesystem package='Package'>
+ <container-type name='List' type='list'>
+ <value-type name='Iterator'/>
+ </container-type>
+ </typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ const AbstractMetaClassList templates = builder->templates();
+
+ QCOMPARE(templates.size(), 1);
+ AbstractMetaClassCPtr list = templates.constFirst();
+ // Verify that the parameter of "void append(List l)" gets fixed to "List<T>"
+ const auto append = list->findFunction("append");
+ QVERIFY(append);
+ QCOMPARE(append->arguments().size(), 1);
+ QCOMPARE(append->arguments().at(0).type().cppSignature(), u"List<T>");
+ // Verify that the parameter of "void erase(Iterator)" is not modified
+ const auto erase = list->findFunction("erase");
+ QVERIFY(erase);
+ QCOMPARE(erase->arguments().size(), 1);
+ QCOMPARE(erase->arguments().at(0).type().cppSignature(), u"List::Iterator");
+}
+
+void TestTemplates::testInheritanceFromContainterTemplate()
+{
+ const char cppCode[] = R"CPP(
+template<typename T>
+struct ListContainer {
+ inline void push_front(const T& t);
+ inline T& front();
+};
+struct FooBar {};
+struct FooBars : public ListContainer<FooBar> {};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <container-type name='ListContainer' type='list'/>
+ <value-type name='FooBar'/>
+ <value-type name='FooBars'>
+ <modify-function signature='push_front(FooBar)' remove='all'/>
+ <modify-function signature='front()' remove='all'/>
+ </value-type>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ AbstractMetaClassList templates = builder->templates();
+ QCOMPARE(classes.size(), 2);
+ QCOMPARE(templates.size(), 1);
+
+ const auto foobars = AbstractMetaClass::findClass(classes, "FooBars");
+ QCOMPARE(foobars->functions().size(), 4);
+
+ AbstractMetaClassCPtr lc = templates.constFirst();
+ QCOMPARE(lc->functions().size(), 2);
+}
+
+void TestTemplates::testTemplateInheritanceMixedWithForwardDeclaration()
+{
+ const char cppCode[] = R"CPP(
+enum SomeEnum { E1, E2 };
+template<SomeEnum type> struct Future;
+template<SomeEnum type>
+struct A {
+ A();
+ void method();
+ friend struct Future<type>;
+};
+typedef A<E1> B;
+template<SomeEnum type> struct Future {};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <enum-type name='SomeEnum'/>
+ <value-type name='A' generate='no'/>
+ <value-type name='B'/>
+ <value-type name='Future' generate='no'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QVERIFY(!classB->baseClass());
+ QVERIFY(classB->baseClassName().isEmpty());
+ // 3 functions: simple constructor, copy constructor and "method()".
+ QCOMPARE(classB->functions().size(), 3);
+}
+
+void TestTemplates::testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration()
+{
+ const char cppCode[] = R"CPP(
+namespace Namespace {
+enum SomeEnum { E1, E2 };
+template<SomeEnum type> struct Future;
+template<SomeEnum type>
+struct A {
+ A();
+ void method();
+ friend struct Future<type>;
+};
+typedef A<E1> B;
+template<SomeEnum type> struct Future {};
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <namespace-type name='Namespace'>
+ <enum-type name='SomeEnum'/>
+ <value-type name='A' generate='no'/>
+ <value-type name='B'/>
+ <value-type name='Future' generate='no'/>
+ </namespace-type>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classB = AbstractMetaClass::findClass(classes, "Namespace::B");
+ QVERIFY(classB);
+ QVERIFY(!classB->baseClass());
+ QVERIFY(classB->baseClassName().isEmpty());
+ // 3 functions: simple constructor, copy constructor and "method()".
+ QCOMPARE(classB->functions().size(), 3);
+}
+
+void TestTemplates::testTypedefOfInstantiationOfTemplateClass()
+{
+ const char cppCode[] = R"CPP(
+namespace NSpace {
+enum ClassType {
+ TypeOne
+};
+template<ClassType CLASS_TYPE>
+struct BaseTemplateClass {
+ inline ClassType getClassType() const { return CLASS_TYPE; }
+};
+typedef BaseTemplateClass<TypeOne> TypeOneClass;
+}
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <namespace-type name='NSpace'>
+ <enum-type name='ClassType'/>
+ <object-type name='BaseTemplateClass' generate='no'/>
+ <object-type name='TypeOneClass'/>
+ </namespace-type>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+
+ const auto base = AbstractMetaClass::findClass(classes, "BaseTemplateClass");
+ QVERIFY(base);
+ const auto one = AbstractMetaClass::findClass(classes, "TypeOneClass");
+ QVERIFY(one);
+ QCOMPARE(one->templateBaseClass(), base);
+ QCOMPARE(one->functions().size(), base->functions().size());
+ QVERIFY(one->isTypeDef());
+ auto oneType = one->typeEntry();
+ auto baseType = base->typeEntry();
+ QCOMPARE(oneType->baseContainerType(), baseType);
+ QCOMPARE(one->baseClassNames(), QStringList(u"NSpace::BaseTemplateClass<NSpace::TypeOne>"_s));
+
+ QVERIFY(one->hasTemplateBaseClassInstantiations());
+ AbstractMetaTypeList instantiations = one->templateBaseClassInstantiations();
+ QCOMPARE(instantiations.size(), 1);
+ const AbstractMetaType &inst = instantiations.constFirst();
+ QVERIFY(!inst.isEnum());
+ QVERIFY(!inst.typeEntry()->isEnum());
+ QVERIFY(inst.typeEntry()->isEnumValue());
+ QCOMPARE(inst.cppSignature(), u"NSpace::TypeOne");
+}
+
+void TestTemplates::testContainerTypeIncompleteArgument()
+{
+ const char cppCode[] = R"CPP(
+template<typename T>
+class Vector {
+ void method(const Vector& vector);
+ Vector otherMethod();
+};
+template <typename T>
+void Vector<T>::method(const Vector<T>& vector) {}
+template <typename T>
+Vector<T> Vector<T>::otherMethod() { return Vector<T>(); }
+typedef Vector<int> IntVector;
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <container-type name='Vector' type='vector'/>
+ <value-type name='IntVector'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+
+ const auto vector = AbstractMetaClass::findClass(classes, "IntVector");
+ QVERIFY(vector);
+ auto baseContainer = vector->typeEntry()->baseContainerType();
+ QVERIFY(baseContainer);
+ QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(baseContainer.get())->containerKind(),
+ ContainerTypeEntry::ListContainer);
+ QCOMPARE(vector->functions().size(), 4);
+
+ const auto method = vector->findFunction("method");
+ QVERIFY(method);
+ QCOMPARE(method->signature(), u"method(const Vector<int> & vector)");
+
+ const auto otherMethod = vector->findFunction("otherMethod");
+ QVERIFY(otherMethod);
+ QCOMPARE(otherMethod->signature(), u"otherMethod()");
+ QVERIFY(!otherMethod->type().isVoid());
+ QCOMPARE(otherMethod->type().cppSignature(), u"Vector<int>");
+}
+
+void TestTemplates::testNonTypeTemplates()
+{
+ // PYSIDe-1296, functions with non type templates parameters.
+ const char cppCode[] = R"CPP(
+template <class T, int Size>
+class Array {
+ T array[Size];
+};
+
+Array<int, 2> foo();
+
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <container-type name='Array' type='vector'/>
+ <function signature="foo()"/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+ auto functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 1);
+ auto foo = functions.constFirst();
+ QCOMPARE(foo->name(), u"foo");
+ QCOMPARE(foo->type().name(), u"Array");
+}
+
+// Perform checks on template inheritance; a typedef of a template class
+// should result in rewritten types.
+void TestTemplates::testTemplateTypeDefs_data()
+{
+ QTest::addColumn<QString>("cpp");
+ QTest::addColumn<QString>("xml");
+
+ const char optionalClassDef[] = R"CPP(
+template<class T> // Some value type similar to std::optional
+class Optional {
+public:
+ T value() const { return m_value; }
+ operator bool() const { return m_success; }
+
+ T m_value;
+ bool m_success = false;
+};
+)CPP";
+
+ const char xmlPrefix[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <primitive-type name='bool'/>
+)XML";
+
+ const char xmlOptionalDecl[] = "<value-type name='Optional' generate='no'/>\n";
+ const char xmlOptionalIntDecl[] = "<value-type name='IntOptional'/>\n";
+ const char xmlPostFix[] = "</typesystem>\n";
+
+ // Flat, global namespace
+ QString cpp;
+ QTextStream(&cpp) << optionalClassDef
+ << "typedef Optional<int> IntOptional;\n";
+ QString xml;
+ QTextStream(&xml) << xmlPrefix << xmlOptionalDecl << xmlOptionalIntDecl
+ << "<typedef-type name='XmlIntOptional' source='Optional&lt;int&gt;'/>"
+ << xmlPostFix;
+ QTest::newRow("global-namespace")
+ << cpp << xml;
+
+ // Typedef from namespace Std
+ cpp.clear();
+ QTextStream(&cpp) << "namespace Std {\n" << optionalClassDef << "}\n"
+ << "typedef Std::Optional<int> IntOptional;\n";
+ xml.clear();
+ QTextStream(&xml) << xmlPrefix
+ << "<namespace-type name='Std'>\n" << xmlOptionalDecl
+ << "</namespace-type>\n" << xmlOptionalIntDecl
+ << "<typedef-type name='XmlIntOptional' source='Std::Optional&lt;int&gt;'/>"
+ << xmlPostFix;
+ QTest::newRow("namespace-Std")
+ << cpp << xml;
+
+ // Typedef from nested class
+ cpp.clear();
+ QTextStream(&cpp) << "class Outer {\npublic:\n" << optionalClassDef << "\n};\n"
+ << "typedef Outer::Optional<int> IntOptional;\n";
+ xml.clear();
+ QTextStream(&xml) << xmlPrefix
+ << "<object-type name='Outer'>\n" << xmlOptionalDecl
+ << "</object-type>\n" << xmlOptionalIntDecl
+ << "<typedef-type name='XmlIntOptional' source='Outer::Optional&lt;int&gt;'/>"
+ << xmlPostFix;
+ QTest::newRow("nested-class")
+ << cpp << xml;
+}
+
+void TestTemplates::testTemplateTypeDefs()
+{
+ QFETCH(QString, cpp);
+ QFETCH(QString, xml);
+
+ const QByteArray cppBa = cpp.toLocal8Bit();
+ const QByteArray xmlBa = xml.toLocal8Bit();
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppBa.constData(), xmlBa.constData(), true));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto optional = AbstractMetaClass::findClass(classes, "Optional");
+ QVERIFY(optional);
+
+ // Find the typedef'ed class
+ const auto optionalInt = AbstractMetaClass::findClass(classes, "IntOptional");
+ QVERIFY(optionalInt);
+ QCOMPARE(optionalInt->templateBaseClass(), optional);
+
+ // Find the class typedef'ed in the typesystem XML
+ const auto xmlOptionalInt = AbstractMetaClass::findClass(classes, "XmlIntOptional");
+ QVERIFY(xmlOptionalInt);
+ QCOMPARE(xmlOptionalInt->templateBaseClass(), optional);
+
+ // Check whether the value() method now has an 'int' return
+ const auto valueMethod = optionalInt->findFunction("value");
+ QVERIFY(valueMethod);
+ QCOMPARE(valueMethod->type().cppSignature(), u"int");
+
+ // ditto for typesystem XML
+ const auto xmlValueMethod = xmlOptionalInt->findFunction("value");
+ QVERIFY(xmlValueMethod);
+ QCOMPARE(xmlValueMethod->type().cppSignature(), u"int");
+
+ // Check whether the m_value field is of type 'int'
+ const auto valueField = optionalInt->findField(u"m_value");
+ QVERIFY(valueField.has_value());
+ QCOMPARE(valueField->type().cppSignature(), u"int");
+
+ // ditto for typesystem XML
+ const auto xmlValueField =
+ xmlOptionalInt->findField(u"m_value");
+ QVERIFY(xmlValueField.has_value());
+ QCOMPARE(xmlValueField->type().cppSignature(), u"int");
+}
+
+void TestTemplates::testTemplateTypeAliases()
+{
+ // Model Qt 6's "template<typename T> using QList = QVector<T>"
+ const char cppCode[] = R"CPP(
+template<typename T>
+class Container1 { };
+
+template<typename T>
+using Container2 = Container1<T>;
+
+class Test
+{
+public:
+ Container2<int> m_intContainer;
+};
+
+class Derived : public Container2<int>
+{
+public:
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <value-type name='Container1'/>
+ <value-type name='Derived'/>
+ <object-type name='Test'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ const auto testClass = AbstractMetaClass::findClass(classes, "Test");
+ QVERIFY(testClass);
+
+ auto fields = testClass->fields();
+ QCOMPARE(fields.size(), 1);
+ auto fieldType = testClass->fields().at(0).type();
+ QCOMPARE(fieldType.name(), u"Container1");
+ QCOMPARE(fieldType.instantiations().size(), 1);
+
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QVERIFY(derived);
+ auto base = derived->templateBaseClass();
+ QVERIFY(base);
+ QCOMPARE(base->name(), u"Container1");
+}
+
+QTEST_APPLESS_MAIN(TestTemplates)
diff --git a/sources/shiboken6/ApiExtractor/tests/testtemplates.h b/sources/shiboken6/ApiExtractor/tests/testtemplates.h
new file mode 100644
index 000000000..36800f723
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtemplates.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTTEMPLATES_H
+#define TESTTEMPLATES_H
+
+#include <QtCore/QObject>
+
+class TestTemplates : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testTemplateOnContainers();
+ void testTemplateWithNamespace();
+ void testTemplateValueAsArgument();
+ void testTemplatePointerAsArgument();
+ void testTemplateReferenceAsArgument();
+ void testTemplateParameterFixup();
+ void testInheritanceFromContainterTemplate();
+ void testTemplateInheritanceMixedWithForwardDeclaration();
+ void testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration();
+ void testTypedefOfInstantiationOfTemplateClass();
+ void testContainerTypeIncompleteArgument();
+ void testNonTypeTemplates();
+ void testTemplateTypeDefs_data();
+ void testTemplateTypeDefs();
+ void testTemplateTypeAliases();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp b/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp
new file mode 100644
index 000000000..50cefcfe9
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp
@@ -0,0 +1,61 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testtoposort.h"
+#include "graph.h"
+
+#include <QtTest/QTest>
+#include <QtCore/QDebug>
+
+using IntGraph = Graph<int>;
+
+Q_DECLARE_METATYPE(IntGraph)
+
+using IntList = QList<int>;
+
+void TestTopoSort::testTopoSort_data()
+{
+ QTest::addColumn<IntGraph>("graph");
+ QTest::addColumn<bool>("expectedValid");
+ QTest::addColumn<IntList>("expectedOrder");
+
+ const int nodes1[] = {0, 1, 2};
+ IntGraph g(std::begin(nodes1), std::end(nodes1));
+ g.addEdge(1, 2);
+ g.addEdge(0, 1);
+ IntList expected = {0, 1, 2};
+ QTest::newRow("DAG") << g << true << expected;
+
+ const int nodes2[] = {0, 1};
+ g.clear();
+ g.setNodes(std::begin(nodes2), std::end(nodes2));
+ expected = {1, 0};
+ QTest::newRow("No edges") << g << true << expected;
+
+ g.clear();
+ g.setNodes(std::begin(nodes1), std::end(nodes1));
+ g.addEdge(0, 1);
+ g.addEdge(1, 2);
+ g.addEdge(2, 0);
+ expected.clear();
+ QTest::newRow("Cyclic") << g << false << expected;
+}
+
+void TestTopoSort::testTopoSort()
+{
+ QFETCH(IntGraph, graph);
+ QFETCH(bool, expectedValid);
+ QFETCH(IntList, expectedOrder);
+
+ const auto result = graph.topologicalSort();
+ QCOMPARE(result.isValid(), expectedValid);
+ if (expectedValid) {
+ QCOMPARE(result.result, expectedOrder);
+ QVERIFY(result.cyclic.isEmpty());
+ } else {
+ QVERIFY(!result.cyclic.isEmpty());
+ }
+}
+
+QTEST_APPLESS_MAIN(TestTopoSort)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testtoposort.h b/sources/shiboken6/ApiExtractor/tests/testtoposort.h
new file mode 100644
index 000000000..4271d6a0e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtoposort.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTTOPOSORT_H
+#define TESTTOPOSORT_H
+
+#include <QtCore/QObject>
+
+class TestTopoSort : public QObject
+{
+Q_OBJECT
+private slots:
+ void testTopoSort_data();
+ void testTopoSort();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp b/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp
new file mode 100644
index 000000000..72dae8cc5
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp
@@ -0,0 +1,92 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testtyperevision.h"
+#include "testutil.h"
+#include <abstractmetaenum.h>
+#include <abstractmetalang.h>
+#include <complextypeentry.h>
+#include <enumtypeentry.h>
+#include <flagstypeentry.h>
+#include <typedatabase.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestTypeRevision::testRevisionAttr()
+{
+ const char cppCode[] = "class Rev_0 {};"
+ "class Rev_1 {};"
+ "class Rev_2 { public: enum Rev_3 { X }; enum Rev_5 { Y }; };";
+ const char xmlCode[] = "<typesystem package=\"Foo\">"
+ "<value-type name=\"Rev_0\"/>"
+ "<value-type name=\"Rev_1\" revision=\"1\"/>"
+ "<object-type name=\"Rev_2\" revision=\"2\">"
+ " <enum-type name=\"Rev_3\" revision=\"3\" flags=\"Flag_4\" flags-revision=\"4\" />"
+ " <enum-type name=\"Rev_5\" revision=\"5\" flags=\"Flag_5\" />"
+ "</object-type>"
+ "</typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto rev0 = AbstractMetaClass::findClass(classes, "Rev_0");
+ QCOMPARE(rev0->typeEntry()->revision(), 0);
+
+ const auto rev1 = AbstractMetaClass::findClass(classes, "Rev_1");
+ QCOMPARE(rev1->typeEntry()->revision(), 1);
+
+ const auto rev2 = AbstractMetaClass::findClass(classes, "Rev_2");
+ QCOMPARE(rev2->typeEntry()->revision(), 2);
+
+ auto rev3 = rev2->findEnum(u"Rev_3"_s);
+ QVERIFY(rev3.has_value());
+ QCOMPARE(rev3->typeEntry()->revision(), 3);
+ auto rev4 = rev3->typeEntry()->flags();
+ QCOMPARE(rev4->revision(), 4);
+ auto rev5 = rev2->findEnum(u"Rev_5"_s);
+ QVERIFY(rev5.has_value());
+ EnumTypeEntryCPtr revEnumTypeEntry = rev5->typeEntry();
+ QCOMPARE(revEnumTypeEntry->revision(), 5);
+ QCOMPARE(revEnumTypeEntry->flags()->revision(), 5);
+}
+
+
+void TestTypeRevision::testVersion_data()
+{
+ QTest::addColumn<QString>("version");
+ QTest::addColumn<int>("expectedClassCount");
+
+ QTest::newRow("none") << QString() << 2;
+ QTest::newRow("1.0") << QString::fromLatin1("1.0") << 1; // Bar20 excluded
+ QTest::newRow("2.0") << QString::fromLatin1("2.0") << 2;
+ QTest::newRow("3.0") << QString::fromLatin1("3.0") << 1; // Bar excluded by "until"
+}
+
+void TestTypeRevision::testVersion()
+{
+ QFETCH(QString, version);
+ QFETCH(int, expectedClassCount);
+
+ const char cppCode[] = R"CPP(
+class Bar {};
+class Bar20 {};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <value-type name="Bar" until="2.0"/>
+ <value-type name="Bar20" since="2.0"/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, version));
+ QVERIFY(builder);
+
+ QCOMPARE(builder->classes().size(), expectedClassCount);
+}
+
+QTEST_APPLESS_MAIN(TestTypeRevision)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testtyperevision.h b/sources/shiboken6/ApiExtractor/tests/testtyperevision.h
new file mode 100644
index 000000000..84af839d2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtyperevision.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTTYPEREVISION_H
+#define TESTTYPEREVISION_H
+
+#include <QtCore/QObject>
+
+class TestTypeRevision : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testRevisionAttr();
+ void testVersion_data();
+ void testVersion();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testutil.h b/sources/shiboken6/ApiExtractor/tests/testutil.h
new file mode 100644
index 000000000..dc4e3b2da
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testutil.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTUTIL_H
+#define TESTUTIL_H
+#include <QtCore/QBuffer>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QTemporaryFile>
+#include "abstractmetabuilder.h"
+#include "reporthandler.h"
+#include "typedatabase.h"
+
+#include <exception>
+#include <memory>
+
+namespace TestUtil
+{
+ static AbstractMetaBuilder *parse(const char *cppCode, const char *xmlCode,
+ bool silent = true,
+ const QString &apiVersion = {},
+ const QStringList &dropTypeEntries = {},
+ LanguageLevel languageLevel = LanguageLevel::Default)
+ {
+ ReportHandler::setSilent(silent);
+ ReportHandler::startTimer();
+ auto *td = TypeDatabase::instance(true);
+ if (apiVersion.isEmpty())
+ TypeDatabase::clearApiVersions();
+ else if (!TypeDatabase::setApiVersion(QLatin1StringView("*"), apiVersion))
+ return nullptr;
+ td->setDropTypeEntries(dropTypeEntries);
+ QBuffer buffer;
+ // parse typesystem
+ buffer.setData(xmlCode);
+ if (!buffer.open(QIODevice::ReadOnly))
+ return nullptr;
+ if (!td->parseFile(&buffer))
+ return nullptr;
+ buffer.close();
+ // parse C++ code
+ QTemporaryFile tempSource(QDir::tempPath() + QLatin1StringView("/st_XXXXXX_main.cpp"));
+ if (!tempSource.open()) {
+ qWarning().noquote().nospace() << "Creation of temporary file failed: "
+ << tempSource.errorString();
+ return nullptr;
+ }
+ QByteArrayList arguments;
+ arguments.append(QFile::encodeName(tempSource.fileName()));
+ tempSource.write(cppCode, qint64(strlen(cppCode)));
+ tempSource.close();
+
+ auto builder = std::make_unique<AbstractMetaBuilder>();
+ try {
+ if (!builder->build(arguments, {}, true, languageLevel))
+ return nullptr;
+ } catch (const std::exception &e) {
+ qWarning("%s", e.what());
+ return nullptr;
+ }
+ return builder.release();
+ }
+} // namespace TestUtil
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp
new file mode 100644
index 000000000..98e30eac2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp
@@ -0,0 +1,39 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testvaluetypedefaultctortag.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <complextypeentry.h>
+
+void TestValueTypeDefaultCtorTag::testValueTypeDefaultCtorTagArgument()
+{
+ const char cppCode[] = "\n\
+ struct A {\n\
+ A(int,int);\n\
+ };\n\
+ struct B {};\n\
+ ";
+ const char xmlCode[] = "\n\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int' />\n\
+ <value-type name='A' default-constructor='A(0, 0)' />\n\
+ <value-type name='B' />\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QVERIFY(classA->typeEntry()->hasDefaultConstructor());
+ QCOMPARE(classA->typeEntry()->defaultConstructor(), u"A(0, 0)");
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QVERIFY(!classB->typeEntry()->hasDefaultConstructor());
+}
+
+QTEST_APPLESS_MAIN(TestValueTypeDefaultCtorTag)
diff --git a/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h
new file mode 100644
index 000000000..192c07c1d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTVALUETYPEDEFAULTCTORTAG_H
+#define TESTVALUETYPEDEFAULTCTORTAG_H
+
+#include <QtCore/QObject>
+
+class TestValueTypeDefaultCtorTag : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testValueTypeDefaultCtorTagArgument();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp b/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp
new file mode 100644
index 000000000..a600181a5
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testvoidarg.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestVoidArg::testVoidParsedFunction()
+{
+ const char cppCode[] = "struct A { void a(void); };";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("a");
+ QVERIFY(addedFunc);
+ QCOMPARE(addedFunc->arguments().size(), 0);
+}
+
+void TestVoidArg::testVoidAddedFunction()
+{
+ const char cppCode[] = "struct A { };";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' >\n\
+ <add-function signature=\"a(void)\"/>\n\
+ </value-type>\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("a");
+ QVERIFY(addedFunc);
+ QCOMPARE(addedFunc->arguments().size(), 0);
+
+}
+
+void TestVoidArg::testVoidPointerParsedFunction()
+{
+ const char cppCode[] = "struct A { void a(void*); };";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' />\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("a");
+ QVERIFY(addedFunc);
+ QCOMPARE(addedFunc->arguments().size(), 1);
+
+}
+
+QTEST_APPLESS_MAIN(TestVoidArg)
diff --git a/sources/shiboken6/ApiExtractor/tests/testvoidarg.h b/sources/shiboken6/ApiExtractor/tests/testvoidarg.h
new file mode 100644
index 000000000..191b9cfb2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testvoidarg.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTVOIDARG_H
+#define TESTVOIDARG_H
+#include <QtCore/QObject>
+
+class TestVoidArg : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testVoidParsedFunction();
+ void testVoidPointerParsedFunction();
+ void testVoidAddedFunction();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/utf8code.txt b/sources/shiboken6/ApiExtractor/tests/utf8code.txt
new file mode 100644
index 000000000..6d5fa9dcf
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/utf8code.txt
@@ -0,0 +1 @@
+áéíóú \ No newline at end of file
diff --git a/sources/shiboken6/ApiExtractor/textstream.cpp b/sources/shiboken6/ApiExtractor/textstream.cpp
new file mode 100644
index 000000000..83d981b2b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/textstream.cpp
@@ -0,0 +1,263 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "textstream.h"
+
+#include <cstring>
+
+TextStream::TextStream(QIODevice *device, Language l) :
+ m_str(device), m_language(l)
+{
+}
+
+TextStream::TextStream(QString *string, Language l) :
+ m_str(string), m_language(l)
+{
+}
+
+TextStream::TextStream(QByteArray *array, Language l) :
+ m_str(array), m_language(l)
+{
+}
+
+TextStream::~TextStream() = default;
+
+QChar TextStream::lastChar() const
+{
+ auto s = m_str.string();
+ return s != nullptr && !s->isEmpty() ? *(s->crbegin()) : QChar();
+}
+
+void TextStream::setIndentation(int i)
+{
+ Q_ASSERT(i >= 0);
+ m_indentation = i;
+}
+
+void TextStream::outdent(int n)
+{
+ m_indentation -= n;
+ Q_ASSERT(m_indentation >= 0);
+}
+
+qint64 TextStream::pos() const
+{
+ // QTextStream::pos() only works for QIODevice, be a bit smarter
+ if (auto s = m_str.string())
+ return s->size();
+ // QIODevices need to flushed to tell the correct position.
+ const_cast<QTextStream &>(m_str).flush();
+ return m_str.pos();
+}
+
+void TextStream::setString(QString *string, QIODeviceBase::OpenMode openMode)
+{
+ m_str.setString(string, openMode);
+ m_rstFormattingEnd = false;
+}
+
+void TextStream::putRepetitiveChars(char c, int count)
+{
+ if (count > 0) {
+ for (int i = 0; i < count; ++i) {
+ const int ofw = m_str.fieldWidth();
+ m_str.setFieldWidth(0);
+ m_str << c;
+ m_str.setFieldWidth(ofw);
+ }
+ }
+}
+
+void TextStream::_setRstFormattingEnd()
+{
+ m_rstFormattingEnd = true;
+}
+
+void TextStream::setLastCharClass(CharClass c)
+{
+ m_lastCharClass = c;
+}
+
+void TextStream::writeIndent()
+{
+ putRepetitiveChars(' ', m_indentation * m_tabWidth);
+}
+
+// Indent handling: If the last character was a new line
+// and the upcoming one is none, indent the stream
+// Special case for C++ : If the upcoming char is a '#', we don't
+// indent (preprocessor directive).
+
+template <class Char>
+static TextStream::CharClass charClassHelper(Char c)
+{
+ switch (c) {
+ case '\n':
+ return TextStream::CharClass::NewLine;
+ case '#':
+ return TextStream::CharClass::Hash;
+ case ' ':
+ case '\t':
+ return TextStream::CharClass::Space;
+ case '\\':
+ return TextStream::CharClass::BackSlash;
+ default:
+ break;
+ }
+ return TextStream::CharClass::Other;
+}
+
+static inline TextStream::CharClass charClass(char c)
+{ return charClassHelper(c); }
+
+static inline TextStream::CharClass charClass(QChar c)
+{ return charClassHelper(c.unicode()); }
+
+void TextStream::checkIndent(CharClass upComingCharClass)
+{
+ if (m_rstFormattingEnd) {
+ if (upComingCharClass != CharClass::Space && upComingCharClass != CharClass::NewLine
+ && upComingCharClass != CharClass::BackSlash) {
+ m_str << '\\';
+ }
+ m_rstFormattingEnd = false;
+ }
+ if (m_indentationEnabled && m_lastCharClass == CharClass::NewLine
+ && (upComingCharClass != CharClass::NewLine
+ && (m_language != Language::Cpp || upComingCharClass != CharClass::Hash))) {
+ writeIndent();
+ }
+ m_lastCharClass = upComingCharClass;
+}
+
+template <class Char>
+void TextStream::putCharHelper(Char c)
+{
+ const auto klass = charClass(c);
+ checkIndent(klass);
+ m_str << c;
+}
+
+void TextStream::putString(QStringView v)
+{
+ if (v.isEmpty())
+ return;
+ if (v.contains(u'\n')) {
+ for (auto c : v)
+ putCharHelper(c);
+ } else {
+ // If there is no newline, write as a blob. This is important to make
+ // field formatting (alignment/width) working, else each char will be
+ // considered a field.
+ const auto klass = charClass(*v.cbegin());
+ checkIndent(klass);
+ m_str << v;
+ m_lastCharClass = CharClass::Other;
+ }
+}
+
+void TextStream::putChar(QChar c)
+{
+ putCharHelper(c);
+}
+
+void TextStream::putString(const char *s)
+{
+ const char firstChar = *s;
+ if (firstChar == '\0')
+ return;
+ if (std::strchr(s, '\n') != nullptr) { // See above
+ for ( ; *s; ++s)
+ putCharHelper(*s);
+ } else {
+ checkIndent(charClass(firstChar));
+ m_str << s;
+ m_lastCharClass = CharClass::Other;
+ }
+}
+
+void TextStream::putChar(char c)
+{
+ putCharHelper(c);
+}
+
+void TextStream::putInt(int t)
+{
+ checkIndent(CharClass::Other);
+ m_str << t;
+}
+
+void TextStream::putSizeType(qsizetype t)
+{
+ checkIndent(CharClass::Other);
+ m_str << t;
+}
+
+StringStream::StringStream(Language l) : TextStream(&m_buffer, l)
+{
+}
+
+void StringStream::clear()
+{
+ m_buffer.clear();
+ setLastCharClass(CharClass::NewLine);
+}
+
+void indent(TextStream &s)
+{
+ s.indent();
+}
+
+void outdent(TextStream &s)
+{
+ s.outdent();
+}
+
+void enableIndent(TextStream &s)
+{
+ s.setIndentationEnabled(true);
+}
+
+void disableIndent(TextStream &s)
+{
+ s.setIndentationEnabled(false);
+}
+
+void ensureEndl(TextStream &s)
+{
+ if (s.lastChar() != u'\n')
+ s << '\n';
+}
+
+void rstBold(TextStream &s)
+{
+ s.putRawString("**");
+}
+
+void rstBoldOff(TextStream &s)
+{
+ s.putRawString("**");
+ s._setRstFormattingEnd();
+}
+
+void rstItalic(TextStream &s)
+{
+ s.putRawChar('*');
+}
+
+void rstItalicOff(TextStream &s)
+{
+ s.putRawChar('*');
+ s._setRstFormattingEnd();
+}
+
+void rstCode(TextStream &s)
+{
+ s.putRawString("``");
+}
+
+void rstCodeOff(TextStream &s)
+{
+ s.putRawString("``");
+ s._setRstFormattingEnd();
+}
diff --git a/sources/shiboken6/ApiExtractor/textstream.h b/sources/shiboken6/ApiExtractor/textstream.h
new file mode 100644
index 000000000..228f36405
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/textstream.h
@@ -0,0 +1,227 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TEXTSTREAM_H
+#define TEXTSTREAM_H
+
+#include <QtCore/QTextStream>
+#include <QtCore/QString>
+
+/// A text stream based on QTextStream with built-in indent.
+class TextStream
+{
+public:
+ Q_DISABLE_COPY_MOVE(TextStream)
+
+ using ManipulatorFunc = void(TextStream &);
+
+ enum class Language
+ {
+ None, Cpp
+ };
+
+ enum class CharClass
+ {
+ Other, NewLine, Space, Hash, BackSlash
+ };
+
+ explicit TextStream(QIODevice *device, Language l = Language::None);
+ explicit TextStream(QString *string, Language l = Language::None);
+ explicit TextStream(QByteArray *array, Language l = Language::None);
+ virtual ~TextStream();
+
+ Language language() const { return m_language; }
+ void setLanguage(Language language) { m_language = language; }
+
+ bool isIndentationEnabled() const { return m_indentationEnabled; }
+ void setIndentationEnabled(bool m)
+ { m_indentationEnabled = m; }
+
+ int tabWidth() const { return m_tabWidth; }
+ void setTabWidth(int tabWidth) { m_tabWidth = tabWidth; }
+
+ void setFieldWidth(int f) { m_str.setFieldWidth(f); }
+ int fieldWidth() const { return m_str.fieldWidth(); }
+
+ int indentation() const { return m_indentation; }
+ void setIndentation(int i);
+
+ void indent(int n = 1) { m_indentation += n; }
+ void outdent(int n = 1);
+
+ // QTextStream API
+ qint64 pos() const;
+ QTextStream::FieldAlignment fieldAlignment() const
+ { return m_str.fieldAlignment(); }
+ void setFieldAlignment(QTextStream::FieldAlignment al)
+ { m_str.setFieldAlignment(al); }
+ void setString(QString *string, QIODeviceBase::OpenMode openMode = QIODeviceBase::ReadWrite);
+ QString *string() const { return m_str.string(); }
+ void flush() { m_str.flush(); }
+ void setDevice(QIODevice *device) { m_str.setDevice(device); }
+ QIODevice *device() const { return m_str.device(); }
+ QTextStream &textStream() { return m_str; }
+
+ // Last character written, works only for streams on strings
+ QChar lastChar() const;
+
+ void putString(QStringView v);
+ void putChar(QChar c);
+ void putString(const char *s);
+ void putChar(char c);
+
+ void putInt(int t);
+ void putSizeType(qsizetype t);
+
+ void putRawString(const char *s) { m_str << s; }
+ void putRawChar(char c) { m_str << c; }
+
+ TextStream &operator<<(QStringView v) { putString(v); return *this; }
+ TextStream &operator<<(const QString &qs) { putString(QStringView{qs}); return *this; }
+ TextStream &operator<<(QLatin1StringView lv) { putString(lv.constData()); return *this; }
+ TextStream &operator<<(QUtf8StringView uv) { putString(uv.data()); return *this; }
+ TextStream &operator<<(const QByteArray &ba) { putString(ba.constData()); return *this; }
+ TextStream &operator<<(QChar c) { putChar(c); return *this; }
+ TextStream &operator<<(const char *s) { putString(s); return *this; }
+ TextStream &operator<<(char c) { putChar(c); return *this; }
+ TextStream &operator<<(int t) { putInt(t); return *this; }
+#if QT_POINTER_SIZE != 4
+ TextStream &operator<<(qsizetype t) { putSizeType(t); return *this; }
+#endif
+
+ inline TextStream &operator<<(const QTextStreamManipulator &m) { m_str << m; return *this; }
+ inline TextStream &operator<<(ManipulatorFunc f) { f(*this); return *this; }
+
+ void putRepetitiveChars(char c, int count);
+
+ void _setRstFormattingEnd();
+
+protected:
+ void setLastCharClass(CharClass c);
+
+private:
+ void writeIndent();
+ void checkIndent(CharClass upComingCharClass);
+ template <class Char>
+ void putCharHelper(Char c);
+
+ QTextStream m_str;
+ CharClass m_lastCharClass = CharClass::NewLine;
+ int m_tabWidth = 4;
+ int m_indentation = 0;
+ bool m_indentationEnabled = true;
+ bool m_rstFormattingEnd = false; // just past some **bla** where '\' needs to be enforced
+ Language m_language;
+};
+
+/// Stream into a string (cf std::ostringstream)
+class StringStream : public TextStream
+{
+public:
+ StringStream(Language l = Language::None);
+
+ qsizetype size() const { return m_buffer.size(); }
+ void clear();
+
+ const QString &toString() const { return m_buffer; }
+ operator const QString &() const { return m_buffer; }
+
+private:
+ QString m_buffer;
+};
+
+void indent(TextStream &s);
+void outdent(TextStream &s);
+void enableIndent(TextStream &s);
+void disableIndent(TextStream &s);
+// Works only for streams on strings
+void ensureEndl(TextStream &s);
+
+void rstBold(TextStream &s);
+void rstBoldOff(TextStream &s);
+void rstCode(TextStream &s);
+void rstCodeOff(TextStream &s);
+void rstItalic(TextStream &s);
+void rstItalicOff(TextStream &s);
+
+inline TextStream &operator<<(TextStream &str, QAnyStringView asv)
+{
+ asv.visit([&str](auto s) { str << s; });
+ return str;
+}
+
+/// Format an aligned field
+template <class T>
+class AlignedField
+{
+public:
+ explicit AlignedField(T value, int fieldWidth,
+ QTextStream::FieldAlignment a = QTextStream::AlignLeft) :
+ m_value(value), m_fieldWidth(fieldWidth), m_alignment(a)
+ {
+ }
+
+ void put(TextStream &s) const
+ {
+ const int oldFieldWidth = s.fieldWidth();
+ const auto oldFieldAlignment = s.fieldAlignment();
+ s.setFieldWidth(m_fieldWidth);
+ s.setFieldAlignment(m_alignment);
+ const auto oldPos = s.pos();
+ s << m_value;
+ // Ensure something is written when an empty string is encountered
+ if (oldPos == s.pos() && m_fieldWidth > 0)
+ s << ' ';
+ s.setFieldAlignment(oldFieldAlignment);
+ s.setFieldWidth(oldFieldWidth);
+ }
+
+private:
+ const T m_value;
+ const int m_fieldWidth;
+ const QTextStream::FieldAlignment m_alignment;
+};
+
+template <class T>
+TextStream &operator<<(TextStream &str, const AlignedField<T> &fa)
+{
+ fa.put(str);
+ return str;
+}
+
+class Pad
+{
+public:
+ explicit Pad(char c, int count) : m_char(c), m_count(count) {}
+
+ void write(TextStream &str) const
+ {
+ for (int i = 0; i < m_count; ++i)
+ str << m_char;
+ }
+
+private:
+ const char m_char;
+ const int m_count;
+};
+
+inline TextStream &operator<<(TextStream &str, const Pad &pad)
+{
+ pad.write(str);
+ return str;
+}
+
+class Indentation
+{
+public:
+ Q_DISABLE_COPY_MOVE(Indentation)
+
+ Indentation(TextStream &s, int n = 1) : m_s(s), m_n(n) { m_s.indent(m_n); }
+ ~Indentation() { m_s.outdent(m_n); }
+
+private:
+ TextStream &m_s;
+ const int m_n;
+};
+
+#endif // TEXTSTREAM_H
diff --git a/sources/shiboken6/ApiExtractor/typedatabase.cpp b/sources/shiboken6/ApiExtractor/typedatabase.cpp
new file mode 100644
index 000000000..61fd22418
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typedatabase.cpp
@@ -0,0 +1,1661 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "typedatabase.h"
+#include "abstractmetatype.h"
+#include "addedfunction.h"
+#include "messages.h"
+#include "typesystemparser_p.h"
+#include "complextypeentry.h"
+#include "constantvaluetypeentry.h"
+#include "containertypeentry.h"
+#include "customtypenentry.h"
+#include "debughelpers_p.h"
+#include "exception.h"
+#include "flagstypeentry.h"
+#include "functiontypeentry.h"
+#include "namespacetypeentry.h"
+#include "objecttypeentry.h"
+#include "primitivetypeentry.h"
+#include "optionsparser.h"
+#include "pythontypeentry.h"
+#include "smartpointertypeentry.h"
+#include "typedefentry.h"
+#include "typesystemtypeentry.h"
+#include "varargstypeentry.h"
+#include "voidtypeentry.h"
+#include "conditionalstreamreader.h"
+#include "predefined_templates.h"
+#include "clangparser/compilersupport.h"
+#include "modifications.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QFile>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QList>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QVersionNumber>
+#include <QtCore/QXmlStreamReader>
+#include "reporthandler.h"
+
+#include <algorithm>
+#include <utility>
+
+using namespace Qt::StringLiterals;
+
+using TypeDatabaseParserContextPtr = std::shared_ptr<TypeDatabaseParserContext>;
+
+// package -> api-version
+
+static QString wildcardToRegExp(QString w)
+{
+ w.replace(u'?', u'.');
+ w.replace(u'*', ".*"_L1);
+ return w;
+}
+
+using ApiVersion = std::pair<QRegularExpression, QVersionNumber>;
+using ApiVersions = QList<ApiVersion>;
+
+Q_GLOBAL_STATIC(ApiVersions, apiVersions)
+
+struct PythonType
+{
+ QString name;
+ QString checkFunction;
+ TypeSystem::CPythonType type;
+};
+
+using PythonTypes = QList<PythonType>;
+
+static const PythonTypes &builtinPythonTypes()
+{
+ static const PythonTypes result{
+ // "Traditional" custom types
+ // numpy
+ {u"PyArrayObject"_s, u"PyArray_Check"_s, TypeSystem::CPythonType::Other},
+ {u"PyBuffer"_s, u"Shiboken::Buffer::checkType"_s, TypeSystem::CPythonType::Other},
+ {u"PyByteArray"_s, u"PyByteArray_Check"_s, TypeSystem::CPythonType::Other},
+ {u"PyBytes"_s, u"PyBytes_Check"_s, TypeSystem::CPythonType::Other},
+ {u"PyCallable"_s, u"PyCallable_Check"_s, TypeSystem::CPythonType::Other},
+ {u"PyDate"_s, u"PyDate_Check"_s, TypeSystem::CPythonType::Other},
+ {u"PyDateTime"_s, u"PyDateTime_Check_Check"_s, TypeSystem::CPythonType::Other},
+ {u"PyDict"_s, u"PyDict_Check"_s, TypeSystem::CPythonType::Other},
+ // Convenience macro in sbkconverter.h
+ {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::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},
+ // Types used as target lang API types for primitive types
+ {u"PyBool"_s, u"PyBool_Check"_s, TypeSystem::CPythonType::Bool},
+ {u"PyComplex"_s, u"PyComplex_Check"_s, TypeSystem::CPythonType::Other},
+ {u"PyLong"_s, u"PyLong_Check"_s, TypeSystem::CPythonType::Integer},
+ {u"PyFloat"_s, u"PyFloat_Check"_s, TypeSystem::CPythonType::Float},
+ // Single character strings to match C++ char types
+ {u"SbkChar"_s, u"SbkChar_Check"_s, TypeSystem::CPythonType::String}
+ };
+ return result;
+}
+
+struct SuppressedWarning
+{
+ QRegularExpression pattern;
+ QString rawText;
+ bool generate; // Current type system
+ mutable bool matched = false;
+};
+
+QList<OptionDescription> TypeDatabase::options()
+{
+ return {
+ {u"api-version=<\"package mask\">,<\"version\">"_s,
+ u"Specify the supported api version used to generate the bindings"_s},
+ {u"drop-type-entries=\"<TypeEntry0>[;TypeEntry1;...]\""_s,
+ u"Semicolon separated list of type system entries (classes, namespaces,\n"
+ "global functions and enums) to be dropped from generation."_s},
+ {u"-T<path>"_s, {} },
+ {u"typesystem-paths="_s + OptionsParser::pathSyntax(),
+ u"Paths used when searching for typesystems"_s},
+ {u"force-process-system-include-paths="_s + OptionsParser::pathSyntax(),
+ u"Include paths that are considered as system headers by the C++ parser, but should still "
+ "be processed to extract types (e.g. Qt include paths in a yocto sysroot)"_s},
+ {u"keywords=keyword1[,keyword2,...]"_s,
+ u"A comma-separated list of keywords for conditional typesystem parsing"_s},
+ };
+}
+
+struct TypeDatabaseOptions
+{
+ QStringList m_dropTypeEntries;
+ QStringList m_forceProcessSystemIncludes;
+ QStringList m_typesystemKeywords;
+ QStringList m_typesystemPaths;
+ bool m_suppressWarnings = true;
+};
+
+class TypeDatabaseOptionsParser : public OptionsParser
+{
+public:
+ explicit TypeDatabaseOptionsParser(TypeDatabaseOptions *o) : m_options(o) {}
+
+ bool handleBoolOption(const QString &key, OptionSource source) override;
+ bool handleOption(const QString &key, const QString &value, OptionSource source) override;
+
+private:
+ TypeDatabaseOptions *m_options;
+};
+
+bool TypeDatabaseOptionsParser::handleBoolOption(const QString &key, OptionSource source)
+{
+ switch (source) {
+ case OptionSource::CommandLine:
+ case OptionSource::ProjectFile:
+ if (key == u"no-suppress-warnings") {
+ m_options->m_suppressWarnings = false;
+ return true;
+ }
+ break;
+ case OptionSource::CommandLineSingleDash:
+ if (key.startsWith(u'T')) { // "-T/path" ends up a bool option
+ m_options->m_typesystemPaths += key.sliced(1).split(QDir::listSeparator(),
+ Qt::SkipEmptyParts);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+bool TypeDatabaseOptionsParser::handleOption(const QString &key, const QString &value,
+ OptionSource source)
+{
+ if (source == OptionSource::CommandLineSingleDash)
+ return false;
+ if (key == u"api-version") {
+ const auto fullVersions = QStringView{value}.split(u'|');
+ for (const auto &fullVersion : fullVersions) {
+ const auto parts = fullVersion.split(u',');
+ const QString package = parts.size() == 1
+ ? u"*"_s : parts.constFirst().toString();
+ const QString version = parts.constLast().toString();
+ if (!TypeDatabase::setApiVersion(package, version))
+ throw Exception(msgInvalidVersion(package, version));
+ }
+ return true;
+ }
+
+ if (key == u"drop-type-entries") {
+ m_options->m_dropTypeEntries = value.split(u';');
+ m_options->m_dropTypeEntries.sort();
+ return true;
+ }
+
+ if (key == u"keywords") {
+ m_options->m_typesystemKeywords = value.split(u',');
+ return true;
+ }
+
+ if (key == u"typesystem-paths") {
+ m_options->m_typesystemPaths += value.split(QDir::listSeparator(),
+ Qt::SkipEmptyParts);
+ return true;
+ }
+
+ if (key == u"force-process-system-include-paths") {
+ m_options->m_forceProcessSystemIncludes += value.split(QDir::listSeparator(),
+ Qt::SkipEmptyParts);
+ return true;
+ }
+
+ if (source == OptionSource::ProjectFile) {
+ if (key == u"typesystem-path") {
+ m_options->m_typesystemPaths += value;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+struct TypeDatabasePrivate : public TypeDatabaseOptions
+{
+ TypeSystemTypeEntryCPtr defaultTypeSystemType() const;
+ TypeEntryPtr findType(const QString &name) const;
+ TypeEntryCList findCppTypes(const QString &name) const;
+ bool addType(TypeEntryPtr e, QString *errorMessage = nullptr);
+ bool parseFile(QIODevice *device, TypeDatabase *db, bool generate = true);
+ static bool parseFile(const TypeDatabaseParserContextPtr &context,
+ QIODevice *device, bool generate = true);
+ bool parseFile(const TypeDatabaseParserContextPtr &context,
+ const QString &filename, const QString &currentPath, bool generate);
+ bool prepareParsing(QFile &file, const QString &origFileName,
+ const QString &currentPath = {});
+
+ QString modifiedTypesystemFilepath(const QString& tsFile,
+ const QString &currentPath) const;
+ void addBuiltInType(const TypeEntryPtr &e);
+ PrimitiveTypeEntryPtr addBuiltInPrimitiveType(const QString &name,
+ const TypeSystemTypeEntryCPtr &root,
+ const QString &rootPackage,
+ const CustomTypeEntryPtr &targetLang);
+ void addBuiltInCppStringPrimitiveType(const QString &name,
+ const QString &viewName,
+ const TypeSystemTypeEntryCPtr &root,
+ const QString &rootPackage,
+ const CustomTypeEntryPtr &targetLang);
+ void addBuiltInPrimitiveTypes();
+ void addBuiltInContainerTypes(const TypeDatabaseParserContextPtr &context);
+ bool addOpaqueContainers(const TypeDatabaseParserContextPtr &context);
+ TypeEntryMultiMapConstIteratorRange findTypeRange(const QString &name) const;
+ template <class Predicate>
+ TypeEntryCList findTypesHelper(const QString &name, Predicate pred) const;
+ template <class Type, class Predicate>
+ QList<std::shared_ptr<const Type> > findTypesByTypeHelper(Predicate pred) const;
+ TypeEntryPtr resolveTypeDefEntry(const TypedefEntryPtr &typedefEntry, QString *errorMessage);
+ template <class String>
+ bool isSuppressedWarningHelper(const String &s) const;
+ bool resolveSmartPointerInstantiations(const TypeDatabaseParserContextPtr &context);
+ void formatDebug(QDebug &d) const;
+ void formatBuiltinTypes(QDebug &d) const;
+
+ TypeEntryMultiMap m_entries; // Contains duplicate entries (cf addInlineNamespaceLookups).
+ TypeEntryMap m_flagsEntries;
+ TypedefEntryMap m_typedefEntries;
+ TemplateEntryMap m_templates;
+ QList<SuppressedWarning> m_suppressedWarnings;
+ QList<TypeSystemTypeEntryCPtr > m_typeSystemEntries; // maintain order, default is first.
+
+ AddedFunctionList m_globalUserFunctions;
+ FunctionModificationList m_functionMods;
+
+ QStringList m_requiredTargetImports;
+
+ QHash<QString, bool> m_parsedTypesystemFiles;
+
+ QList<TypeRejection> m_rejections;
+};
+
+static const char ENV_TYPESYSTEMPATH[] = "TYPESYSTEMPATH";
+
+TypeDatabase::TypeDatabase() : d(new TypeDatabasePrivate)
+{
+ // Environment TYPESYSTEMPATH
+ if (qEnvironmentVariableIsSet(ENV_TYPESYSTEMPATH)) {
+ d->m_typesystemPaths
+ += qEnvironmentVariable(ENV_TYPESYSTEMPATH).split(QDir::listSeparator(),
+ Qt::SkipEmptyParts);
+ }
+
+ d->addBuiltInType(TypeEntryPtr(new VoidTypeEntry()));
+ d->addBuiltInType(TypeEntryPtr(new VarargsTypeEntry()));
+ for (const auto &pt : builtinPythonTypes())
+ d->addBuiltInType(TypeEntryPtr(new PythonTypeEntry(pt.name, pt.checkFunction, pt.type)));
+
+ for (const auto &p : predefinedTemplates())
+ addTemplate(p.name, p.content);
+}
+
+TypeDatabase::~TypeDatabase()
+{
+ delete d;
+}
+
+std::shared_ptr<OptionsParser> TypeDatabase::createOptionsParser()
+{
+ return std::make_shared<TypeDatabaseOptionsParser>(d);
+}
+
+TypeDatabase *TypeDatabase::instance(bool newInstance)
+{
+ static TypeDatabase *db = nullptr;
+ if (!db || newInstance) {
+ delete db;
+ db = new TypeDatabase;
+ }
+ return db;
+}
+
+// A list of regex/replacements to fix int types like "ushort" to "unsigned short"
+// unless present in TypeDatabase
+struct IntTypeNormalizationEntry
+{
+ QRegularExpression regex;
+ QString replacement;
+};
+
+using IntTypeNormalizationEntries = QList<IntTypeNormalizationEntry>;
+
+static const IntTypeNormalizationEntries &intTypeNormalizationEntries()
+{
+ static IntTypeNormalizationEntries result;
+ static bool firstTime = true;
+ if (firstTime) {
+ firstTime = false;
+ for (const auto &intType : {"char"_L1, "short"_L1, "int"_L1, "long"_L1}) {
+ if (!TypeDatabase::instance()->findType(u'u' + intType)) {
+ IntTypeNormalizationEntry entry;
+ entry.replacement = "unsigned "_L1 + intType;
+ entry.regex.setPattern("\\bu"_L1 + intType + "\\b"_L1);
+ Q_ASSERT(entry.regex.isValid());
+ result.append(entry);
+ }
+ }
+ }
+ return result;
+}
+
+// Normalization helpers
+enum CharCategory { Space, Identifier, Other };
+
+static CharCategory charCategory(QChar c)
+{
+ if (c.isSpace())
+ return Space;
+ if (c.isLetterOrNumber() || c == u'_')
+ return Identifier;
+ return Other;
+}
+
+// Normalize a C++ function signature:
+// Drop space except between identifiers ("unsigned int", "const int")
+static QString normalizeCppFunctionSignature(const QString &signatureIn)
+{
+ const QString signature = signatureIn.simplified();
+ QString result;
+ result.reserve(signature.size());
+
+ CharCategory lastNonSpaceCategory = Other;
+ bool pendingSpace = false;
+ for (QChar c : signature) {
+ if (c.isSpace()) {
+ pendingSpace = true;
+ } else {
+ const auto category = charCategory(c);
+ if (pendingSpace) {
+ if (lastNonSpaceCategory == Identifier && category == Identifier)
+ result.append(u' ');
+ pendingSpace = false;
+ }
+ lastNonSpaceCategory = category;
+ result.append(c);
+ }
+ }
+ return result;
+}
+
+// Normalize a signature for <add-function> by removing spaces
+QString TypeDatabase::normalizedAddedFunctionSignature(const QString &signature)
+{
+ return normalizeCppFunctionSignature(signature);
+}
+
+// Normalize a signature for matching by <modify-function>/<function>
+// by removing spaces and changing const-ref to value.
+// FIXME: PYSIDE7: Check whether the above simple normalization can be used
+// here as well. Note though that const-ref would then have to be spelled out
+// in typeystem XML.
+QString TypeDatabase::normalizedSignature(const QString &signature)
+{
+ // QMetaObject::normalizedSignature() changes const-ref to value and
+ // changes "unsigned int" to "uint" which is undone by the below code
+ QByteArray normalizedB = QMetaObject::normalizedSignature(signature.toUtf8().constData());
+ QString normalized = QLatin1StringView(normalizedB);
+
+ if (instance() && signature.contains(u"unsigned")) {
+ const IntTypeNormalizationEntries &entries = intTypeNormalizationEntries();
+ for (const auto &entry : entries)
+ normalized.replace(entry.regex, entry.replacement);
+ }
+
+ return normalized;
+}
+
+QStringList TypeDatabase::requiredTargetImports() const
+{
+ return d->m_requiredTargetImports;
+}
+
+void TypeDatabase::addRequiredTargetImport(const QString& moduleName)
+{
+ if (!d->m_requiredTargetImports.contains(moduleName))
+ d->m_requiredTargetImports << moduleName;
+}
+
+QStringList TypeDatabase::typesystemKeywords() const
+{
+ QStringList result = d->m_typesystemKeywords;
+ for (const auto &d : d->m_dropTypeEntries)
+ result.append("no_"_L1 + d);
+
+ switch (clang::emulatedCompilerLanguageLevel()) {
+ case LanguageLevel::Cpp11:
+ result.append(u"c++11"_s);
+ break;
+ case LanguageLevel::Cpp14:
+ result.append(u"c++14"_s);
+ break;
+ case LanguageLevel::Cpp17:
+ result.append(u"c++17"_s);
+ break;
+ case LanguageLevel::Cpp20:
+ result.append(u"c++20"_s);
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+IncludeList TypeDatabase::extraIncludes(const QString& className) const
+{
+ auto typeEntry = findComplexType(className);
+ return typeEntry ? typeEntry->extraIncludes() : IncludeList();
+}
+
+const QStringList &TypeDatabase::forceProcessSystemIncludes() const
+{
+ return d->m_forceProcessSystemIncludes;
+}
+
+void TypeDatabase::addForceProcessSystemInclude(const QString &name)
+{
+ d->m_forceProcessSystemIncludes.append(name);
+}
+
+// Add a lookup for the short name excluding inline namespaces
+// so that "std::shared_ptr" finds "std::__1::shared_ptr" as well.
+// Note: This inserts duplicate TypeEntryPtr into m_entries.
+void TypeDatabase::addInlineNamespaceLookups(const NamespaceTypeEntryCPtr &n)
+{
+ TypeEntryList additionalEntries; // Store before modifying the hash
+ for (const auto &entry : std::as_const(d->m_entries)) {
+ if (entry->isChildOf(n))
+ additionalEntries.append(entry);
+ }
+ for (const auto &ae : std::as_const(additionalEntries))
+ d->m_entries.insert(ae->shortName(), ae);
+}
+
+ContainerTypeEntryPtr TypeDatabase::findContainerType(const QString &name) const
+{
+ QString template_name = name;
+
+ const auto pos = name.indexOf(u'<');
+ if (pos > 0)
+ template_name = name.left(pos);
+
+ auto type_entry = findType(template_name);
+ if (type_entry && type_entry->isContainer())
+ return std::static_pointer_cast<ContainerTypeEntry>(type_entry);
+ return {};
+}
+
+static bool inline useType(const TypeEntryCPtr &t)
+{
+ return !t->isPrimitive()
+ || std::static_pointer_cast<const PrimitiveTypeEntry>(t)->preferredTargetLangType();
+}
+
+FunctionTypeEntryPtr TypeDatabase::findFunctionType(const QString &name) const
+{
+ const auto entries = d->findTypeRange(name);
+ for (const TypeEntryPtr &entry : entries) {
+ if (entry->type() == TypeEntry::FunctionType && useType(entry))
+ return std::static_pointer_cast<FunctionTypeEntry>(entry);
+ }
+ return {};
+}
+
+void TypeDatabase::addTypeSystemType(const TypeSystemTypeEntryCPtr &e)
+{
+ d->m_typeSystemEntries.append(e);
+}
+
+TypeSystemTypeEntryCPtr TypeDatabase::findTypeSystemType(const QString &name) const
+{
+ for (auto entry : d->m_typeSystemEntries) {
+ if (entry->name() == name)
+ return entry;
+ }
+ return {};
+}
+
+TypeSystemTypeEntryCPtr TypeDatabase::defaultTypeSystemType() const
+{
+ return d->defaultTypeSystemType();
+}
+
+QString TypeDatabase::loadedTypeSystemNames() const
+{
+ QString result;
+ for (const auto &entry : d->m_typeSystemEntries) {
+ if (!result.isEmpty())
+ result += u", "_s;
+ result += entry->name();
+ }
+ return result;
+}
+
+TypeSystemTypeEntryCPtr TypeDatabasePrivate::defaultTypeSystemType() const
+{
+ return m_typeSystemEntries.value(0, nullptr);
+}
+
+QString TypeDatabase::defaultPackageName() const
+{
+ Q_ASSERT(!d->m_typeSystemEntries.isEmpty());
+ return d->m_typeSystemEntries.constFirst()->name();
+}
+
+TypeEntryPtr TypeDatabase::findType(const QString& name) const
+{
+ return d->findType(name);
+}
+
+TypeEntryPtr TypeDatabasePrivate::findType(const QString& name) const
+{
+ const auto entries = findTypeRange(name);
+ for (const auto &entry : entries) {
+ if (useType(entry))
+ return entry;
+ }
+ return {};
+}
+
+template <class Predicate>
+TypeEntryCList TypeDatabasePrivate::findTypesHelper(const QString &name, Predicate pred) const
+{
+ TypeEntryCList result;
+ const auto entries = findTypeRange(name);
+ for (const auto &entry : entries) {
+ if (pred(entry))
+ result.append(entry);
+ }
+ return result;
+}
+
+template<class Type, class Predicate>
+QList<std::shared_ptr<const Type> > TypeDatabasePrivate::findTypesByTypeHelper(Predicate pred) const
+{
+ QList<std::shared_ptr<const Type> > result;
+ for (const auto &entry : m_entries) {
+ if (pred(entry))
+ result.append(std::static_pointer_cast<const Type>(entry));
+ }
+ return result;
+}
+
+TypeEntryCList TypeDatabase::findTypes(const QString &name) const
+{
+ return d->findTypesHelper(name, useType);
+}
+
+static bool useCppType(const TypeEntryCPtr &t)
+{
+ bool result = false;
+ switch (t->type()) {
+ case TypeEntry::PrimitiveType:
+ case TypeEntry::VoidType:
+ case TypeEntry::FlagsType:
+ case TypeEntry::EnumType:
+ case TypeEntry::TemplateArgumentType:
+ case TypeEntry::BasicValueType:
+ case TypeEntry::ContainerType:
+ case TypeEntry::ObjectType:
+ case TypeEntry::ArrayType:
+ case TypeEntry::CustomType:
+ case TypeEntry::SmartPointerType:
+ case TypeEntry::TypedefType:
+ result = useType(t);
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+TypeEntryCList TypeDatabase::findCppTypes(const QString &name) const
+{
+ return d->findCppTypes(name);
+}
+
+TypeEntryCList TypeDatabasePrivate::findCppTypes(const QString &name) const
+{
+ return findTypesHelper(name, useCppType);
+}
+
+const TypeEntryMultiMap &TypeDatabase::entries() const
+{
+ return d->m_entries;
+}
+
+const TypedefEntryMap &TypeDatabase::typedefEntries() const
+{
+ return d->m_typedefEntries;
+}
+
+TypeEntryMultiMapConstIteratorRange TypeDatabasePrivate::findTypeRange(const QString &name) const
+{
+ const auto range = m_entries.equal_range(name);
+ return {range.first, range.second};
+}
+
+PrimitiveTypeEntryCList TypeDatabase::primitiveTypes() const
+{
+ auto pred = [](const TypeEntryCPtr &t) { return t->isPrimitive(); };
+ return d->findTypesByTypeHelper<PrimitiveTypeEntry>(pred);
+}
+
+ContainerTypeEntryCList TypeDatabase::containerTypes() const
+{
+ auto pred = [](const TypeEntryCPtr &t) { return t->isContainer(); };
+ return d->findTypesByTypeHelper<ContainerTypeEntry>(pred);
+}
+
+SmartPointerTypeEntryList TypeDatabase::smartPointerTypes() const
+{
+ auto pred = [](const TypeEntryCPtr &t) { return t->isSmartPointer(); };
+ return d->findTypesByTypeHelper<SmartPointerTypeEntry>(pred);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const TypeRejection &r)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "TypeRejection(type=" << r.matchType << ", class="
+ << r.className.pattern() << ", pattern=" << r.pattern.pattern() << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+void TypeDatabase::addRejection(const TypeRejection &r)
+{
+ d->m_rejections << r;
+}
+
+// Match class name only
+bool TypeDatabase::isClassRejected(const QString& className, QString *reason) const
+{
+ for (const TypeRejection& r : d->m_rejections) {
+ if (r.matchType == TypeRejection::ExcludeClass && r.className.match(className).hasMatch()) {
+ r.matched = true;
+ if (reason)
+ *reason = msgRejectReason(r);
+ return true;
+ }
+ }
+ return false;
+}
+
+// Match class name and function/enum/field
+static bool findRejection(const QList<TypeRejection> &rejections,
+ TypeRejection::MatchType matchType,
+ const QString& className, const QString& name,
+ QString *reason = nullptr)
+{
+ Q_ASSERT(matchType != TypeRejection::ExcludeClass);
+ for (const TypeRejection& r : rejections) {
+ if (r.matchType == matchType && r.pattern.match(name).hasMatch()
+ && r.className.match(className).hasMatch()) {
+ r.matched = true;
+ if (reason)
+ *reason = msgRejectReason(r, name);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumName, QString *reason) const
+{
+ return findRejection(d->m_rejections, TypeRejection::Enum, className, enumName, reason);
+}
+
+TypeEntryPtr TypeDatabasePrivate::resolveTypeDefEntry(const TypedefEntryPtr &typedefEntry,
+ QString *errorMessage)
+{
+ QString sourceName = typedefEntry->sourceType();
+ const auto lessThanPos = sourceName.indexOf(u'<');
+ if (lessThanPos != -1)
+ sourceName.truncate(lessThanPos);
+ ComplexTypeEntryPtr source;
+ for (const auto &e : findTypeRange(sourceName)) {
+ switch (e->type()) {
+ case TypeEntry::BasicValueType:
+ case TypeEntry::ContainerType:
+ case TypeEntry::ObjectType:
+ case TypeEntry::SmartPointerType:
+ source = std::dynamic_pointer_cast<ComplexTypeEntry>(e);
+ Q_ASSERT(source);
+ break;
+ default:
+ break;
+ }
+ }
+ if (!source) {
+ if (errorMessage)
+ *errorMessage = msgUnableToResolveTypedef(typedefEntry->sourceType(), sourceName);
+ return nullptr;
+ }
+
+ m_typedefEntries.insert(typedefEntry->qualifiedCppName(), typedefEntry);
+ return TypeDatabase::initializeTypeDefEntry(typedefEntry, source);
+}
+
+ComplexTypeEntryPtr
+ TypeDatabase::initializeTypeDefEntry(const TypedefEntryPtr &typedefEntry,
+ const ComplexTypeEntryCPtr &source)
+{
+ ComplexTypeEntryPtr result(static_cast<ComplexTypeEntry *>(source->clone()));
+ result->useAsTypedef(typedefEntry);
+ typedefEntry->setSource(source);
+ typedefEntry->setTarget(result);
+ return result;
+}
+
+bool TypeDatabase::addType(const TypeEntryPtr &e, QString *errorMessage)
+{
+ return d->addType(e, errorMessage);
+}
+
+bool TypeDatabasePrivate::addType(TypeEntryPtr e, QString *errorMessage)
+{
+ if (e->type() == TypeEntry::TypedefType) {
+ e = resolveTypeDefEntry(std::static_pointer_cast<TypedefEntry>(e), errorMessage);
+ if (Q_UNLIKELY(!e))
+ return false;
+ }
+ m_entries.insert(e->qualifiedCppName(), e);
+ return true;
+}
+
+// Add a dummy value entry for non-type template parameters
+ConstantValueTypeEntryPtr
+ TypeDatabase::addConstantValueTypeEntry(const QString &value,
+ const TypeEntryCPtr &parent)
+{
+ auto result = std::make_shared<ConstantValueTypeEntry>(value, parent);
+ result->setCodeGeneration(TypeEntry::GenerateNothing);
+ addType(result);
+ return result;
+}
+
+bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName,
+ QString *reason) const
+{
+ return findRejection(d->m_rejections, TypeRejection::Function, className, functionName, reason);
+}
+
+bool TypeDatabase::isFieldRejected(const QString& className, const QString& fieldName,
+ QString *reason) const
+{
+ return findRejection(d->m_rejections, TypeRejection::Field, className, fieldName, reason);
+}
+
+bool TypeDatabase::isArgumentTypeRejected(const QString& className, const QString& typeName,
+ QString *reason) const
+{
+ return findRejection(d->m_rejections, TypeRejection::ArgumentType, className, typeName, reason);
+}
+
+bool TypeDatabase::isReturnTypeRejected(const QString& className, const QString& typeName,
+ QString *reason) const
+{
+ return findRejection(d->m_rejections, TypeRejection::ReturnType, className, typeName, reason);
+}
+
+FlagsTypeEntryPtr TypeDatabase::findFlagsType(const QString &name) const
+{
+ TypeEntryPtr fte = findType(name);
+ if (!fte) {
+ fte = d->m_flagsEntries.value(name);
+ if (!fte) {
+ //last hope, search for flag without scope inside of flags hash
+ const auto end = d->m_flagsEntries.cend();
+ for (auto it = d->m_flagsEntries.cbegin(); it != end; ++it) {
+ if (it.key().endsWith(name)) {
+ fte = it.value();
+ break;
+ }
+ }
+ }
+ }
+ return std::static_pointer_cast<FlagsTypeEntry>(fte);
+}
+
+void TypeDatabase::addFlagsType(const FlagsTypeEntryPtr &fte)
+{
+ d->m_flagsEntries[fte->originalName()] = fte;
+}
+
+TemplateEntryPtr TypeDatabase::findTemplate(const QString &name) const
+{
+ return d->m_templates[name];
+}
+
+void TypeDatabase::addTemplate(const TemplateEntryPtr &t)
+{
+ d->m_templates[t->name()] = t;
+}
+
+void TypeDatabase::addTemplate(const QString &name, const QString &code)
+{
+ auto te = std::make_shared<TemplateEntry>(name);
+ te->addCode(code);
+ addTemplate(te);
+}
+
+AddedFunctionList TypeDatabase::globalUserFunctions() const
+{
+ return d->m_globalUserFunctions;
+}
+
+void TypeDatabase::addGlobalUserFunctions(const AddedFunctionList &functions)
+{
+ d->m_globalUserFunctions << functions;
+}
+
+AddedFunctionList TypeDatabase::findGlobalUserFunctions(const QString& name) const
+{
+ AddedFunctionList addedFunctions;
+ for (const AddedFunctionPtr &func : d->m_globalUserFunctions) {
+ if (func->name() == name)
+ addedFunctions.append(func);
+ }
+ return addedFunctions;
+}
+
+void TypeDatabase::addGlobalUserFunctionModifications(const FunctionModificationList &functionModifications)
+{
+ d->m_functionMods << functionModifications;
+}
+
+QString TypeDatabase::globalNamespaceClassName(const TypeEntryCPtr & /*entry*/)
+{
+ return u"Global"_s;
+}
+
+FunctionModificationList
+ TypeDatabase::globalFunctionModifications(const QStringList &signatures) const
+{
+ FunctionModificationList lst;
+ for (const auto &mod : d->m_functionMods) {
+ if (mod.matches(signatures))
+ lst << mod;
+ }
+
+ return lst;
+}
+
+bool TypeDatabase::addSuppressedWarning(const QString &warning, bool generate,
+ QString *errorMessage)
+{
+ QString pattern;
+ if (warning.startsWith(u'^') && warning.endsWith(u'$')) {
+ pattern = warning;
+ } else {
+ // Legacy syntax: Use wildcards '*' (unless escaped by '\')
+ QList<qsizetype> asteriskPositions;
+ const auto warningSize = warning.size();
+ for (qsizetype i = 0, warningSize = warning.size(); i < warningSize; ++i) {
+ if (warning.at(i) == u'\\')
+ ++i;
+ else if (warning.at(i) == u'*')
+ asteriskPositions.append(i);
+ }
+ asteriskPositions.append(warningSize);
+
+ pattern.append(u'^');
+ qsizetype lastPos = 0;
+ for (qsizetype a = 0, aSize = asteriskPositions.size(); a < aSize; ++a) {
+ if (a)
+ pattern.append(".*"_L1);
+ const auto nextPos = asteriskPositions.at(a);
+ if (nextPos > lastPos)
+ pattern.append(QRegularExpression::escape(warning.mid(lastPos, nextPos - lastPos)));
+ lastPos = nextPos + 1;
+ }
+ pattern.append(u'$');
+ }
+
+ QRegularExpression expression(pattern);
+ if (!expression.isValid()) {
+ *errorMessage = u"Invalid message pattern \""_s + warning
+ + u"\": "_s + expression.errorString();
+ return false;
+ }
+ expression.setPatternOptions(expression.patternOptions() | QRegularExpression::MultilineOption);
+
+ d->m_suppressedWarnings.append({expression, warning, generate});
+ return true;
+}
+
+bool TypeDatabase::isSuppressedWarning(QStringView s) const
+{
+ if (!d->m_suppressWarnings)
+ return false;
+ auto wit = std::find_if(d->m_suppressedWarnings.cbegin(), d->m_suppressedWarnings.cend(),
+ [&s] (const SuppressedWarning &e) {
+ return e.pattern.matchView(s).hasMatch();
+ });
+ const bool found = wit != d->m_suppressedWarnings.cend();
+ if (found)
+ wit->matched = true;
+ return found;
+}
+
+QString TypeDatabase::modifiedTypesystemFilepath(const QString& tsFile, const QString &currentPath) const
+{
+ return d->modifiedTypesystemFilepath(tsFile, currentPath);
+}
+
+void TypeDatabase::logUnmatched() const
+{
+ for (auto &sw : d->m_suppressedWarnings) {
+ if (sw.generate && !sw.matched)
+ qWarning("Unmatched suppressed warning: \"%s\"", qPrintable(sw.rawText));
+ }
+
+ for (auto &tr : d->m_rejections) {
+ if (tr.generate && !tr.matched) {
+ QDebug d = qWarning();
+ d.noquote();
+ d.nospace();
+ d << "Unmatched rejection: " << tr.matchType;
+ if (!tr.className.pattern().isEmpty())
+ d << " class " << tr.className.pattern();
+ if (!tr.pattern.pattern().isEmpty())
+ d << " \"" << tr.pattern.pattern() << '"';
+ }
+ }
+}
+
+QString TypeDatabasePrivate::modifiedTypesystemFilepath(const QString& tsFile,
+ const QString &currentPath) const
+{
+ const QFileInfo tsFi(tsFile);
+ if (tsFi.isAbsolute()) // No point in further lookups
+ return tsFi.absoluteFilePath();
+ if (tsFi.isFile()) // Make path absolute
+ return tsFi.absoluteFilePath();
+ if (!currentPath.isEmpty()) {
+ const QFileInfo fi(currentPath + u'/' + tsFile);
+ if (fi.isFile())
+ return fi.absoluteFilePath();
+ }
+ for (const QString &path : m_typesystemPaths) {
+ const QFileInfo fi(path + u'/' + tsFile);
+ if (fi.isFile())
+ return fi.absoluteFilePath();
+ }
+ return tsFile;
+}
+
+void TypeDatabasePrivate::addBuiltInContainerTypes(const TypeDatabaseParserContextPtr &context)
+{
+ // Unless the user has added the standard containers (potentially with
+ // some opaque types), add them by default.
+ const bool hasStdArray = findType(u"std::array"_s) != nullptr;
+ const bool hasStdPair = findType(u"std::pair"_s) != nullptr;
+ const bool hasStdList = findType(u"std::list"_s) != nullptr;
+ const bool hasStdVector = findType(u"std::vector"_s) != nullptr;
+ const bool hasStdMap = findType(u"std::map"_s) != nullptr;
+ const bool hasStdUnorderedMap = findType(u"std::unordered_map"_s) != nullptr;
+ const bool hasStdSpan = findType(u"std::span"_s) != nullptr;
+
+ if (hasStdPair && hasStdList && hasStdVector && hasStdMap && hasStdUnorderedMap)
+ return;
+
+ QByteArray ts = R"(<?xml version="1.0" encoding="UTF-8"?><typesystem>)";
+ if (!hasStdArray) {
+ ts += containerTypeSystemSnippet(
+ "std::array", "list", "array",
+ "shiboken_conversion_cppsequence_to_pylist",
+ "PySequence",
+ "shiboken_conversion_pyiterable_to_cpparray");
+ }
+ if (!hasStdPair) {
+ ts += containerTypeSystemSnippet(
+ "std::pair", "pair", "utility",
+ "shiboken_conversion_cpppair_to_pytuple",
+ "PySequence", "shiboken_conversion_pysequence_to_cpppair");
+ }
+ if (!hasStdList) {
+ ts += containerTypeSystemSnippet(
+ "std::list", "list", "list",
+ "shiboken_conversion_cppsequence_to_pylist",
+ "PySequence",
+ "shiboken_conversion_pyiterable_to_cppsequentialcontainer");
+ }
+ if (!hasStdVector) {
+ ts += containerTypeSystemSnippet(
+ "std::vector", "list", "vector",
+ "shiboken_conversion_cppsequence_to_pylist",
+ "PySequence",
+ "shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve");
+ }
+ if (!hasStdMap) {
+ ts += containerTypeSystemSnippet(
+ "std::map", "map", "map",
+ "shiboken_conversion_stdmap_to_pydict",
+ "PyDict", "shiboken_conversion_pydict_to_stdmap");
+ }
+ if (!hasStdUnorderedMap) {
+ ts += containerTypeSystemSnippet(
+ "std::unordered_map", "map", "unordered_map",
+ "shiboken_conversion_stdmap_to_pydict",
+ "PyDict", "shiboken_conversion_pydict_to_stdmap");
+ }
+ if (!hasStdSpan
+ && clang::emulatedCompilerLanguageLevel() >= LanguageLevel::Cpp20) {
+ auto spanSnip = containerTypeSystemSnippet(
+ "std::span", "span", "span",
+ "shiboken_conversion_cppsequence_to_pylist");
+ auto pos = spanSnip.indexOf('>');
+ spanSnip.insert(pos, R"( view-on="std::vector")");
+ ts += spanSnip;
+ }
+
+ ts += "</typesystem>";
+ QBuffer buffer(&ts);
+ buffer.open(QIODevice::ReadOnly);
+ const bool ok = parseFile(context, &buffer, true);
+ Q_ASSERT(ok);
+}
+
+bool TypeDatabasePrivate::addOpaqueContainers(const TypeDatabaseParserContextPtr &context)
+{
+ const auto &och = context->opaqueContainerHash;
+ for (auto it = och.cbegin(), end = och.cend(); it != end; ++it) {
+ const QString &name = it.key();
+ auto te = findType(name);
+ if (!te || !te->isContainer()) {
+ qCWarning(lcShiboken, "No container \"%s\" found.", qPrintable(name));
+ return false;
+ }
+ auto cte = std::static_pointer_cast<ContainerTypeEntry>(te);
+ cte->appendOpaqueContainers(it.value());
+ }
+ return true;
+}
+
+bool TypeDatabase::parseFile(const QString &filename, bool generate)
+{
+ QString filepath = modifiedTypesystemFilepath(filename, {});
+ QFile file(filepath);
+ return d->prepareParsing(file, filename) && d->parseFile(&file, this, generate);
+}
+
+bool TypeDatabase::parseFile(const TypeDatabaseParserContextPtr &context,
+ const QString &filename, const QString &currentPath,
+ bool generate)
+{
+ return d->parseFile(context, filename, currentPath, generate);
+}
+
+bool TypeDatabasePrivate::prepareParsing(QFile &file, const QString &origFileName,
+ const QString &currentPath)
+{
+ const QString &filepath = file.fileName();
+ if (!file.exists()) {
+ m_parsedTypesystemFiles[filepath] = false;
+ QString message = u"Can't find "_s + origFileName;
+ if (!currentPath.isEmpty())
+ message += u", current path: "_s + currentPath;
+ message += u", typesystem paths: "_s + m_typesystemPaths.join(u", "_s);
+ qCWarning(lcShiboken, "%s", qPrintable(message));
+ return false;
+ }
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_parsedTypesystemFiles[filepath] = false;
+ qCWarning(lcShiboken, "%s", qPrintable(msgCannotOpenForReading(file)));
+ return false;
+ }
+
+ m_parsedTypesystemFiles[filepath] = true;
+ return true;
+}
+
+bool TypeDatabasePrivate::parseFile(const TypeDatabaseParserContextPtr &context,
+ const QString &filename, const QString &currentPath,
+ bool generate)
+{
+ // Prevent recursion when including self.
+ QString filepath = modifiedTypesystemFilepath(filename, currentPath);
+ const auto it = m_parsedTypesystemFiles.constFind(filepath);
+ if (it != m_parsedTypesystemFiles.cend())
+ return it.value();
+
+ QFile file(filepath);
+ if (!prepareParsing(file, filename, currentPath))
+ return false;
+
+ const bool ok = parseFile(context, &file, generate);
+ m_parsedTypesystemFiles[filepath] = ok;
+ return ok;
+}
+
+bool TypeDatabase::parseFile(QIODevice *device, bool generate)
+{
+ return d->parseFile(device, this, generate);
+}
+
+bool TypeDatabasePrivate::parseFile(QIODevice *device, TypeDatabase *db, bool generate)
+{
+ const auto context = std::make_shared<TypeDatabaseParserContext>();
+ context->db = db;
+
+ if (!parseFile(context, device, generate))
+ return false;
+
+ addBuiltInPrimitiveTypes();
+ addBuiltInContainerTypes(context);
+ return addOpaqueContainers(context)
+ && resolveSmartPointerInstantiations(context);
+}
+
+bool TypeDatabase::parseFile(const TypeDatabaseParserContextPtr &context,
+ QIODevice *device, bool generate)
+{
+ return d->parseFile(context, device, generate);
+}
+
+bool TypeDatabasePrivate::parseFile(const TypeDatabaseParserContextPtr &context,
+ QIODevice *device, bool generate)
+{
+ ConditionalStreamReader reader(device);
+ reader.setConditions(context->db->typesystemKeywords());
+ TypeSystemParser handler(context, generate);
+ const bool result = handler.parse(reader);
+ if (!result) {
+ qCWarning(lcShiboken, "%s", qPrintable(handler.errorString()));
+ return false;
+ }
+ return result;
+}
+
+// Split a type list potentially with template types
+// "A<B,C>,D" -> ("A<B,C>", "D")
+static QStringList splitTypeList(const QString &s)
+{
+ QStringList result;
+ int templateDepth = 0;
+ qsizetype lastPos = 0;
+ const auto size = s.size();
+ for (qsizetype i = 0; i < size; ++i) {
+ switch (s.at(i).toLatin1()) {
+ case '<':
+ ++templateDepth;
+ break;
+ case '>':
+ --templateDepth;
+ break;
+ case ',':
+ if (templateDepth == 0) {
+ result.append(s.mid(lastPos, i - lastPos).trimmed());
+ lastPos = i + 1;
+ }
+ break;
+ }
+ }
+ if (lastPos < size)
+ result.append(s.mid(lastPos, size - lastPos).trimmed());
+ return result;
+}
+
+bool TypeDatabasePrivate::resolveSmartPointerInstantiations(const TypeDatabaseParserContextPtr &context)
+{
+ const auto &instantiations = context->smartPointerInstantiations;
+ for (auto it = instantiations.cbegin(), end = instantiations.cend(); it != end; ++it) {
+ auto smartPointerEntry = it.key();
+ const auto instantiationNames = splitTypeList(it.value());
+ SmartPointerTypeEntry::Instantiations instantiations;
+ instantiations.reserve(instantiationNames.size());
+ for (const auto &instantiation : instantiationNames) {
+ QString name;
+ QString type = instantiation;
+ const auto equalsPos = instantiation.indexOf(u'=');
+ if (equalsPos != -1) {
+ type.truncate(equalsPos);
+ name = instantiation.mid(equalsPos + 1);
+ }
+
+ const auto typeEntries = findCppTypes(type);
+ if (typeEntries.isEmpty()) {
+ const QString m = msgCannotFindTypeEntryForSmartPointer(type,
+ smartPointerEntry->name());
+ qCWarning(lcShiboken, "%s", qPrintable(m));
+ return false;
+ }
+ if (typeEntries.size() > 1) {
+ const QString m = msgAmbiguousTypesFound(type, typeEntries);
+ qCWarning(lcShiboken, "%s", qPrintable(m));
+ return false;
+ }
+ instantiations.append({name, typeEntries.constFirst()});
+ }
+ smartPointerEntry->setInstantiations(instantiations);
+ }
+ return true;
+}
+
+PrimitiveTypeEntryPtr TypeDatabase::findPrimitiveType(const QString& name) const
+{
+ const auto entries = d->findTypeRange(name);
+ for (const auto &entry : entries) {
+ if (entry->isPrimitive()) {
+ auto pe = std::static_pointer_cast<PrimitiveTypeEntry>(entry);
+ if (pe->preferredTargetLangType())
+ return pe;
+ }
+ }
+
+ return nullptr;
+}
+
+ComplexTypeEntryPtr TypeDatabase::findComplexType(const QString& name) const
+{
+ const auto entries = d->findTypeRange(name);
+ for (const auto &entry : entries) {
+ if (entry->isComplex() && useType(entry))
+ return std::static_pointer_cast<ComplexTypeEntry>(entry);
+ }
+ return nullptr;
+}
+
+ObjectTypeEntryPtr TypeDatabase::findObjectType(const QString& name) const
+{
+ const auto entries = d->findTypeRange(name);
+ for (const auto &entry : entries) {
+ if (entry && entry->isObject() && useType(entry))
+ return std::static_pointer_cast<ObjectTypeEntry>(entry);
+ }
+ return nullptr;
+}
+
+NamespaceTypeEntryList TypeDatabase::findNamespaceTypes(const QString& name) const
+{
+ NamespaceTypeEntryList result;
+ const auto entries = d->findTypeRange(name);
+ for (const auto &entry : entries) {
+ if (entry->isNamespace())
+ result.append(std::static_pointer_cast<NamespaceTypeEntry>(entry));
+ }
+ return result;
+}
+
+NamespaceTypeEntryPtr TypeDatabase::findNamespaceType(const QString& name,
+ const QString &fileName) const
+{
+ const auto entries = findNamespaceTypes(name);
+ // Preferably check on matching file name first, if a pattern was given.
+ if (!fileName.isEmpty()) {
+ for (const auto &entry : entries) {
+ if (entry->hasPattern() && entry->matchesFile(fileName))
+ return entry;
+ }
+ }
+ for (const auto &entry : entries) {
+ if (!entry->hasPattern())
+ return entry;
+ }
+ return nullptr;
+}
+
+bool TypeDatabase::shouldDropTypeEntry(const QString& fullTypeName) const
+{
+ return d->m_dropTypeEntries.contains(fullTypeName);
+}
+
+void TypeDatabase::setDropTypeEntries(const QStringList &dropTypeEntries)
+{
+ d->m_dropTypeEntries = dropTypeEntries;
+ d->m_dropTypeEntries.sort();
+}
+
+static bool computeTypeIndexes = true;
+static int maxTypeIndex;
+
+static bool typeEntryLessThan(const TypeEntryCPtr &t1, const TypeEntryCPtr &t2)
+{
+ if (t1->revision() < t2->revision())
+ return true;
+ return t1->revision() == t2->revision()
+ && t1->qualifiedCppName() < t2->qualifiedCppName();
+}
+
+static void _computeTypeIndexes()
+{
+ auto *tdb = TypeDatabase::instance();
+
+ TypeEntryList list;
+
+ // Group type entries by revision numbers
+ const auto &allEntries = tdb->entries();
+ list.reserve(allEntries.size());
+ for (auto tit = allEntries.cbegin(), end = allEntries.cend(); tit != end; ++tit) {
+ const TypeEntryPtr &entry = tit.value();
+ if (entry->isPrimitive()
+ || entry->isContainer()
+ || entry->isFunction()
+ || !entry->generateCode()
+ || entry->isEnumValue()
+ || entry->isVarargs()
+ || entry->isTypeSystem()
+ || entry->isVoid()
+ || entry->isCustom())
+ continue;
+ if (!list.contains(entry)) // Remove duplicates
+ list.append(entry);
+ }
+
+ // Sort the type entries by revision, name
+ std::sort(list.begin(), list.end(), typeEntryLessThan);
+
+ maxTypeIndex = 0;
+ for (const TypeEntryPtr &e : std::as_const(list))
+ e->setSbkIndex(maxTypeIndex++);
+ computeTypeIndexes = false;
+}
+
+void TypeEntry::setRevision(int r)
+{
+ if (setRevisionHelper(r))
+ computeTypeIndexes = true;
+}
+
+int TypeEntry::sbkIndex() const
+{
+ if (computeTypeIndexes)
+ _computeTypeIndexes();
+ return sbkIndexHelper();
+}
+
+int getMaxTypeIndex()
+{
+ if (computeTypeIndexes)
+ _computeTypeIndexes();
+ return maxTypeIndex;
+}
+
+void TypeDatabase::clearApiVersions()
+{
+ apiVersions()->clear();
+}
+
+bool TypeDatabase::setApiVersion(const QString& packageWildcardPattern, const QString &version)
+{
+ const QString packagePattern = wildcardToRegExp(packageWildcardPattern.trimmed());
+ const QVersionNumber versionNumber = QVersionNumber::fromString(version);
+ if (versionNumber.isNull())
+ return false;
+ ApiVersions &versions = *apiVersions();
+ for (qsizetype i = 0, size = versions.size(); i < size; ++i) {
+ if (versions.at(i).first.pattern() == packagePattern) {
+ versions[i].second = versionNumber;
+ return true;
+ }
+ }
+ const QRegularExpression packageRegex(packagePattern);
+ if (!packageRegex.isValid())
+ return false;
+ versions.append(std::make_pair(packageRegex, versionNumber));
+ return true;
+}
+
+bool TypeDatabase::checkApiVersion(const QString &package,
+ const VersionRange &vr)
+{
+ const ApiVersions &versions = *apiVersions();
+ if (versions.isEmpty()) // Nothing specified: use latest.
+ return true;
+ for (qsizetype i = 0, size = versions.size(); i < size; ++i) {
+ if (versions.at(i).first.match(package).hasMatch())
+ return versions.at(i).second >= vr.since
+ && versions.at(i).second <= vr.until;
+ }
+ return false;
+}
+
+bool TypeDatabase::hasDroppedTypeEntries() const
+{
+ return !d->m_dropTypeEntries.isEmpty();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void TypeDatabase::formatDebug(QDebug &debug) const
+{
+ d->formatDebug(debug);
+}
+
+void TypeDatabasePrivate::formatDebug(QDebug &d) const
+{
+ d << "TypeDatabase("
+ << "entries[" << m_entries.size() << "]=";
+ for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it)
+ d << " " << it.value() << '\n';
+ if (!m_typedefEntries.isEmpty()) {
+ d << "typedefs[" << m_typedefEntries.size() << "]=(";
+ const auto begin = m_typedefEntries.cbegin();
+ for (auto it = begin, end = m_typedefEntries.cend(); it != end; ++it) {
+ if (it != begin)
+ d << ", ";
+ d << " " << it.value() << '\n';
+ }
+ d << ")\n";
+ }
+ if (!m_templates.isEmpty()) {
+ d << "templates[" << m_templates.size() << "]=(";
+ const auto begin = m_templates.cbegin();
+ for (auto it = begin, end = m_templates.cend(); it != end; ++it) {
+ if (it != begin)
+ d << ", ";
+ d << it.value();
+ }
+ d << ")\n";
+ }
+ if (!m_flagsEntries.isEmpty()) {
+ d << "flags[" << m_flagsEntries.size() << "]=(";
+ const auto begin = m_flagsEntries.cbegin();
+ for (auto it = begin, end = m_flagsEntries.cend(); it != end; ++it) {
+ if (it != begin)
+ d << ", ";
+ d << it.value();
+ }
+ d << ")\n";
+ }
+ d <<"\nglobalUserFunctions=" << m_globalUserFunctions << '\n';
+ formatList(d, "globalFunctionMods", m_functionMods, "\n");
+ d << ')';
+}
+
+// Helpers for dumping out primitive type info
+
+struct formatPrimitiveEntry
+{
+ explicit formatPrimitiveEntry(const PrimitiveTypeEntryCPtr &e) : m_pe(e) {}
+
+ PrimitiveTypeEntryCPtr m_pe;
+};
+
+QDebug operator<<(QDebug debug, const formatPrimitiveEntry &fe)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ const QString &name = fe.m_pe->name();
+ const QString &targetLangName = fe.m_pe->targetLangApiName();
+ debug << '"' << name << '"';
+ if (name != targetLangName)
+ debug << " (\"" << targetLangName << "\")";
+ if (fe.m_pe->isBuiltIn())
+ debug << " [builtin]";
+ if (isExtendedCppPrimitive(fe.m_pe)) {
+ debug << " [";
+ if (!isCppPrimitive(fe.m_pe))
+ debug << "extended ";
+ debug << "C++]";
+ }
+ return debug;
+}
+
+// Sort primitive types for displaying; base type and typedef'ed types
+struct PrimitiveFormatListEntry
+{
+ PrimitiveTypeEntryCPtr baseType;
+ PrimitiveTypeEntryCList typedefs;
+};
+
+static bool operator<(const PrimitiveFormatListEntry &e1, const PrimitiveFormatListEntry &e2)
+{
+ return e1.baseType->name() < e2.baseType->name();
+}
+
+using PrimitiveFormatListEntries = QList<PrimitiveFormatListEntry>;
+
+static qsizetype indexOf(const PrimitiveFormatListEntries &e, const PrimitiveTypeEntryCPtr &needle)
+{
+ for (qsizetype i = 0, size = e.size(); i < size; ++i) {
+ if (e.at(i).baseType == needle)
+ return i;
+ }
+ return -1;
+}
+
+void TypeDatabase::formatBuiltinTypes(QDebug debug) const
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+
+ // Determine base types and their typedef'ed types
+ QList<PrimitiveFormatListEntry> primitiveEntries;
+ for (const auto &e : std::as_const(d->m_entries)) {
+ if (e->isPrimitive()) {
+ auto pe = std::static_pointer_cast<const PrimitiveTypeEntry>(e);
+ auto basic = basicReferencedTypeEntry(pe);
+ if (basic != pe) {
+ const auto idx = indexOf(primitiveEntries, basic);
+ if (idx != -1)
+ primitiveEntries[idx].typedefs.append(pe);
+ else
+ primitiveEntries.append(PrimitiveFormatListEntry{basic, {pe}});
+ } else {
+ primitiveEntries.append(PrimitiveFormatListEntry{pe, {}});
+ }
+ }
+ }
+
+ std::sort(primitiveEntries.begin(), primitiveEntries.end());
+
+ for (const auto &e : std::as_const(primitiveEntries)) {
+ debug << "Primitive: " << formatPrimitiveEntry(e.baseType) << '\n';
+ for (const auto &pe : e.typedefs)
+ debug << " " << formatPrimitiveEntry(pe) << '\n';
+ }
+}
+
+void TypeDatabasePrivate::addBuiltInType(const TypeEntryPtr &e)
+{
+ e->setBuiltIn(true);
+ addType(e);
+}
+
+PrimitiveTypeEntryPtr
+ TypeDatabasePrivate::addBuiltInPrimitiveType(const QString &name,
+ const TypeSystemTypeEntryCPtr &root,
+ const QString &rootPackage,
+ const CustomTypeEntryPtr &targetLang)
+{
+ auto result = std::make_shared<PrimitiveTypeEntry>(name, QVersionNumber{}, root);
+ result->setTargetLangApiType(targetLang);
+ result->setTargetLangPackage(rootPackage);
+ addBuiltInType(result);
+ return result;
+}
+
+void TypeDatabasePrivate::addBuiltInCppStringPrimitiveType(const QString &name,
+ const QString &viewName,
+ const TypeSystemTypeEntryCPtr &root,
+ const QString &rootPackage,
+ const CustomTypeEntryPtr &targetLang)
+
+{
+ auto stringType = addBuiltInPrimitiveType(name, root, rootPackage,
+ targetLang);
+ auto viewType = addBuiltInPrimitiveType(viewName, root, rootPackage,
+ nullptr);
+ viewType->setViewOn(stringType);
+}
+
+void TypeDatabasePrivate::addBuiltInPrimitiveTypes()
+{
+ auto root = defaultTypeSystemType();
+ const QString &rootPackage = root->name();
+
+ // C++ primitive types
+ auto pyLongEntry = findType(u"PyLong"_s);
+ Q_ASSERT(pyLongEntry && pyLongEntry->isCustom());
+ auto pyLongCustomEntry = std::static_pointer_cast<CustomTypeEntry>(pyLongEntry);
+ auto pyBoolEntry = findType(u"PyBool"_s);
+ Q_ASSERT(pyBoolEntry && pyBoolEntry->isCustom());
+ auto sbkCharEntry = findType(u"SbkChar"_s);
+ Q_ASSERT(sbkCharEntry && sbkCharEntry->isCustom());
+ auto sbkCharCustomEntry = std::static_pointer_cast<CustomTypeEntry>(sbkCharEntry);
+
+ auto pyBoolCustomEntry = std::static_pointer_cast<CustomTypeEntry>(pyBoolEntry);
+ for (const auto &t : AbstractMetaType::cppIntegralTypes()) {
+ if (!m_entries.contains(t)) {
+ CustomTypeEntryPtr targetLangApi = pyLongCustomEntry;
+ if (t == u"bool")
+ targetLangApi = pyBoolCustomEntry;
+ else if (AbstractMetaType::cppCharTypes().contains(t))
+ targetLangApi = sbkCharCustomEntry;
+ addBuiltInPrimitiveType(t, root, rootPackage, targetLangApi);
+ }
+ }
+
+ auto pyFloatEntry = findType(u"PyFloat"_s);
+ Q_ASSERT(pyFloatEntry && pyFloatEntry->isCustom());
+ auto pyFloatCustomEntry = std::static_pointer_cast<CustomTypeEntry>(pyFloatEntry);
+ for (const auto &t : AbstractMetaType::cppFloatTypes()) {
+ if (!m_entries.contains(t))
+ addBuiltInPrimitiveType(t, root, rootPackage, pyFloatCustomEntry);
+ }
+
+ auto pyUnicodeEntry = findType(u"PyUnicode"_s);
+ Q_ASSERT(pyUnicodeEntry && pyUnicodeEntry->isCustom());
+ auto pyUnicodeCustomEntry = std::static_pointer_cast<CustomTypeEntry>(pyUnicodeEntry);
+
+ constexpr auto stdString = "std::string"_L1;
+ if (!m_entries.contains(stdString)) {
+ addBuiltInCppStringPrimitiveType(stdString, u"std::string_view"_s,
+ root, rootPackage,
+ pyUnicodeCustomEntry);
+ }
+ constexpr auto stdWString = "std::wstring"_L1;
+ if (!m_entries.contains(stdWString)) {
+ addBuiltInCppStringPrimitiveType(stdWString, u"std::wstring_view"_s,
+ root, rootPackage,
+ pyUnicodeCustomEntry);
+ }
+}
+
+QDebug operator<<(QDebug d, const TypeDatabase &db)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ db.formatDebug(d);
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/typedatabase.h b/sources/shiboken6/ApiExtractor/typedatabase.h
new file mode 100644
index 000000000..d5adca324
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typedatabase.h
@@ -0,0 +1,208 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPEDATABASE_H
+#define TYPEDATABASE_H
+
+#include "include.h"
+#include "modifications_typedefs.h"
+#include "typedatabase_typedefs.h"
+
+#include <QtCore/QRegularExpression>
+#include <QtCore/QStringList>
+#include <QtCore/QVersionNumber>
+
+#include <memory>
+
+QT_FORWARD_DECLARE_CLASS(QIODevice)
+
+struct OptionDescription;
+class OptionsParser;
+struct TypeDatabasePrivate;
+struct TypeDatabaseParserContext;
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+int getMaxTypeIndex();
+
+struct VersionRange
+{
+ bool isNull() const
+ {
+ return since.majorVersion() == 0 && since.minorVersion() == 0
+ && until.majorVersion() == 9999 && until.minorVersion() == 9999;
+ }
+
+ QVersionNumber since{0, 0};
+ QVersionNumber until{9999, 9999};
+};
+
+struct TypeRejection
+{
+ enum MatchType
+ {
+ ExcludeClass, // Match className only
+ Function, // Match className and function name
+ Field, // Match className and field name
+ Enum, // Match className and enum name
+ ArgumentType, // Match className and argument type
+ ReturnType // Match className and return type
+ };
+
+ QRegularExpression className;
+ QRegularExpression pattern;
+ MatchType matchType = ExcludeClass;
+ bool generate; // Current type system
+ mutable bool matched = false;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const TypeRejection &r);
+#endif
+
+class TypeDatabase
+{
+ TypeDatabase();
+public:
+ Q_DISABLE_COPY_MOVE(TypeDatabase)
+
+ ~TypeDatabase();
+
+ static QList<OptionDescription> options();
+ std::shared_ptr<OptionsParser> createOptionsParser();
+
+ /**
+ * Return the type system instance.
+ * \param newInstance This parameter is useful just for unit testing, because singletons causes
+ * too many side effects on unit testing.
+ */
+ static TypeDatabase *instance(bool newInstance = false);
+
+ static QString normalizedSignature(const QString &signature);
+ static QString normalizedAddedFunctionSignature(const QString &signature);
+
+ QStringList requiredTargetImports() const;
+
+ void addRequiredTargetImport(const QString &moduleName);
+
+ QStringList typesystemKeywords() const;
+
+ IncludeList extraIncludes(const QString &className) const;
+
+ const QStringList &forceProcessSystemIncludes() const;
+ void addForceProcessSystemInclude(const QString &name);
+
+ void addInlineNamespaceLookups(const NamespaceTypeEntryCPtr &n);
+
+ PrimitiveTypeEntryPtr findPrimitiveType(const QString &name) const;
+ ComplexTypeEntryPtr findComplexType(const QString &name) const;
+ ObjectTypeEntryPtr findObjectType(const QString &name) const;
+ NamespaceTypeEntryList findNamespaceTypes(const QString &name) const;
+ NamespaceTypeEntryPtr findNamespaceType(const QString &name, const QString &fileName = QString()) const;
+ ContainerTypeEntryPtr findContainerType(const QString &name) const;
+ FunctionTypeEntryPtr findFunctionType(const QString &name) const;
+ TypeSystemTypeEntryCPtr findTypeSystemType(const QString &name) const;
+ TypeSystemTypeEntryCPtr defaultTypeSystemType() const;
+ QString loadedTypeSystemNames() const;
+ QString defaultPackageName() const;
+
+ TypeEntryPtr findType(const QString &name) const;
+ TypeEntryCList findTypes(const QString &name) const;
+ TypeEntryCList findCppTypes(const QString &name) const;
+
+ const TypeEntryMultiMap &entries() const;
+ const TypedefEntryMap &typedefEntries() const;
+
+ PrimitiveTypeEntryCList primitiveTypes() const;
+
+ ContainerTypeEntryCList containerTypes() const;
+
+ SmartPointerTypeEntryList smartPointerTypes() const;
+
+ void addRejection(const TypeRejection &);
+ bool isClassRejected(const QString &className, QString *reason = nullptr) const;
+ bool isFunctionRejected(const QString &className, const QString &functionName,
+ QString *reason = nullptr) const;
+ bool isFieldRejected(const QString &className, const QString &fieldName,
+ QString *reason = nullptr) const;
+ bool isEnumRejected(const QString &className, const QString &enumName,
+ QString *reason = nullptr) const;
+ bool isArgumentTypeRejected(const QString &className, const QString &typeName,
+ QString *reason = nullptr) const;
+ bool isReturnTypeRejected(const QString &className, const QString &typeName,
+ QString *reason = nullptr) const;
+
+ bool addType(const TypeEntryPtr &e, QString *errorMessage = nullptr);
+ ConstantValueTypeEntryPtr addConstantValueTypeEntry(const QString &value,
+ const TypeEntryCPtr &parent);
+ void addTypeSystemType(const TypeSystemTypeEntryCPtr &e);
+
+ static ComplexTypeEntryPtr
+ initializeTypeDefEntry(const TypedefEntryPtr &typedefEntry,
+ const ComplexTypeEntryCPtr &source);
+
+ FlagsTypeEntryPtr findFlagsType(const QString &name) const;
+ void addFlagsType(const FlagsTypeEntryPtr &fte);
+
+ TemplateEntryPtr findTemplate(const QString &name) const;
+
+ void addTemplate(const TemplateEntryPtr &t);
+ void addTemplate(const QString &name, const QString &code);
+
+ AddedFunctionList globalUserFunctions() const;
+
+ void addGlobalUserFunctions(const AddedFunctionList &functions);
+
+ AddedFunctionList findGlobalUserFunctions(const QString &name) const;
+
+ void addGlobalUserFunctionModifications(const FunctionModificationList &functionModifications);
+
+ FunctionModificationList
+ globalFunctionModifications(const QStringList &signatures) const;
+
+ bool addSuppressedWarning(const QString &warning, bool generate, QString *errorMessage);
+
+ bool isSuppressedWarning(QStringView s) const;
+
+ static QString globalNamespaceClassName(const TypeEntryCPtr &te);
+
+ // Top level file parsing
+ bool parseFile(const QString &filename, bool generate = true);
+ bool parseFile(const std::shared_ptr<TypeDatabaseParserContext> &context,
+ const QString &filename, const QString &currentPath, bool generate);
+
+ // Top level QIODevice parsing for tests.
+ bool parseFile(QIODevice *device, bool generate = true);
+ bool parseFile(const std::shared_ptr<TypeDatabaseParserContext> &context,
+ QIODevice *device, bool generate = true);
+
+ static bool setApiVersion(const QString &package, const QString &version);
+ static void clearApiVersions();
+
+ static bool checkApiVersion(const QString &package, const VersionRange &vr);
+
+ bool hasDroppedTypeEntries() const;
+
+ bool shouldDropTypeEntry(const QString &fullTypeName) const;
+
+ void setDropTypeEntries(const QStringList &dropTypeEntries);
+
+ QString modifiedTypesystemFilepath(const QString &tsFile, const QString &currentPath = QString()) const;
+
+ void logUnmatched() const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+ void formatBuiltinTypes(QDebug debug) const;
+
+private:
+ TypeDatabasePrivate *d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const TypeEntryCPtr &te);
+QDebug operator<<(QDebug d, const TypeEntry *te);
+QDebug operator<<(QDebug d, const TypeDatabase &db);
+#endif
+#endif // TYPEDATABASE_H
diff --git a/sources/shiboken6/ApiExtractor/typedatabase_p.h b/sources/shiboken6/ApiExtractor/typedatabase_p.h
new file mode 100644
index 000000000..fc56c7961
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typedatabase_p.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPEDATABASE_P_H
+#define TYPEDATABASE_P_H
+
+#include "typesystem_typedefs.h"
+#include "containertypeentry.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QString>
+
+class TypeDatabase;
+
+struct TypeDatabaseParserContext
+{
+ using SmartPointerInstantiations = QHash<SmartPointerTypeEntryPtr, QString>;
+ using OpaqueContainerHash = QHash<QString, OpaqueContainers>;
+
+ TypeDatabase *db;
+ SmartPointerInstantiations smartPointerInstantiations;
+ OpaqueContainerHash opaqueContainerHash;
+};
+
+#endif // TYPEDATABASE_P_H
diff --git a/sources/shiboken6/ApiExtractor/typedatabase_typedefs.h b/sources/shiboken6/ApiExtractor/typedatabase_typedefs.h
new file mode 100644
index 000000000..f00c61570
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typedatabase_typedefs.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPEDATABASE_TYPEDEFS_H
+#define TYPEDATABASE_TYPEDEFS_H
+
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QMultiMap>
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+using TemplateEntryMap =QMap<QString, TemplateEntryPtr>;
+
+template <class Key, class Value>
+struct QMultiMapConstIteratorRange // A range of iterator for a range-based for loop
+{
+ using ConstIterator = typename QMultiMap<Key, Value>::const_iterator;
+
+ ConstIterator begin() const { return m_begin; }
+ ConstIterator end() const { return m_end; }
+
+ ConstIterator m_begin;
+ ConstIterator m_end;
+};
+
+using TypeEntryMultiMap = QMultiMap<QString, TypeEntryPtr>;
+using TypeEntryMultiMapConstIteratorRange = QMultiMapConstIteratorRange<QString, TypeEntryPtr>;
+
+using TypeEntryMap = QMap<QString, TypeEntryPtr>;
+using TypedefEntryMap = QMap<QString, TypedefEntryPtr>;
+
+#endif // TYPEDATABASE_TYPEDEFS_H
diff --git a/sources/shiboken6/ApiExtractor/typedefentry.h b/sources/shiboken6/ApiExtractor/typedefentry.h
new file mode 100644
index 000000000..44646972c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typedefentry.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPEDEFENTRY_H
+#define TYPEDEFENTRY_H
+
+#include "complextypeentry.h"
+
+class TypedefEntryPrivate;
+
+class TypedefEntry : public ComplexTypeEntry
+{
+public:
+ explicit TypedefEntry(const QString &entryName,
+ const QString &sourceType,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ QString sourceType() const;
+ void setSourceType(const QString &s);
+
+ TypeEntry *clone() const override;
+
+ ComplexTypeEntryCPtr source() const;
+ void setSource(const ComplexTypeEntryCPtr &source);
+
+ ComplexTypeEntryPtr target() const;
+ void setTarget(ComplexTypeEntryPtr target);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ explicit TypedefEntry(TypedefEntryPrivate *d);
+};
+
+#endif // TYPEDEFENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/typeparser.cpp b/sources/shiboken6/ApiExtractor/typeparser.cpp
new file mode 100644
index 000000000..11d7bf641
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typeparser.cpp
@@ -0,0 +1,292 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "typeparser.h"
+#include <typeinfo.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QStack>
+#include <QtCore/QTextStream>
+
+using namespace Qt::StringLiterals;
+
+class Scanner
+{
+public:
+ enum Token {
+ StarToken,
+ AmpersandToken,
+ LessThanToken,
+ ColonToken,
+ CommaToken,
+ OpenParenToken,
+ CloseParenToken,
+ SquareBegin,
+ SquareEnd,
+ GreaterThanToken,
+
+ ConstToken,
+ VolatileToken,
+ Identifier,
+ NoToken,
+ InvalidToken
+ };
+
+ Scanner(const QString &s)
+ : m_pos(0), m_length(s.length()), m_tokenStart(-1), m_chars(s.constData())
+ {
+ }
+
+ Token nextToken(QString *errorMessage = nullptr);
+ QString identifier() const;
+
+ QString msgParseError(const QString &why) const;
+
+private:
+ int m_pos;
+ int m_length;
+ int m_tokenStart;
+ const QChar *m_chars;
+};
+
+QString Scanner::identifier() const
+{
+ return QString(m_chars + m_tokenStart, m_pos - m_tokenStart);
+}
+
+Scanner::Token Scanner::nextToken(QString *errorMessage)
+{
+ Token tok = NoToken;
+
+ // remove whitespace
+ while (m_pos < m_length && m_chars[m_pos] == u' ')
+ ++m_pos;
+
+ m_tokenStart = m_pos;
+
+ while (m_pos < m_length) {
+
+ const QChar &c = m_chars[m_pos];
+
+ if (tok == NoToken) {
+ switch (c.toLatin1()) {
+ case '*': tok = StarToken; break;
+ case '&': tok = AmpersandToken; break;
+ case '<': tok = LessThanToken; break;
+ case '>': tok = GreaterThanToken; break;
+ case ',': tok = CommaToken; break;
+ case '(': tok = OpenParenToken; break;
+ case ')': tok = CloseParenToken; break;
+ case '[': tok = SquareBegin; break;
+ case ']' : tok = SquareEnd; break;
+ case ':':
+ tok = ColonToken;
+ Q_ASSERT(m_pos + 1 < m_length);
+ ++m_pos;
+ break;
+ default:
+ if (c.isLetterOrNumber() || c == u'_') {
+ tok = Identifier;
+ } else {
+ QString message;
+ QTextStream (&message) << ": Unrecognized character in lexer at "
+ << m_pos << " : '" << c << '\'';
+ message = msgParseError(message);
+ if (errorMessage)
+ *errorMessage = message;
+ else
+ qWarning().noquote().nospace() << message;
+ return InvalidToken;
+ }
+ break;
+ }
+ }
+
+ if (tok <= GreaterThanToken) {
+ ++m_pos;
+ break;
+ }
+
+ if (tok == Identifier) {
+ if (c.isLetterOrNumber() || c == u'_')
+ ++m_pos;
+ else
+ break;
+ }
+ }
+
+ if (tok == Identifier) {
+ switch (m_pos - m_tokenStart) {
+ case 5:
+ if (m_chars[m_tokenStart] == u'c'
+ && m_chars[m_tokenStart + 1] == u'o'
+ && m_chars[m_tokenStart + 2] == u'n'
+ && m_chars[m_tokenStart + 3] == u's'
+ && m_chars[m_tokenStart + 4] == u't') {
+ tok = ConstToken;
+ }
+ break;
+ case 8:
+ if (m_chars[m_tokenStart] == u'v'
+ && m_chars[m_tokenStart + 1] == u'o'
+ && m_chars[m_tokenStart + 2] == u'l'
+ && m_chars[m_tokenStart + 3] == u'a'
+ && m_chars[m_tokenStart + 4] == u't'
+ && m_chars[m_tokenStart + 5] == u'i'
+ && m_chars[m_tokenStart + 6] == u'l'
+ && m_chars[m_tokenStart + 7] == u'e') {
+ tok = VolatileToken;
+ }
+ break;
+ }
+ }
+
+ return tok;
+
+}
+
+QString Scanner::msgParseError(const QString &why) const
+{
+ return "TypeParser: Unable to parse \""_L1
+ + QString(m_chars, m_length) + "\": "_L1 + why;
+}
+
+TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
+{
+ Scanner scanner(str);
+
+ QStack<TypeInfo> stack;
+ stack.push(TypeInfo());
+
+ bool colon_prefix = false;
+ bool in_array = false;
+ QString array;
+ bool seenStar = false;
+
+ Scanner::Token tok = scanner.nextToken(errorMessage);
+ while (tok != Scanner::NoToken) {
+ if (tok == Scanner::InvalidToken)
+ return {};
+
+// switch (tok) {
+// case Scanner::StarToken: printf(" - *\n"); break;
+// case Scanner::AmpersandToken: printf(" - &\n"); break;
+// case Scanner::LessThanToken: printf(" - <\n"); break;
+// case Scanner::GreaterThanToken: printf(" - >\n"); break;
+// case Scanner::ColonToken: printf(" - ::\n"); break;
+// case Scanner::CommaToken: printf(" - ,\n"); break;
+// case Scanner::ConstToken: printf(" - const\n"); break;
+// case Scanner::SquareBegin: printf(" - [\n"); break;
+// case Scanner::SquareEnd: printf(" - ]\n"); break;
+// case Scanner::Identifier: printf(" - '%s'\n", qPrintable(scanner.identifier())); break;
+// default:
+// break;
+// }
+
+ switch (tok) {
+
+ case Scanner::StarToken:
+ seenStar = true;
+ stack.top().addIndirection(Indirection::Pointer);
+ break;
+
+ case Scanner::AmpersandToken:
+ switch (stack.top().referenceType()) {
+ case NoReference:
+ stack.top().setReferenceType(LValueReference);
+ break;
+ case LValueReference:
+ stack.top().setReferenceType(RValueReference);
+ break;
+ case RValueReference:
+ const QString message = scanner.msgParseError("Too many '&' qualifiers"_L1);
+ if (errorMessage)
+ *errorMessage = message;
+ else
+ qWarning().noquote().nospace() << message;
+ return {};
+ }
+ break;
+ case Scanner::LessThanToken:
+ stack.push(TypeInfo());
+ break;
+
+ case Scanner::CommaToken:
+ {
+ auto i = stack.pop();
+ stack.top().addInstantiation(i); // Add after populating to prevent detach
+ stack.push(TypeInfo());
+ }
+ break;
+
+ case Scanner::GreaterThanToken: {
+ auto i = stack.pop();
+ stack.top().addInstantiation(i); // Add after populating to prevent detach
+ }
+ break;
+
+ case Scanner::ColonToken:
+ colon_prefix = true;
+ break;
+
+ case Scanner::ConstToken:
+ if (seenStar) { // "int *const": Last indirection is const.
+ auto indirections = stack.top().indirectionsV();
+ Q_ASSERT(!indirections.isEmpty());
+ indirections[0] = Indirection::ConstPointer;
+ stack.top().setIndirectionsV(indirections);
+ } else {
+ stack.top().setConstant(true);
+ }
+ break;
+
+ case Scanner::VolatileToken:
+ stack.top().setVolatile(true);
+ break;
+
+ case Scanner::OpenParenToken: // function pointers not supported
+ case Scanner::CloseParenToken: {
+ const QString message = scanner.msgParseError("Function pointers are not supported"_L1);
+ if (errorMessage)
+ *errorMessage = message;
+ else
+ qWarning().noquote().nospace() << message;
+ return {};
+ }
+
+ case Scanner::Identifier:
+ if (in_array) {
+ array = scanner.identifier();
+ } else if (colon_prefix || stack.top().qualifiedName().isEmpty()) {
+ stack.top().addName(scanner.identifier());
+ colon_prefix = false;
+ } else {
+ QStringList qualifiedName = stack.top().qualifiedName();
+ qualifiedName.last().append(u' ' + scanner.identifier());
+ stack.top().setQualifiedName(qualifiedName);
+ }
+ break;
+
+ case Scanner::SquareBegin:
+ in_array = true;
+ break;
+
+ case Scanner::SquareEnd:
+ in_array = false;
+ stack.top().addArrayElement(array);
+ break;
+
+
+ default:
+ break;
+ }
+
+ tok = scanner.nextToken(errorMessage);
+ }
+
+ if (stack.isEmpty() || stack.constFirst().qualifiedName().isEmpty()) {
+ *errorMessage = u"Unable to parse type \""_s + str + u"\"."_s;
+ return {};
+ }
+ return stack.constFirst();
+}
diff --git a/sources/shiboken6/ApiExtractor/typeparser.h b/sources/shiboken6/ApiExtractor/typeparser.h
new file mode 100644
index 000000000..97634b5db
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typeparser.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPEPARSER_H
+#define TYPEPARSER_H
+
+#include <QtCore/QString>
+
+class TypeInfo;
+
+class TypeParser
+{
+public:
+ static TypeInfo parse(const QString &str, QString *errorMessage = nullptr);
+};
+
+#endif // TYPEPARSER_H
diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp
new file mode 100644
index 000000000..99d42b668
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typesystem.cpp
@@ -0,0 +1,2649 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "typesystem.h"
+#include "arraytypeentry.h"
+#include "codesnip.h"
+#include "complextypeentry.h"
+#include "configurabletypeentry.h"
+#include "constantvaluetypeentry.h"
+#include "containertypeentry.h"
+#include "customtypenentry.h"
+#include "debughelpers_p.h"
+#include "enumtypeentry.h"
+#include "enumvaluetypeentry.h"
+#include "flagstypeentry.h"
+#include "functiontypeentry.h"
+#include "include.h"
+#include "namespacetypeentry.h"
+#include "objecttypeentry.h"
+#include "primitivetypeentry.h"
+#include "pythontypeentry.h"
+#include "smartpointertypeentry.h"
+#include "templateargumententry.h"
+#include "typedefentry.h"
+#include "typesystemtypeentry.h"
+#include "valuetypeentry.h"
+#include "varargstypeentry.h"
+#include "voidtypeentry.h"
+#include "abstractmetatype.h"
+#include "typedatabase.h"
+#include "modifications.h"
+#include "sourcelocation.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QSet>
+#include <QtCore/QVarLengthArray>
+
+using namespace Qt::StringLiterals;
+
+static QString buildName(const QString &entryName, const TypeEntryCPtr &parent)
+{
+ return parent == nullptr || parent->type() == TypeEntry::TypeSystemType
+ ? entryName : parent->name() + u"::"_s + entryName;
+}
+
+// Access private class as 'd', cf macro Q_D()
+#define S_D(Class) auto d = static_cast<Class##Private *>(d_func())
+
+class TypeEntryPrivate
+{
+public:
+ TypeEntryPrivate(const TypeEntryPrivate &) = default; // Enable copy for cloning.
+ TypeEntryPrivate &operator=(const TypeEntryPrivate &) = delete;
+ TypeEntryPrivate(TypeEntryPrivate &&) = delete;
+ TypeEntryPrivate &operator=(TypeEntryPrivate &&) = delete;
+
+ explicit TypeEntryPrivate(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+ virtual ~TypeEntryPrivate() = default;
+
+ QString shortName() const;
+
+ TypeEntryCPtr m_parent;
+ QString m_name; // C++ fully qualified
+ mutable QString m_cachedShortName; // C++ excluding inline namespaces
+ QString m_entryName;
+ QString m_targetLangPackage;
+ mutable QString m_cachedTargetLangName; // "Foo.Bar"
+ mutable QString m_cachedTargetLangEntryName; // "Bar"
+ IncludeList m_extraIncludes;
+ Include m_include;
+ QVersionNumber m_version;
+ SourceLocation m_sourceLocation; // XML file
+ TypeEntry::CodeGeneration m_codeGeneration = TypeEntry::GenerateCode;
+ TypeEntryPtr m_viewOn;
+ CustomTypeEntryPtr m_targetLangApiType;
+ int m_revision = 0;
+ int m_sbkIndex = 0;
+ TypeEntry::Type m_type;
+ bool m_stream = false;
+ bool m_private = false;
+ bool m_builtin = false;
+};
+
+TypeEntryPrivate::TypeEntryPrivate(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ m_parent(parent),
+ m_name(buildName(entryName, parent)),
+ m_entryName(entryName),
+ m_version(vr),
+ m_type(t)
+{
+}
+
+TypeEntry::TypeEntry(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(new TypeEntryPrivate(entryName, t, vr, parent))
+{
+}
+
+TypeEntry::TypeEntry(TypeEntryPrivate *d) : m_d(d)
+{
+}
+
+TypeEntry::~TypeEntry() = default;
+
+const IncludeList &TypeEntry::extraIncludes() const
+{
+ return m_d->m_extraIncludes;
+}
+
+void TypeEntry::setExtraIncludes(const IncludeList &includes)
+{
+ m_d->m_extraIncludes = includes;
+}
+
+void TypeEntry::addExtraInclude(const Include &newInclude)
+{
+ if (!m_d->m_extraIncludes.contains(newInclude))
+ m_d->m_extraIncludes.append(newInclude);
+}
+
+Include TypeEntry::include() const
+{
+ return m_d->m_include;
+}
+
+void TypeEntry::setInclude(const Include &inc)
+{
+ // This is a workaround for preventing double inclusion of the QSharedPointer implementation
+ // header, which does not use header guards. In the previous parser this was not a problem
+ // because the Q_QDOC define was set, and the implementation header was never included.
+ if (inc.name().endsWith(u"qsharedpointer_impl.h")) {
+ QString path = inc.name();
+ path.remove(u"_impl"_s);
+ m_d->m_include = Include(inc.type(), path);
+ } else {
+ m_d->m_include = inc;
+ }
+}
+
+QVersionNumber TypeEntry::version() const
+{
+ return m_d->m_version;
+}
+
+bool isCppPrimitive(const TypeEntryCPtr &e)
+{
+ if (!e->isPrimitive())
+ return false;
+
+ if (e->type() == TypeEntry::VoidType)
+ return true;
+
+ PrimitiveTypeEntryCPtr referencedType = basicReferencedTypeEntry(e);
+ const QString &typeName = referencedType->name();
+ return AbstractMetaType::cppPrimitiveTypes().contains(typeName);
+}
+
+TypeEntry::Type TypeEntry::type() const
+{
+ return m_d->m_type;
+}
+
+TypeEntryCPtr TypeEntry::parent() const
+{
+ return m_d->m_parent;
+}
+
+void TypeEntry::setParent(const TypeEntryCPtr &p)
+{
+ m_d->m_parent = p;
+}
+
+bool TypeEntry::isChildOf(const TypeEntryCPtr &p) const
+{
+ for (auto e = m_d->m_parent; e; e = e->parent()) {
+ if (e == p)
+ return true;
+ }
+ return false;
+}
+
+TypeSystemTypeEntryCPtr typeSystemTypeEntry(TypeEntryCPtr e)
+{
+ for (; e; e = e->parent()) {
+ if (e->type() == TypeEntry::TypeSystemType)
+ return std::static_pointer_cast<const TypeSystemTypeEntry>(e);
+ }
+ return {};
+}
+
+TypeEntryCPtr targetLangEnclosingEntry(const TypeEntryCPtr &e)
+{
+ auto result = e->parent();
+ while (result && result->type() != TypeEntry::TypeSystemType
+ && !NamespaceTypeEntry::isVisibleScope(result)) {
+ result = result->parent();
+ }
+ return result;
+}
+
+bool TypeEntry::isPrimitive() const
+{
+ return m_d->m_type == PrimitiveType;
+}
+
+bool TypeEntry::isEnum() const
+{
+ return m_d->m_type == EnumType;
+}
+
+bool TypeEntry::isFlags() const
+{
+ return m_d->m_type == FlagsType;
+}
+
+bool TypeEntry::isObject() const
+{
+ return m_d->m_type == ObjectType;
+}
+
+bool TypeEntry::isNamespace() const
+{
+ return m_d->m_type == NamespaceType;
+}
+
+bool TypeEntry::isContainer() const
+{
+ return m_d->m_type == ContainerType;
+}
+
+bool TypeEntry::isSmartPointer() const
+{
+ return m_d->m_type == SmartPointerType;
+}
+
+bool TypeEntry::isUniquePointer() const
+{
+ if (m_d->m_type != SmartPointerType)
+ return false;
+ auto *ste = static_cast<const SmartPointerTypeEntry *>(this);
+ return ste->smartPointerType() == TypeSystem::SmartPointerType::Unique;
+}
+
+bool TypeEntry::isArray() const
+{
+ return m_d->m_type == ArrayType;
+}
+
+bool TypeEntry::isTemplateArgument() const
+{
+ return m_d->m_type == TemplateArgumentType;
+}
+
+bool TypeEntry::isVoid() const
+{
+ return m_d->m_type == VoidType;
+}
+
+bool TypeEntry::isVarargs() const
+{
+ return m_d->m_type == VarargsType;
+}
+
+bool TypeEntry::isCustom() const
+{
+ return m_d->m_type == CustomType || m_d->m_type == PythonType;
+}
+
+bool TypeEntry::isTypeSystem() const
+{
+ return m_d->m_type == TypeSystemType;
+}
+
+bool TypeEntry::isFunction() const
+{
+ return m_d->m_type == FunctionType;
+}
+
+bool TypeEntry::isEnumValue() const
+{
+ return m_d->m_type == EnumValue;
+}
+
+bool TypeEntry::stream() const
+{
+ return m_d->m_stream;
+}
+
+void TypeEntry::setStream(bool b)
+{
+ m_d->m_stream = b;
+}
+
+bool TypeEntry::isBuiltIn() const
+{
+ return m_d->m_builtin;
+}
+
+void TypeEntry::setBuiltIn(bool b)
+{
+ m_d->m_builtin = b;
+}
+
+bool TypeEntry::isPrivate() const
+{
+ return m_d->m_private;
+}
+
+void TypeEntry::setPrivate(bool b)
+{
+ m_d->m_private = b;
+}
+
+QString TypeEntry::name() const
+{
+ return m_d->m_name;
+}
+
+// Build the C++ name excluding any inline namespaces
+// ("std::__1::shared_ptr" -> "std::shared_ptr"
+QString TypeEntryPrivate::shortName() const
+{
+ if (m_cachedShortName.isEmpty()) {
+ QVarLengthArray<TypeEntryCPtr > parents;
+ bool foundInlineNamespace = false;
+ for (auto p = m_parent; p != nullptr && p->type() != TypeEntry::TypeSystemType; p = p->parent()) {
+ if (p->type() == TypeEntry::NamespaceType
+ && std::static_pointer_cast<const NamespaceTypeEntry>(p)->isInlineNamespace()) {
+ foundInlineNamespace = true;
+ } else {
+ parents.append(p);
+ }
+ }
+ if (foundInlineNamespace) {
+ m_cachedShortName.reserve(m_name.size());
+ for (auto i = parents.size() - 1; i >= 0; --i) {
+ m_cachedShortName.append(parents.at(i)->entryName());
+ m_cachedShortName.append(u"::"_s);
+ }
+ m_cachedShortName.append(m_entryName);
+ } else {
+ m_cachedShortName = m_name;
+ }
+ }
+ return m_cachedShortName;
+}
+
+QString TypeEntry::shortName() const
+{
+ return m_d->shortName();
+}
+
+QString TypeEntry::entryName() const
+{
+ return m_d->m_entryName;
+}
+
+TypeEntry::CodeGeneration TypeEntry::codeGeneration() const
+{
+ return m_d->m_codeGeneration;
+}
+
+void TypeEntry::setCodeGeneration(TypeEntry::CodeGeneration cg)
+{
+ m_d->m_codeGeneration = cg;
+}
+
+bool TypeEntry::generateCode() const
+{
+ return m_d->m_codeGeneration == GenerateCode;
+}
+
+bool TypeEntry::shouldGenerate() const
+{
+ return generateCode() && NamespaceTypeEntry::isVisibleScope(this);
+}
+
+int TypeEntry::revision() const
+{
+ return m_d->m_revision;
+}
+
+void TypeEntry::setSbkIndex(int i)
+{
+ m_d->m_sbkIndex = i;
+}
+
+QString TypeEntry::qualifiedCppName() const
+{
+ return m_d->m_name;
+}
+
+CustomTypeEntryCPtr TypeEntry::targetLangApiType() const
+{
+ return m_d->m_targetLangApiType;
+}
+
+bool TypeEntry::hasTargetLangApiType() const
+{
+ return m_d->m_targetLangApiType != nullptr;
+}
+
+void TypeEntry::setTargetLangApiType(const CustomTypeEntryPtr &cte)
+{
+ m_d->m_targetLangApiType = cte;
+}
+
+QString TypeEntry::targetLangApiName() const
+{
+ return m_d->m_targetLangApiType != nullptr
+ ? m_d->m_targetLangApiType->name() : m_d->m_name;
+}
+
+QString TypeEntry::targetLangName() const
+{
+ if (m_d->m_cachedTargetLangName.isEmpty())
+ m_d->m_cachedTargetLangName = buildTargetLangName();
+ return m_d->m_cachedTargetLangName;
+}
+
+void TypeEntry::setTargetLangName(const QString &n)
+{
+ m_d->m_cachedTargetLangName = n;
+}
+
+QString TypeEntry::buildTargetLangName() const
+{
+ QString result = m_d->m_entryName;
+ for (auto p = parent(); p && p->type() != TypeEntry::TypeSystemType; p = p->parent()) {
+ if (NamespaceTypeEntry::isVisibleScope(p)) {
+ if (!result.isEmpty())
+ result.prepend(u'.');
+ QString n = p->m_d->m_entryName;
+ n.replace(u"::"_s, u"."_s); // Primitive types may have "std::"
+ result.prepend(n);
+ }
+ }
+ return result;
+}
+
+bool TypeEntry::setRevisionHelper(int r)
+{
+ const bool changed = m_d->m_revision != r;
+ m_d->m_revision = r;
+ return changed;
+}
+
+int TypeEntry::sbkIndexHelper() const
+{
+ return m_d->m_sbkIndex;
+}
+
+SourceLocation TypeEntry::sourceLocation() const
+{
+ return m_d->m_sourceLocation;
+}
+
+void TypeEntry::setSourceLocation(const SourceLocation &sourceLocation)
+{
+ m_d->m_sourceLocation = sourceLocation;
+}
+
+bool isUserPrimitive(const TypeEntryCPtr &e)
+{
+ if (!e->isPrimitive())
+ return false;
+ const auto type = basicReferencedTypeEntry(e);
+ return !isCppPrimitive(type)
+ && type->qualifiedCppName() != u"std::string";
+}
+
+bool TypeEntry::isWrapperType() const
+{
+ return isObject() || isValue() || isSmartPointer();
+}
+
+bool isCppIntegralPrimitive(const TypeEntryCPtr &e)
+{
+ if (!isCppPrimitive(e))
+ return false;
+ const auto type = basicReferencedTypeEntry(e);
+ return AbstractMetaType::cppIntegralTypes().contains(type->qualifiedCppName());
+}
+
+bool isExtendedCppPrimitive(const TypeEntryCPtr &e)
+{
+ if (isCppPrimitive(e))
+ return true;
+ if (!e->isPrimitive())
+ return false;
+ const auto type = basicReferencedTypeEntry(e);
+ const QString &name = type->qualifiedCppName();
+ return name == u"std::string" || name == u"std::wstring";
+}
+
+const TypeEntryPrivate *TypeEntry::d_func() const
+{
+ return m_d.data();
+}
+
+TypeEntryPrivate *TypeEntry::d_func()
+{
+ return m_d.data();
+}
+
+QString TypeEntry::targetLangEntryName() const
+{
+ if (m_d->m_cachedTargetLangEntryName.isEmpty()) {
+ m_d->m_cachedTargetLangEntryName = targetLangName();
+ const int lastDot = m_d->m_cachedTargetLangEntryName.lastIndexOf(u'.');
+ if (lastDot != -1)
+ m_d->m_cachedTargetLangEntryName.remove(0, lastDot + 1);
+ }
+ return m_d->m_cachedTargetLangEntryName;
+}
+
+QString TypeEntry::targetLangPackage() const
+{
+ return m_d->m_targetLangPackage;
+}
+
+void TypeEntry::setTargetLangPackage(const QString &p)
+{
+ m_d->m_targetLangPackage = p;
+}
+
+QString TypeEntry::qualifiedTargetLangName() const
+{
+ return targetLangPackage() + u'.' + targetLangName();
+}
+
+bool TypeEntry::isValue() const
+{
+ return false;
+}
+
+bool TypeEntry::isComplex() const
+{
+ return false;
+}
+
+TypeEntryPtr TypeEntry::viewOn() const
+{
+ return m_d->m_viewOn;
+}
+
+void TypeEntry::setViewOn(const TypeEntryPtr &v)
+{
+ m_d->m_viewOn = v;
+}
+
+TypeEntry *TypeEntry::clone() const
+{
+ return new TypeEntry(new TypeEntryPrivate(*m_d.data()));
+}
+
+// Take over parameters relevant for typedefs
+void TypeEntry::useAsTypedef(const TypeEntryCPtr &source)
+{
+ // XML Typedefs are in the global namespace for now.
+ m_d->m_parent = typeSystemTypeEntry(source);
+ m_d->m_entryName = source->m_d->m_entryName;
+ m_d->m_name = source->m_d->m_name;
+ m_d->m_targetLangPackage = source->m_d->m_targetLangPackage;
+ m_d->m_cachedTargetLangName.clear(); // Clear cached names.
+ m_d->m_cachedTargetLangEntryName.clear();
+ m_d->m_codeGeneration = source->m_d->m_codeGeneration;
+ m_d->m_version = source->m_d->m_version;
+}
+
+// ----------------- CustomTypeEntry
+class CustomTypeEntryPrivate : public TypeEntryPrivate
+{
+public:
+ using TypeEntryPrivate::TypeEntryPrivate;
+
+ QString m_checkFunction;
+};
+
+CustomTypeEntry::CustomTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(new CustomTypeEntryPrivate(entryName, CustomType, vr, parent))
+{
+}
+
+CustomTypeEntry::CustomTypeEntry(TypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+TypeEntry *CustomTypeEntry::clone() const
+{
+ S_D(const CustomTypeEntry);
+ return new CustomTypeEntry(new CustomTypeEntryPrivate(*d));
+}
+
+bool CustomTypeEntry::hasCheckFunction() const
+{
+ S_D(const CustomTypeEntry);
+ return !d->m_checkFunction.isEmpty();
+}
+
+QString CustomTypeEntry::checkFunction() const
+{
+ S_D(const CustomTypeEntry);
+ return d->m_checkFunction;
+}
+
+void CustomTypeEntry::setCheckFunction(const QString &f)
+{
+ S_D(CustomTypeEntry);
+ d->m_checkFunction = f;
+}
+
+// ----------------- PythonTypeEntry
+class PythonTypeEntryPrivate : public CustomTypeEntryPrivate
+{
+public:
+ using CustomTypeEntryPrivate::CustomTypeEntryPrivate;
+ explicit PythonTypeEntryPrivate(const QString &entryName,
+ const QString &checkFunction,
+ TypeSystem::CPythonType type) :
+ CustomTypeEntryPrivate(entryName, TypeEntry::PythonType, {}, {}),
+ m_cPythonType(type)
+ {
+ m_checkFunction = checkFunction;
+ }
+
+ TypeSystem::CPythonType m_cPythonType;
+};
+
+PythonTypeEntry::PythonTypeEntry(const QString &entryName,
+ const QString &checkFunction,
+ TypeSystem::CPythonType type) :
+ CustomTypeEntry(new PythonTypeEntryPrivate(entryName, checkFunction, type))
+{
+}
+
+TypeEntry *PythonTypeEntry::clone() const
+{
+ S_D(const PythonTypeEntry);
+ return new PythonTypeEntry(new PythonTypeEntryPrivate(*d));
+}
+
+TypeSystem::CPythonType PythonTypeEntry::cPythonType() const
+{
+ S_D(const PythonTypeEntry);
+ return d->m_cPythonType;
+}
+
+PythonTypeEntry::PythonTypeEntry(TypeEntryPrivate *d) :
+ CustomTypeEntry(d)
+{
+}
+
+// ----------------- TypeSystemTypeEntry
+class TypeSystemTypeEntryPrivate : public TypeEntryPrivate
+{
+public:
+ using TypeEntryPrivate::TypeEntryPrivate;
+
+ CodeSnipList m_codeSnips;
+ TypeSystem::SnakeCase m_snakeCase = TypeSystem::SnakeCase::Disabled;
+ QString m_subModuleOf;
+ QString m_namespaceBegin;
+ QString m_namespaceEnd;
+};
+
+TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(new TypeSystemTypeEntryPrivate(entryName, TypeSystemType, vr, parent))
+{
+}
+
+TypeSystemTypeEntry::TypeSystemTypeEntry(TypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+TypeEntry *TypeSystemTypeEntry::clone() const
+{
+ S_D(const TypeSystemTypeEntry);
+ return new TypeSystemTypeEntry(new TypeSystemTypeEntryPrivate(*d));
+}
+
+const CodeSnipList &TypeSystemTypeEntry::codeSnips() const
+{
+ S_D(const TypeSystemTypeEntry);
+ return d->m_codeSnips;
+}
+
+CodeSnipList &TypeSystemTypeEntry::codeSnips()
+{
+ S_D(TypeSystemTypeEntry);
+ return d->m_codeSnips;
+}
+
+void TypeSystemTypeEntry::addCodeSnip(const CodeSnip &codeSnip)
+{
+ S_D(TypeSystemTypeEntry);
+ d->m_codeSnips.append(codeSnip);
+}
+
+QString TypeSystemTypeEntry::subModuleOf() const
+{
+ S_D(const TypeSystemTypeEntry);
+ return d->m_subModuleOf;
+}
+
+void TypeSystemTypeEntry::setSubModule(const QString &s)
+{
+ S_D(TypeSystemTypeEntry);
+ d->m_subModuleOf = s;
+}
+
+const QString &TypeSystemTypeEntry::namespaceBegin() const
+{
+ S_D(const TypeSystemTypeEntry);
+ return d->m_namespaceBegin;
+}
+
+void TypeSystemTypeEntry::setNamespaceBegin(const QString &p)
+{
+ S_D(TypeSystemTypeEntry);
+ d->m_namespaceBegin = p;
+}
+
+const QString &TypeSystemTypeEntry::namespaceEnd() const
+{
+ S_D(const TypeSystemTypeEntry);
+ return d->m_namespaceEnd;
+}
+
+void TypeSystemTypeEntry::setNamespaceEnd(const QString &n)
+{
+ S_D(TypeSystemTypeEntry);
+ d->m_namespaceEnd = n;
+}
+
+TypeSystem::SnakeCase TypeSystemTypeEntry::snakeCase() const
+{
+ S_D(const TypeSystemTypeEntry);
+ return d->m_snakeCase;
+}
+
+void TypeSystemTypeEntry::setSnakeCase(TypeSystem::SnakeCase sc)
+{
+ S_D(TypeSystemTypeEntry);
+ d->m_snakeCase = sc;
+}
+
+// ----------------- VoidTypeEntry
+VoidTypeEntry::VoidTypeEntry() :
+ TypeEntry(u"void"_s, VoidType, QVersionNumber(0, 0), nullptr)
+{
+}
+
+VoidTypeEntry::VoidTypeEntry(TypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+TypeEntry *VoidTypeEntry::clone() const
+{
+ return new VoidTypeEntry(new TypeEntryPrivate(*d_func()));
+}
+
+VarargsTypeEntry::VarargsTypeEntry() :
+ TypeEntry(u"..."_s, VarargsType, QVersionNumber(0, 0), nullptr)
+{
+}
+
+// ----------------- VarargsTypeEntry
+TypeEntry *VarargsTypeEntry::clone() const
+{
+ return new VarargsTypeEntry(new TypeEntryPrivate(*d_func()));
+}
+
+VarargsTypeEntry::VarargsTypeEntry(TypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+// ----------------- TemplateArgumentEntry
+class TemplateArgumentEntryPrivate : public TypeEntryPrivate
+{
+public:
+ using TypeEntryPrivate::TypeEntryPrivate;
+
+ int m_ordinal = 0;
+};
+
+TemplateArgumentEntry::TemplateArgumentEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(new TemplateArgumentEntryPrivate(entryName, TemplateArgumentType, vr, parent))
+{
+}
+
+int TemplateArgumentEntry::ordinal() const
+{
+ S_D(const TemplateArgumentEntry);
+ return d->m_ordinal;
+}
+
+void TemplateArgumentEntry::setOrdinal(int o)
+{
+ S_D(TemplateArgumentEntry);
+ d->m_ordinal = o;
+}
+
+TypeEntry *TemplateArgumentEntry::clone() const
+{
+ S_D(const TemplateArgumentEntry);
+ return new TemplateArgumentEntry(new TemplateArgumentEntryPrivate(*d));
+}
+
+TemplateArgumentEntry::TemplateArgumentEntry(TemplateArgumentEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+// ----------------- ArrayTypeEntry
+class ArrayTypeEntryPrivate : public TypeEntryPrivate
+{
+public:
+ explicit ArrayTypeEntryPrivate(const TypeEntryCPtr &nested_type, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntryPrivate(u"Array"_s, TypeEntry::ArrayType, vr, parent),
+ m_nestedType(nested_type)
+ {
+ }
+
+ TypeEntryCPtr m_nestedType;
+};
+
+ArrayTypeEntry::ArrayTypeEntry(const TypeEntryCPtr &nested_type, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(new ArrayTypeEntryPrivate(nested_type, vr, parent))
+{
+ Q_ASSERT(nested_type);
+}
+
+void ArrayTypeEntry::setNestedTypeEntry(const TypeEntryPtr &nested)
+{
+ S_D(ArrayTypeEntry);
+ d->m_nestedType = nested;
+}
+
+TypeEntryCPtr ArrayTypeEntry::nestedTypeEntry() const
+{
+ S_D(const ArrayTypeEntry);
+ return d->m_nestedType;
+}
+
+QString ArrayTypeEntry::buildTargetLangName() const
+{
+ S_D(const ArrayTypeEntry);
+ return d->m_nestedType->targetLangName() + u"[]"_s;
+}
+
+TypeEntry *ArrayTypeEntry::clone() const
+{
+ S_D(const ArrayTypeEntry);
+ return new ArrayTypeEntry(new ArrayTypeEntryPrivate(*d));
+}
+
+ArrayTypeEntry::ArrayTypeEntry(ArrayTypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+// ----------------- PrimitiveTypeEntry
+class PrimitiveTypeEntryPrivate : public TypeEntryPrivate
+{
+public:
+ PrimitiveTypeEntryPrivate(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntryPrivate(entryName, TypeEntry::PrimitiveType, vr, parent),
+ m_preferredTargetLangType(true)
+ {
+ }
+
+ QString m_defaultConstructor;
+ CustomConversionPtr m_customConversion;
+ PrimitiveTypeEntryPtr m_referencedTypeEntry;
+ uint m_preferredTargetLangType : 1;
+};
+
+PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(new PrimitiveTypeEntryPrivate(entryName, vr, parent))
+{
+}
+
+QString PrimitiveTypeEntry::defaultConstructor() const
+{
+ S_D(const PrimitiveTypeEntry);
+ return d->m_defaultConstructor;
+}
+
+void PrimitiveTypeEntry::setDefaultConstructor(const QString &defaultConstructor)
+{
+ S_D(PrimitiveTypeEntry);
+ d->m_defaultConstructor = defaultConstructor;
+}
+
+bool PrimitiveTypeEntry::hasDefaultConstructor() const
+{
+ S_D(const PrimitiveTypeEntry);
+ return !d->m_defaultConstructor.isEmpty();
+}
+
+PrimitiveTypeEntryPtr PrimitiveTypeEntry::referencedTypeEntry() const
+{
+ S_D(const PrimitiveTypeEntry);
+ return d->m_referencedTypeEntry;
+}
+
+void PrimitiveTypeEntry::setReferencedTypeEntry(PrimitiveTypeEntryPtr referencedTypeEntry)
+{
+ S_D(PrimitiveTypeEntry);
+ d->m_referencedTypeEntry = referencedTypeEntry;
+}
+
+PrimitiveTypeEntryCPtr basicReferencedTypeEntry(const PrimitiveTypeEntryCPtr &e)
+{
+ auto result = e;
+ while (auto referenced = result->referencedTypeEntry())
+ result = referenced;
+ return result;
+}
+
+PrimitiveTypeEntryCPtr basicReferencedTypeEntry(const TypeEntryCPtr &e)
+{
+ Q_ASSERT(e->isPrimitive());
+ return basicReferencedTypeEntry(std::static_pointer_cast<const PrimitiveTypeEntry>(e));
+}
+
+PrimitiveTypeEntryCPtr basicReferencedNonBuiltinTypeEntry(const PrimitiveTypeEntryCPtr &e)
+{
+ auto result = e;
+ for (; result->referencedTypeEntry() ; result = result->referencedTypeEntry()) {
+ if (!result->isBuiltIn())
+ break;
+ }
+ return result;
+}
+
+bool PrimitiveTypeEntry::referencesType() const
+{
+ S_D(const PrimitiveTypeEntry);
+ return d->m_referencedTypeEntry != nullptr;
+}
+
+bool PrimitiveTypeEntry::preferredTargetLangType() const
+{
+ S_D(const PrimitiveTypeEntry);
+ return d->m_preferredTargetLangType;
+}
+
+void PrimitiveTypeEntry::setPreferredTargetLangType(bool b)
+{
+ S_D(PrimitiveTypeEntry);
+ d->m_preferredTargetLangType = b;
+}
+
+bool PrimitiveTypeEntry::hasCustomConversion() const
+{
+ S_D(const PrimitiveTypeEntry);
+ return bool(d->m_customConversion);
+}
+
+void PrimitiveTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion)
+{
+ S_D(PrimitiveTypeEntry);
+ d->m_customConversion = customConversion;
+}
+
+CustomConversionPtr PrimitiveTypeEntry::customConversion() const
+{
+ S_D(const PrimitiveTypeEntry);
+ return d->m_customConversion;
+}
+
+TypeEntry *PrimitiveTypeEntry::clone() const
+{
+ S_D(const PrimitiveTypeEntry);
+ return new PrimitiveTypeEntry(new PrimitiveTypeEntryPrivate(*d));
+}
+
+PrimitiveTypeEntry::PrimitiveTypeEntry(PrimitiveTypeEntryPrivate *d)
+ : TypeEntry(d)
+{
+}
+
+// ----------------- ConfigurableTypeEntry
+
+class ConfigurableTypeEntryPrivate : public TypeEntryPrivate
+{
+public:
+ using TypeEntryPrivate::TypeEntryPrivate;
+
+ QString m_configCondition;
+};
+
+ConfigurableTypeEntry::ConfigurableTypeEntry(const QString &entryName, Type t,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(new ConfigurableTypeEntryPrivate(entryName, t, vr, parent))
+{
+}
+
+ConfigurableTypeEntry::ConfigurableTypeEntry(ConfigurableTypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+TypeEntry *ConfigurableTypeEntry::clone() const
+{
+ S_D(const ConfigurableTypeEntry);
+ return new ConfigurableTypeEntry(new ConfigurableTypeEntryPrivate(*d));
+}
+
+QString ConfigurableTypeEntry::configCondition() const
+{
+ S_D(const ConfigurableTypeEntry);
+ return d->m_configCondition;
+}
+
+void ConfigurableTypeEntry::setConfigCondition(const QString &c)
+{
+ S_D(ConfigurableTypeEntry);
+ d->m_configCondition = c;
+ if (!d->m_configCondition.startsWith(u'#'))
+ d->m_configCondition.prepend(u"#if ");
+}
+
+bool ConfigurableTypeEntry::hasConfigCondition() const
+{
+ S_D(const ConfigurableTypeEntry);
+ return !d->m_configCondition.isEmpty();
+}
+
+// ----------------- EnumTypeEntry
+class EnumTypeEntryPrivate : public ConfigurableTypeEntryPrivate
+{
+public:
+ using ConfigurableTypeEntryPrivate::ConfigurableTypeEntryPrivate;
+
+ EnumValueTypeEntryCPtr m_nullValue;
+ QStringList m_rejectedEnums;
+ FlagsTypeEntryPtr m_flags;
+ QString m_cppType;
+ QString m_docFile;
+ TypeSystem::PythonEnumType m_pythonEnumType = TypeSystem::PythonEnumType::Unspecified;
+};
+
+EnumTypeEntry::EnumTypeEntry(const QString &entryName,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ConfigurableTypeEntry(new EnumTypeEntryPrivate(entryName, EnumType, vr, parent))
+{
+}
+
+TypeSystem::PythonEnumType EnumTypeEntry::pythonEnumType() const
+{
+ S_D(const EnumTypeEntry);
+ return d->m_pythonEnumType;
+}
+
+void EnumTypeEntry::setPythonEnumType(TypeSystem::PythonEnumType t)
+{
+ S_D(EnumTypeEntry);
+ d->m_pythonEnumType = t;
+}
+
+QString EnumTypeEntry::targetLangQualifier() const
+{
+ const QString q = qualifier();
+ if (!q.isEmpty()) {
+ if (auto te = TypeDatabase::instance()->findType(q))
+ return te->targetLangName();
+ }
+ return q;
+}
+
+QString EnumTypeEntry::qualifier() const
+{
+ auto parentEntry = parent();
+ return parentEntry && parentEntry->type() != TypeEntry::TypeSystemType ?
+ parentEntry->name() : QString();
+}
+
+EnumValueTypeEntryCPtr EnumTypeEntry::nullValue() const
+{
+ S_D(const EnumTypeEntry);
+ return d->m_nullValue;
+}
+
+void EnumTypeEntry::setNullValue(const EnumValueTypeEntryCPtr &n)
+{
+ S_D(EnumTypeEntry);
+ d->m_nullValue = n;
+}
+
+void EnumTypeEntry::setFlags(const FlagsTypeEntryPtr &flags)
+{
+ S_D(EnumTypeEntry);
+ d->m_flags = flags;
+}
+
+FlagsTypeEntryPtr EnumTypeEntry::flags() const
+{
+ S_D(const EnumTypeEntry);
+ return d->m_flags;
+}
+
+QString EnumTypeEntry::cppType() const
+{
+ S_D(const EnumTypeEntry);
+ return d->m_cppType;
+}
+
+void EnumTypeEntry::setCppType(const QString &t)
+{
+ S_D(EnumTypeEntry);
+ d->m_cppType = t;
+}
+
+bool EnumTypeEntry::isEnumValueRejected(const QString &name) const
+{
+ S_D(const EnumTypeEntry);
+ return d->m_rejectedEnums.contains(name);
+}
+
+void EnumTypeEntry::addEnumValueRejection(const QString &name)
+{
+ S_D(EnumTypeEntry);
+ d->m_rejectedEnums << name;
+}
+
+QStringList EnumTypeEntry::enumValueRejections() const
+{
+ S_D(const EnumTypeEntry);
+ return d->m_rejectedEnums;
+}
+
+QString EnumTypeEntry::docFile() const
+{
+ S_D(const EnumTypeEntry);
+ return d->m_docFile;
+}
+
+void EnumTypeEntry::setDocFile(const QString &df)
+{
+ S_D(EnumTypeEntry);
+ d->m_docFile = df;
+}
+
+TypeEntry *EnumTypeEntry::clone() const
+{
+ S_D(const EnumTypeEntry);
+ return new EnumTypeEntry(new EnumTypeEntryPrivate(*d));
+}
+
+EnumTypeEntry::EnumTypeEntry(EnumTypeEntryPrivate *d) :
+ ConfigurableTypeEntry(d)
+{
+}
+
+// ----------------- EnumValueTypeEntryPrivate
+class EnumValueTypeEntryPrivate : public TypeEntryPrivate
+{
+public:
+ EnumValueTypeEntryPrivate(const QString &name, const QString &value,
+ const EnumTypeEntryCPtr &enclosingEnum,
+ bool isScopedEnum,
+ const QVersionNumber &vr) :
+ TypeEntryPrivate(name, TypeEntry::EnumValue, vr,
+ isScopedEnum ? enclosingEnum : enclosingEnum->parent()),
+ m_value(value),
+ m_enclosingEnum(enclosingEnum)
+ {
+ }
+
+ QString m_value;
+ EnumTypeEntryCPtr m_enclosingEnum;
+};
+
+EnumValueTypeEntry::EnumValueTypeEntry(const QString &name, const QString &value,
+ const EnumTypeEntryCPtr &enclosingEnum,
+ bool isScopedEnum,
+ const QVersionNumber &vr) :
+ TypeEntry(new EnumValueTypeEntryPrivate(name, value, enclosingEnum, isScopedEnum, vr))
+{
+}
+
+QString EnumValueTypeEntry::value() const
+{
+ S_D(const EnumValueTypeEntry);
+ return d->m_value;
+}
+
+EnumTypeEntryCPtr EnumValueTypeEntry::enclosingEnum() const
+{
+ S_D(const EnumValueTypeEntry);
+ return d->m_enclosingEnum;
+}
+
+TypeEntry *EnumValueTypeEntry::clone() const
+{
+ S_D(const EnumValueTypeEntry);
+ return new EnumValueTypeEntry(new EnumValueTypeEntryPrivate(*d));
+}
+
+EnumValueTypeEntry::EnumValueTypeEntry(EnumValueTypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+// ----------------- FlagsTypeEntry
+class FlagsTypeEntryPrivate : public TypeEntryPrivate
+{
+public:
+ using TypeEntryPrivate::TypeEntryPrivate;
+
+ QString m_originalName;
+ QString m_flagsName;
+ EnumTypeEntryPtr m_enum;
+};
+
+FlagsTypeEntry::FlagsTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(new FlagsTypeEntryPrivate(entryName, FlagsType, vr, parent))
+{
+}
+
+QString FlagsTypeEntry::buildTargetLangName() const
+{
+ S_D(const FlagsTypeEntry);
+ QString on = d->m_originalName;
+ on.replace(u"::"_s, u"."_s);
+ return on;
+}
+
+FlagsTypeEntry::FlagsTypeEntry(FlagsTypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+QString FlagsTypeEntry::originalName() const
+{
+ S_D(const FlagsTypeEntry);
+ return d->m_originalName;
+}
+
+void FlagsTypeEntry::setOriginalName(const QString &s)
+{
+ S_D(FlagsTypeEntry);
+ d->m_originalName = s;
+}
+
+QString FlagsTypeEntry::flagsName() const
+{
+ S_D(const FlagsTypeEntry);
+ return d->m_flagsName;
+}
+
+void FlagsTypeEntry::setFlagsName(const QString &name)
+{
+ S_D(FlagsTypeEntry);
+ d->m_flagsName = name;
+}
+
+EnumTypeEntryPtr FlagsTypeEntry::originator() const
+{
+ S_D(const FlagsTypeEntry);
+ return d->m_enum;
+}
+
+void FlagsTypeEntry::setOriginator(const EnumTypeEntryPtr &e)
+{
+ S_D(FlagsTypeEntry);
+ d->m_enum = e;
+}
+
+TypeEntry *FlagsTypeEntry::clone() const
+{
+ S_D(const FlagsTypeEntry);
+ return new FlagsTypeEntry(new FlagsTypeEntryPrivate(*d));
+}
+
+// ----------------- ConstantValueTypeEntry
+ConstantValueTypeEntry::ConstantValueTypeEntry(const QString& name,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(name, ConstantValueType, QVersionNumber(0, 0), parent)
+{
+}
+
+ConstantValueTypeEntry::ConstantValueTypeEntry(TypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+// ----------------- ComplexTypeEntry
+class ComplexTypeEntryPrivate : public ConfigurableTypeEntryPrivate
+{
+public:
+ ComplexTypeEntryPrivate(const QString &entryName, TypeEntry::Type t,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ConfigurableTypeEntryPrivate(entryName, t, vr, parent),
+ m_qualifiedCppName(buildName(entryName, parent)),
+ m_polymorphicBase(false),
+ m_genericClass(false),
+ m_deleteInMainThread(false)
+ {
+ }
+
+ AddedFunctionList m_addedFunctions;
+ FunctionModificationList m_functionMods;
+ CodeSnipList m_codeSnips;
+ DocModificationList m_docModifications;
+ DocModificationList m_functionDocModifications;
+ IncludeList m_argumentIncludes;
+ QSet<QString> m_generateFunctions;
+ FieldModificationList m_fieldMods;
+ QList<TypeSystemProperty> m_properties;
+ QList<TypeSystemPyMethodDefEntry> m_PyMethodDefEntrys;
+ QString m_defaultConstructor;
+ QString m_defaultSuperclass;
+ QString m_qualifiedCppName;
+
+ uint m_polymorphicBase : 1;
+ uint m_genericClass : 1;
+ uint m_deleteInMainThread : 1;
+
+ QString m_polymorphicIdValue;
+ QString m_polymorphicNameFunction;
+ QString m_targetType;
+ ComplexTypeEntry::TypeFlags m_typeFlags;
+ ComplexTypeEntry::CopyableFlag m_copyableFlag = ComplexTypeEntry::Unknown;
+ QString m_hashFunction;
+
+ ComplexTypeEntryCPtr m_baseContainerType;
+ // For class functions
+ TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+ TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified;
+ TypeSystem::SnakeCase m_snakeCase = TypeSystem::SnakeCase::Unspecified;
+ TypeSystem::BoolCast m_operatorBoolMode = TypeSystem::BoolCast::Unspecified;
+ TypeSystem::BoolCast m_isNullMode = TypeSystem::BoolCast::Unspecified;
+ TypeSystem::QtMetaTypeRegistration m_qtMetaTypeRegistration =
+ TypeSystem::QtMetaTypeRegistration::Unspecified;
+ // Determined by AbstractMetaBuilder from the code model.
+ bool m_isValueTypeWithCopyConstructorOnly = false;
+};
+
+ComplexTypeEntry::ComplexTypeEntry(const QString &entryName, TypeEntry::Type t,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ConfigurableTypeEntry(new ComplexTypeEntryPrivate(entryName, t, vr, parent))
+{
+}
+
+bool ComplexTypeEntry::isComplex() const
+{
+ return true;
+}
+
+void ComplexTypeEntry::setTypeFlags(TypeFlags flags)
+{
+ S_D(ComplexTypeEntry);
+ d->m_typeFlags = flags;
+}
+
+TypeSystem::BoolCast ComplexTypeEntry::operatorBoolMode() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_operatorBoolMode;
+}
+
+void ComplexTypeEntry::setOperatorBoolMode(TypeSystem::BoolCast b)
+{
+ S_D(ComplexTypeEntry);
+ d->m_operatorBoolMode = b;
+}
+
+TypeSystem::BoolCast ComplexTypeEntry::isNullMode() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_isNullMode;
+}
+
+void ComplexTypeEntry::setIsNullMode(TypeSystem::BoolCast b)
+{
+ S_D(ComplexTypeEntry);
+ d->m_isNullMode = b;
+}
+
+ComplexTypeEntry::TypeFlags ComplexTypeEntry::typeFlags() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_typeFlags;
+}
+
+FunctionModificationList ComplexTypeEntry::functionModifications() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_functionMods;
+}
+
+void ComplexTypeEntry::setFunctionModifications(const FunctionModificationList &functionModifications)
+{
+ S_D(ComplexTypeEntry);
+ d->m_functionMods = functionModifications;
+}
+
+void ComplexTypeEntry::addFunctionModification(const FunctionModification &functionModification)
+{
+ S_D(ComplexTypeEntry);
+ d->m_functionMods << functionModification;
+}
+
+FunctionModificationList
+ ComplexTypeEntry::functionModifications(const QStringList &signatures) const
+{
+ S_D(const ComplexTypeEntry);
+ FunctionModificationList lst;
+ for (const auto &mod : std::as_const(d->m_functionMods)) {
+ if (mod.matches(signatures))
+ lst << mod;
+ }
+ return lst;
+}
+
+const CodeSnipList &ComplexTypeEntry::codeSnips() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_codeSnips;
+}
+
+CodeSnipList &ComplexTypeEntry::codeSnips()
+{
+ S_D(ComplexTypeEntry);
+ return d->m_codeSnips;
+}
+
+void ComplexTypeEntry::setCodeSnips(const CodeSnipList &codeSnips)
+{
+ S_D(ComplexTypeEntry);
+ d->m_codeSnips = codeSnips;
+}
+
+void ComplexTypeEntry::addCodeSnip(const CodeSnip &codeSnip)
+{
+ S_D(ComplexTypeEntry);
+ d->m_codeSnips << codeSnip;
+}
+
+void ComplexTypeEntry::setDocModification(const DocModificationList &docMods)
+{
+ S_D(ComplexTypeEntry);
+ for (const auto &m : docMods) {
+ if (m.signature().isEmpty())
+ d->m_docModifications << m;
+ else
+ d->m_functionDocModifications << m;
+ }
+}
+
+DocModificationList ComplexTypeEntry::docModifications() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_docModifications;
+}
+
+DocModificationList ComplexTypeEntry::functionDocModifications() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_functionDocModifications;
+}
+
+const IncludeList &ComplexTypeEntry::argumentIncludes() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_argumentIncludes;
+}
+
+void ComplexTypeEntry::addArgumentInclude(const Include &newInclude)
+{
+ S_D(ComplexTypeEntry);
+ IncludeGroup::appendInclude(newInclude, &d->m_argumentIncludes);
+}
+
+AddedFunctionList ComplexTypeEntry::addedFunctions() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_addedFunctions;
+}
+
+void ComplexTypeEntry::setAddedFunctions(const AddedFunctionList &addedFunctions)
+{
+ S_D(ComplexTypeEntry);
+ d->m_addedFunctions = addedFunctions;
+}
+
+void ComplexTypeEntry::addNewFunction(const AddedFunctionPtr &addedFunction)
+{
+ S_D(ComplexTypeEntry);
+ d->m_addedFunctions << addedFunction;
+}
+
+const QList<TypeSystemPyMethodDefEntry> &ComplexTypeEntry::addedPyMethodDefEntrys() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_PyMethodDefEntrys;
+}
+
+void ComplexTypeEntry::addPyMethodDef(const TypeSystemPyMethodDefEntry &p)
+{
+ S_D(ComplexTypeEntry);
+ d->m_PyMethodDefEntrys.append(p);
+}
+
+const QSet<QString> &ComplexTypeEntry::generateFunctions() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_generateFunctions;
+}
+
+void ComplexTypeEntry::setGenerateFunctions(const QSet<QString> &f)
+{
+ S_D(ComplexTypeEntry);
+ d->m_generateFunctions = f;
+}
+
+void ComplexTypeEntry::setFieldModifications(const FieldModificationList &mods)
+{
+ S_D(ComplexTypeEntry);
+ d->m_fieldMods = mods;
+}
+
+FieldModificationList ComplexTypeEntry::fieldModifications() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_fieldMods;
+}
+
+const QList<TypeSystemProperty> &ComplexTypeEntry::properties() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_properties;
+}
+
+void ComplexTypeEntry::addProperty(const TypeSystemProperty &p)
+{
+ S_D(ComplexTypeEntry);
+ d->m_properties.append(p);
+}
+
+QString ComplexTypeEntry::defaultSuperclass() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_defaultSuperclass;
+}
+
+void ComplexTypeEntry::setDefaultSuperclass(const QString &sc)
+{
+ S_D(ComplexTypeEntry);
+ d->m_defaultSuperclass = sc;
+}
+
+QString ComplexTypeEntry::qualifiedCppName() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_qualifiedCppName;
+}
+
+void ComplexTypeEntry::setIsPolymorphicBase(bool on)
+{
+ S_D(ComplexTypeEntry);
+ d->m_polymorphicBase = on;
+}
+
+bool ComplexTypeEntry::isPolymorphicBase() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_polymorphicBase;
+}
+
+void ComplexTypeEntry::setPolymorphicIdValue(const QString &value)
+{
+ S_D(ComplexTypeEntry);
+ d->m_polymorphicIdValue = value;
+}
+
+QString ComplexTypeEntry::polymorphicIdValue() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_polymorphicIdValue;
+}
+
+QString ComplexTypeEntry::polymorphicNameFunction() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_polymorphicNameFunction;
+}
+
+void ComplexTypeEntry::setPolymorphicNameFunction(const QString &n)
+{
+ S_D(ComplexTypeEntry);
+ d->m_polymorphicNameFunction = n;
+}
+
+QString ComplexTypeEntry::targetType() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_targetType;
+}
+
+void ComplexTypeEntry::setTargetType(const QString &code)
+{
+ S_D(ComplexTypeEntry);
+ d->m_targetType = code;
+}
+
+bool ComplexTypeEntry::isGenericClass() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_genericClass;
+}
+
+void ComplexTypeEntry::setGenericClass(bool isGeneric)
+{
+ S_D(ComplexTypeEntry);
+ d->m_genericClass = isGeneric;
+}
+
+bool ComplexTypeEntry::deleteInMainThread() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_deleteInMainThread;
+}
+
+void ComplexTypeEntry::setDeleteInMainThread(bool dmt)
+{
+ S_D(ComplexTypeEntry);
+ d->m_deleteInMainThread = dmt;
+}
+
+ComplexTypeEntry::CopyableFlag ComplexTypeEntry::copyable() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_copyableFlag;
+}
+
+void ComplexTypeEntry::setCopyable(ComplexTypeEntry::CopyableFlag flag)
+{
+ S_D(ComplexTypeEntry);
+ d->m_copyableFlag = flag;
+}
+
+TypeSystem::QtMetaTypeRegistration ComplexTypeEntry::qtMetaTypeRegistration() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_qtMetaTypeRegistration;
+}
+
+void ComplexTypeEntry::setQtMetaTypeRegistration(TypeSystem::QtMetaTypeRegistration r)
+{
+ S_D(ComplexTypeEntry);
+ d->m_qtMetaTypeRegistration = r;
+}
+
+QString ComplexTypeEntry::hashFunction() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_hashFunction;
+}
+
+void ComplexTypeEntry::setHashFunction(const QString &hashFunction)
+{
+ S_D(ComplexTypeEntry);
+ d->m_hashFunction = hashFunction;
+}
+
+void ComplexTypeEntry::setBaseContainerType(const ComplexTypeEntryCPtr &baseContainer)
+{
+ S_D(ComplexTypeEntry);
+ d->m_baseContainerType = baseContainer;
+}
+
+ComplexTypeEntryCPtr ComplexTypeEntry::baseContainerType() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_baseContainerType;
+}
+
+TypeSystem::ExceptionHandling ComplexTypeEntry::exceptionHandling() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_exceptionHandling;
+}
+
+void ComplexTypeEntry::setExceptionHandling(TypeSystem::ExceptionHandling e)
+{
+ S_D(ComplexTypeEntry);
+ d->m_exceptionHandling = e;
+}
+
+TypeSystem::AllowThread ComplexTypeEntry::allowThread() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_allowThread;
+}
+
+void ComplexTypeEntry::setAllowThread(TypeSystem::AllowThread allowThread)
+{
+ S_D(ComplexTypeEntry);
+ d->m_allowThread = allowThread;
+}
+
+void ComplexTypeEntry::setDefaultConstructor(const QString& defaultConstructor)
+{
+ S_D(ComplexTypeEntry);
+ d->m_defaultConstructor = defaultConstructor;
+}
+
+QString ComplexTypeEntry::defaultConstructor() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_defaultConstructor;
+}
+
+bool ComplexTypeEntry::hasDefaultConstructor() const
+{
+ S_D(const ComplexTypeEntry);
+ return !d->m_defaultConstructor.isEmpty();
+}
+
+TypeSystem::SnakeCase ComplexTypeEntry::snakeCase() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_snakeCase;
+}
+
+void ComplexTypeEntry::setSnakeCase(TypeSystem::SnakeCase sc)
+{
+ S_D(ComplexTypeEntry);
+ d->m_snakeCase = sc;
+}
+
+bool ComplexTypeEntry::isValueTypeWithCopyConstructorOnly() const
+{
+ S_D(const ComplexTypeEntry);
+ return d->m_isValueTypeWithCopyConstructorOnly;
+}
+
+void ComplexTypeEntry::setValueTypeWithCopyConstructorOnly(bool v)
+{
+ S_D(ComplexTypeEntry);
+ d->m_isValueTypeWithCopyConstructorOnly = v;
+}
+
+// FIXME PYSIDE 7: Remove this and make "true" the default
+static bool parentManagementEnabled = false;
+
+bool ComplexTypeEntry::isParentManagementEnabled()
+{
+ return parentManagementEnabled;
+}
+
+void ComplexTypeEntry::setParentManagementEnabled(bool e)
+{
+ parentManagementEnabled = e;
+}
+
+TypeEntry *ComplexTypeEntry::clone() const
+{
+ S_D(const ComplexTypeEntry);
+ return new ComplexTypeEntry(new ComplexTypeEntryPrivate(*d));
+}
+
+// Take over parameters relevant for typedefs
+void ComplexTypeEntry::useAsTypedef(const ComplexTypeEntryCPtr &source)
+{
+ S_D(ComplexTypeEntry);
+ TypeEntry::useAsTypedef(source);
+ d->m_qualifiedCppName = source->qualifiedCppName();
+ d->m_targetType = source->targetType();
+ d->m_typeFlags.setFlag(ComplexTypeEntry::Typedef);
+}
+
+ComplexTypeEntry::ComplexTypeEntry(ComplexTypeEntryPrivate *d) :
+ ConfigurableTypeEntry(d)
+{
+}
+
+TypeEntry *ConstantValueTypeEntry::clone() const
+{
+ return new ConstantValueTypeEntry(new TypeEntryPrivate(*d_func()));
+}
+
+
+// ----------------- TypedefEntry
+/* A typedef entry allows for specifying template specializations in the
+ * typesystem XML file. */
+class TypedefEntryPrivate : public ComplexTypeEntryPrivate
+{
+public:
+ TypedefEntryPrivate(const QString &entryName,
+ const QString &sourceType,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ComplexTypeEntryPrivate(entryName, TypeEntry::TypedefType,
+ vr, parent),
+ m_sourceType(sourceType)
+ {
+ }
+
+ QString m_sourceType;
+ ComplexTypeEntryCPtr m_source;
+ ComplexTypeEntryPtr m_target;
+};
+
+TypedefEntry::TypedefEntry(const QString &entryName, const QString &sourceType,
+ const QVersionNumber &vr, const TypeEntryCPtr &parent) :
+ ComplexTypeEntry(new TypedefEntryPrivate(entryName, sourceType, vr, parent))
+{
+}
+
+QString TypedefEntry::sourceType() const
+{
+ S_D(const TypedefEntry);
+ return d->m_sourceType;
+}
+
+void TypedefEntry::setSourceType(const QString &s)
+{
+ S_D(TypedefEntry);
+ d->m_sourceType =s;
+}
+
+TypeEntry *TypedefEntry::clone() const
+{
+ S_D(const TypedefEntry);
+ return new TypedefEntry(new TypedefEntryPrivate(*d));
+}
+
+ComplexTypeEntryCPtr TypedefEntry::source() const
+{
+ S_D(const TypedefEntry);
+ return d->m_source;
+}
+
+void TypedefEntry::setSource(const ComplexTypeEntryCPtr &source)
+{
+ S_D(TypedefEntry);
+ d->m_source = source;
+}
+
+ComplexTypeEntryPtr TypedefEntry::target() const
+{
+ S_D(const TypedefEntry);
+ return d->m_target;
+}
+
+void TypedefEntry::setTarget(ComplexTypeEntryPtr target)
+{
+ S_D(TypedefEntry);
+ d->m_target = target;
+}
+
+TypedefEntry::TypedefEntry(TypedefEntryPrivate *d) :
+ ComplexTypeEntry(d)
+{
+}
+
+// ----------------- ContainerTypeEntry
+class ContainerTypeEntryPrivate : public ComplexTypeEntryPrivate
+{
+public:
+ ContainerTypeEntryPrivate(const QString &entryName,
+ ContainerTypeEntry::ContainerKind containerKind,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ComplexTypeEntryPrivate(entryName, TypeEntry::ContainerType, vr, parent),
+ m_containerKind(containerKind)
+ {
+ }
+
+ OpaqueContainers::const_iterator findOpaqueContainer(const QStringList &instantiations) const
+ {
+ return std::find_if(m_opaqueContainers.cbegin(), m_opaqueContainers.cend(),
+ [&instantiations](const OpaqueContainer &r) {
+ return r.instantiations == instantiations;
+ });
+ }
+
+ OpaqueContainers m_opaqueContainers;
+ CustomConversionPtr m_customConversion;
+ ContainerTypeEntry::ContainerKind m_containerKind;
+};
+
+QString OpaqueContainer::templateParameters() const
+{
+ QString result;
+ result += u'<';
+ for (qsizetype i = 0, size = instantiations.size(); i < size; ++i) {
+ if (i)
+ result += u',';
+ result += instantiations.at(i);
+ }
+ result += u'>';
+ return result;
+}
+
+ContainerTypeEntry::ContainerTypeEntry(const QString &entryName, ContainerKind containerKind,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ComplexTypeEntry(new ContainerTypeEntryPrivate(entryName, containerKind, vr, parent))
+{
+ setCodeGeneration(GenerateForSubclass);
+}
+
+ContainerTypeEntry::ContainerKind ContainerTypeEntry::containerKind() const
+{
+ S_D(const ContainerTypeEntry);
+ return d->m_containerKind;
+}
+
+qsizetype ContainerTypeEntry::templateParameterCount() const
+{
+ S_D(const ContainerTypeEntry);
+ qsizetype result = 1;
+ switch (d->m_containerKind) {
+ case MapContainer:
+ case MultiMapContainer:
+ case PairContainer:
+ case SpanContainer:
+ result = 2;
+ break;
+ case ListContainer:
+ case SetContainer:
+ break;
+ }
+ return result;
+}
+
+const OpaqueContainers &ContainerTypeEntry::opaqueContainers() const
+{
+ S_D(const ContainerTypeEntry);
+ return d->m_opaqueContainers;
+}
+
+void ContainerTypeEntry::appendOpaqueContainers(const OpaqueContainers &l)
+{
+ S_D(ContainerTypeEntry);
+ d->m_opaqueContainers.append(l);
+}
+
+bool ContainerTypeEntry::generateOpaqueContainer(const QStringList &instantiations) const
+{
+ S_D(const ContainerTypeEntry);
+ return d->findOpaqueContainer(instantiations) != d->m_opaqueContainers.cend();
+}
+
+QString ContainerTypeEntry::opaqueContainerName(const QStringList &instantiations) const
+{
+ S_D(const ContainerTypeEntry);
+ const auto it = d->findOpaqueContainer(instantiations);
+ return it != d->m_opaqueContainers.cend() ? it->name : QString{};
+}
+
+bool ContainerTypeEntry::hasCustomConversion() const
+{
+ S_D(const ContainerTypeEntry);
+ return bool(d->m_customConversion);
+}
+
+void ContainerTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion)
+{
+ S_D(ContainerTypeEntry);
+ d->m_customConversion = customConversion;
+}
+
+CustomConversionPtr ContainerTypeEntry::customConversion() const
+{
+ S_D(const ContainerTypeEntry);
+ return d->m_customConversion;
+}
+
+TypeEntry *ContainerTypeEntry::clone() const
+{
+ S_D(const ContainerTypeEntry);
+ return new ContainerTypeEntry(new ContainerTypeEntryPrivate(*d));
+}
+
+ContainerTypeEntry::ContainerTypeEntry(ContainerTypeEntryPrivate *d) :
+ ComplexTypeEntry(d)
+{
+}
+
+// ----------------- SmartPointerTypeEntry
+class SmartPointerTypeEntryPrivate : public ComplexTypeEntryPrivate
+{
+public:
+ SmartPointerTypeEntryPrivate(const QString &entryName,
+ const QString &getterName,
+ TypeSystem::SmartPointerType type,
+ const QString &refCountMethodName,
+ const QVersionNumber &vr, const TypeEntryCPtr &parent) :
+ ComplexTypeEntryPrivate(entryName, TypeEntry::SmartPointerType, vr, parent),
+ m_getterName(getterName),
+ m_refCountMethodName(refCountMethodName),
+ m_smartPointerType(type)
+ {
+ }
+
+ qsizetype instantiationIndex(const TypeEntryCPtr &t) const;
+
+ QString m_getterName;
+ QString m_refCountMethodName;
+ QString m_valueCheckMethod;
+ QString m_nullCheckMethod;
+ QString m_resetMethod;
+ SmartPointerTypeEntry::Instantiations m_instantiations;
+ TypeSystem::SmartPointerType m_smartPointerType;
+};
+
+qsizetype SmartPointerTypeEntryPrivate::instantiationIndex(const TypeEntryCPtr &t) const
+{
+ for (qsizetype i = 0, size = m_instantiations.size(); i < size; ++i) {
+ if (m_instantiations.at(i).typeEntry == t)
+ return i;
+ }
+ return -1;
+}
+
+SmartPointerTypeEntry::SmartPointerTypeEntry(const QString &entryName,
+ const QString &getterName,
+ TypeSystem::SmartPointerType smartPointerType,
+ const QString &refCountMethodName,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ComplexTypeEntry(new SmartPointerTypeEntryPrivate(entryName, getterName, smartPointerType,
+ refCountMethodName, vr, parent))
+{
+}
+
+TypeSystem::SmartPointerType SmartPointerTypeEntry::smartPointerType() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return d->m_smartPointerType;
+}
+
+QString SmartPointerTypeEntry::getter() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return d->m_getterName;
+}
+
+QString SmartPointerTypeEntry::refCountMethodName() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return d->m_refCountMethodName;
+}
+
+QString SmartPointerTypeEntry::valueCheckMethod() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return d->m_valueCheckMethod;
+}
+
+void SmartPointerTypeEntry::setValueCheckMethod(const QString &m)
+{
+ S_D(SmartPointerTypeEntry);
+ d->m_valueCheckMethod = m;
+}
+
+QString SmartPointerTypeEntry::nullCheckMethod() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return d->m_nullCheckMethod;
+}
+
+void SmartPointerTypeEntry::setNullCheckMethod(const QString &f)
+{
+ S_D(SmartPointerTypeEntry);
+ d->m_nullCheckMethod = f;
+}
+
+QString SmartPointerTypeEntry::resetMethod() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return d->m_resetMethod;
+}
+
+void SmartPointerTypeEntry::setResetMethod(const QString &f)
+{
+ S_D(SmartPointerTypeEntry);
+ d->m_resetMethod = f;
+}
+
+TypeEntry *SmartPointerTypeEntry::clone() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return new SmartPointerTypeEntry(new SmartPointerTypeEntryPrivate(*d));
+}
+
+const SmartPointerTypeEntry::Instantiations &SmartPointerTypeEntry::instantiations() const
+{
+ S_D(const SmartPointerTypeEntry);
+ return d->m_instantiations;
+}
+
+void SmartPointerTypeEntry::setInstantiations(const Instantiations &i)
+{
+ S_D(SmartPointerTypeEntry);
+ d->m_instantiations = i;
+}
+
+SmartPointerTypeEntry::SmartPointerTypeEntry(SmartPointerTypeEntryPrivate *d) :
+ ComplexTypeEntry(d)
+{
+}
+
+bool SmartPointerTypeEntry::matchesInstantiation(const TypeEntryCPtr &e) const
+{
+ S_D(const SmartPointerTypeEntry);
+ // No instantiations specified, or match
+ return d->m_instantiations.isEmpty() || d->instantiationIndex(e) != -1;
+}
+
+static QString fixSmartPointerName(QString name)
+{
+ name.replace(u"::"_s, u"_"_s);
+ name.replace(u'<', u'_');
+ name.remove(u'>');
+ name.remove(u' ');
+ return name;
+}
+
+QString SmartPointerTypeEntry::getTargetName(const AbstractMetaType &metaType) const
+{
+ S_D(const SmartPointerTypeEntry);
+ auto instantiatedTe = metaType.instantiations().constFirst().typeEntry();
+ const auto index = d->instantiationIndex(instantiatedTe);
+ if (index != -1 && !d->m_instantiations.at(index).name.isEmpty())
+ return d->m_instantiations.at(index).name;
+
+ QString name = metaType.cppSignature();
+ const auto templatePos = name.indexOf(u'<');
+ if (templatePos != -1) { // "std::shared_ptr<A::B>" -> "shared_ptr<A::B>"
+ const auto colonPos = name.lastIndexOf(u"::"_s, templatePos);
+ if (colonPos != -1)
+ name.remove(0, colonPos + 2);
+ }
+ return fixSmartPointerName(name);
+}
+
+// ----------------- NamespaceTypeEntry
+class NamespaceTypeEntryPrivate : public ComplexTypeEntryPrivate
+{
+public:
+ using ComplexTypeEntryPrivate::ComplexTypeEntryPrivate;
+
+ QRegularExpression m_filePattern;
+ NamespaceTypeEntryCPtr m_extends;
+ TypeSystem::Visibility m_visibility = TypeSystem::Visibility::Auto;
+ bool m_hasPattern = false;
+ bool m_inlineNamespace = false;
+ bool m_generateUsing = true; // Whether to generate "using namespace" into wrapper
+};
+
+NamespaceTypeEntry::NamespaceTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ComplexTypeEntry(new NamespaceTypeEntryPrivate(entryName, NamespaceType, vr, parent))
+{
+}
+
+TypeEntry *NamespaceTypeEntry::clone() const
+{
+ S_D(const NamespaceTypeEntry);
+ return new NamespaceTypeEntry(new NamespaceTypeEntryPrivate(*d));
+}
+
+NamespaceTypeEntryCPtr NamespaceTypeEntry::extends() const
+{
+ S_D(const NamespaceTypeEntry);
+ return d->m_extends;
+}
+
+void NamespaceTypeEntry::setExtends(const NamespaceTypeEntryCPtr &e)
+{
+ S_D(NamespaceTypeEntry);
+ d->m_extends = e;
+}
+
+const QRegularExpression &NamespaceTypeEntry::filePattern() const
+{
+ S_D(const NamespaceTypeEntry);
+ return d->m_filePattern;
+}
+
+void NamespaceTypeEntry::setFilePattern(const QRegularExpression &r)
+{
+ S_D(NamespaceTypeEntry);
+ d->m_filePattern = r;
+ d->m_hasPattern = !d->m_filePattern.pattern().isEmpty();
+ if (d->m_hasPattern)
+ d->m_filePattern.optimize();
+}
+
+bool NamespaceTypeEntry::hasPattern() const
+{
+ S_D(const NamespaceTypeEntry);
+ return d->m_hasPattern;
+}
+
+NamespaceTypeEntry::NamespaceTypeEntry(NamespaceTypeEntryPrivate *d) :
+ ComplexTypeEntry(d)
+{
+}
+
+bool NamespaceTypeEntry::matchesFile(const QString &needle) const
+{
+ S_D(const NamespaceTypeEntry);
+ return d->m_filePattern.match(needle).hasMatch();
+}
+
+bool NamespaceTypeEntry::isVisible() const
+{
+ S_D(const NamespaceTypeEntry);
+ return d->m_visibility == TypeSystem::Visibility::Visible
+ || (d->m_visibility == TypeSystem::Visibility::Auto && !d->m_inlineNamespace);
+}
+
+void NamespaceTypeEntry::setVisibility(TypeSystem::Visibility v)
+{
+ S_D(NamespaceTypeEntry);
+ d->m_visibility = v;
+}
+
+bool NamespaceTypeEntry::isInlineNamespace() const
+{
+ S_D(const NamespaceTypeEntry);
+ return d->m_inlineNamespace;
+}
+
+void NamespaceTypeEntry::setInlineNamespace(bool i)
+{
+ S_D(NamespaceTypeEntry);
+ d->m_inlineNamespace = i;
+}
+
+bool NamespaceTypeEntry::isVisibleScope(const TypeEntryCPtr &e)
+{
+ return isVisibleScope(e.get());
+}
+
+bool NamespaceTypeEntry::isVisibleScope(const TypeEntry *e)
+{
+ return e->type() != TypeEntry::NamespaceType
+ || static_cast<const NamespaceTypeEntry *>(e)->isVisible();
+}
+
+bool NamespaceTypeEntry::generateUsing() const
+{
+ S_D(const NamespaceTypeEntry);
+ return d->m_generateUsing;
+}
+
+void NamespaceTypeEntry::setGenerateUsing(bool generateUsing)
+{
+ S_D(NamespaceTypeEntry);
+ d->m_generateUsing = generateUsing;
+}
+
+// ----------------- ValueTypeEntry
+
+class ValueTypeEntryPrivate : public ComplexTypeEntryPrivate
+{
+public:
+ using ComplexTypeEntryPrivate::ComplexTypeEntryPrivate;
+
+ QString m_targetConversionRule;
+ CustomConversionPtr m_customConversion;
+};
+
+ValueTypeEntry::ValueTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ComplexTypeEntry(new ValueTypeEntryPrivate(entryName, BasicValueType, vr, parent))
+{
+}
+
+bool ValueTypeEntry::hasCustomConversion() const
+{
+ S_D(const ValueTypeEntry);
+ return bool(d->m_customConversion);
+}
+
+void ValueTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion)
+{
+ S_D(ValueTypeEntry);
+ d->m_customConversion = customConversion;
+}
+
+CustomConversionPtr ValueTypeEntry::customConversion() const
+{
+ S_D(const ValueTypeEntry);
+ return d->m_customConversion;
+}
+
+void ValueTypeEntry::setTargetConversionRule(const QString &conversionRule)
+{
+ S_D(ValueTypeEntry);
+ d->m_targetConversionRule = conversionRule;
+}
+
+QString ValueTypeEntry::targetConversionRule() const
+{
+ S_D(const ValueTypeEntry);
+ return d->m_targetConversionRule;
+}
+
+bool ValueTypeEntry::hasTargetConversionRule() const
+{
+ S_D(const ValueTypeEntry);
+ return !d->m_targetConversionRule.isEmpty();
+}
+
+bool ValueTypeEntry::isValue() const
+{
+ return true;
+}
+
+TypeEntry *ValueTypeEntry::clone() const
+{
+ S_D(const ValueTypeEntry);
+ return new ValueTypeEntry(new ValueTypeEntryPrivate(*d));
+}
+
+ValueTypeEntry::ValueTypeEntry(ComplexTypeEntryPrivate *d) :
+ ComplexTypeEntry(d)
+{
+}
+
+ValueTypeEntry::ValueTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ ComplexTypeEntry(entryName, t, vr, parent)
+{
+}
+
+// ----------------- FunctionTypeEntry
+class FunctionTypeEntryPrivate : public TypeEntryPrivate
+{
+public:
+ FunctionTypeEntryPrivate(const QString &entryName, const QString &signature,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntryPrivate(entryName, TypeEntry::FunctionType, vr, parent),
+ m_signatures(signature)
+ {
+ }
+
+ QStringList m_signatures;
+ QString m_docFile;
+};
+
+FunctionTypeEntry::FunctionTypeEntry(const QString &entryName, const QString &signature,
+ const QVersionNumber &vr,
+ const TypeEntryCPtr &parent) :
+ TypeEntry(new FunctionTypeEntryPrivate(entryName, signature, vr, parent))
+{
+}
+
+void FunctionTypeEntry::addSignature(const QString &signature)
+{
+ S_D(FunctionTypeEntry);
+ d->m_signatures << signature;
+}
+
+const QStringList &FunctionTypeEntry::signatures() const
+{
+ S_D(const FunctionTypeEntry);
+ return d->m_signatures;
+}
+
+bool FunctionTypeEntry::hasSignature(const QString &signature) const
+{
+ S_D(const FunctionTypeEntry);
+ return d->m_signatures.contains(signature);
+}
+
+QString FunctionTypeEntry::docFile() const
+{
+ S_D(const FunctionTypeEntry);
+ return d->m_docFile;
+}
+
+void FunctionTypeEntry::setDocFile(const QString &df)
+{
+ S_D(FunctionTypeEntry);
+ d->m_docFile = df;
+}
+
+TypeEntry *FunctionTypeEntry::clone() const
+{
+ S_D(const FunctionTypeEntry);
+ return new FunctionTypeEntry(new FunctionTypeEntryPrivate(*d));
+}
+
+FunctionTypeEntry::FunctionTypeEntry(FunctionTypeEntryPrivate *d) :
+ TypeEntry(d)
+{
+}
+
+// ----------------- ObjectTypeEntry
+ObjectTypeEntry::ObjectTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent)
+ : ComplexTypeEntry(entryName, ObjectType, vr, parent)
+{
+}
+
+TypeEntry *ObjectTypeEntry::clone() const
+{
+ S_D(const ComplexTypeEntry);
+ return new ObjectTypeEntry(new ComplexTypeEntryPrivate(*d));
+}
+
+ObjectTypeEntry::ObjectTypeEntry(ComplexTypeEntryPrivate *d) :
+ ComplexTypeEntry(d)
+{
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+#define FORMAT_BOOL(name, var) \
+ if (var) \
+ debug << ", [" << name << ']';
+
+#define FORMAT_NONEMPTY_STRING(name, var) \
+ if (!var.isEmpty()) \
+ debug << ", " << name << "=\"" << var << '"';
+
+#define FORMAT_LIST_SIZE(name, var) \
+ if (!var.isEmpty()) \
+ debug << ", " << var.size() << ' ' << name;
+
+void TypeEntry::formatDebug(QDebug &debug) const
+{
+ const QString cppName = qualifiedCppName();
+ debug << '"' << m_d->m_name << '"';
+ if (m_d->m_name != cppName)
+ debug << "\", cppName=\"" << cppName << '"';
+ debug << ", type=" << m_d->m_type << ", codeGeneration="
+ << m_d->m_codeGeneration;
+ const QString &targetName = targetLangName();
+ if (m_d->m_name != targetName)
+ debug << ", target=\"" << targetLangName() << '"';
+ FORMAT_NONEMPTY_STRING("package", m_d->m_targetLangPackage)
+ FORMAT_BOOL("stream", m_d->m_stream)
+ FORMAT_BOOL("built-in", m_d->m_builtin)
+ if (m_d->m_viewOn)
+ debug << ", views=" << m_d->m_viewOn->name();
+ if (!m_d->m_version.isNull() && m_d->m_version > QVersionNumber(0, 0))
+ debug << ", version=" << m_d->m_version;
+ if (m_d->m_revision)
+ debug << ", revision=" << m_d->m_revision;
+ if (m_d->m_sbkIndex)
+ debug << ", sbkIndex=" << m_d->m_sbkIndex;
+ if (m_d->m_include.isValid())
+ debug << ", include=" << m_d->m_include;
+ if (m_d->m_private)
+ debug << ", [private]";
+ formatList(debug, "extraIncludes", m_d->m_extraIncludes, ", ");
+}
+
+void PrimitiveTypeEntry::formatDebug(QDebug &debug) const
+{
+ TypeEntry::formatDebug(debug);
+ if (auto e = referencedTypeEntry()) {
+ debug << ", references";
+ for (; e ; e = e->referencedTypeEntry())
+ debug << ":\"" << e->qualifiedCppName() <<'"';
+ }
+}
+
+void ComplexTypeEntry::formatDebug(QDebug &debug) const
+{
+ S_D(const ComplexTypeEntry);
+
+ TypeEntry::formatDebug(debug);
+ FORMAT_BOOL("polymorphicBase", d->m_polymorphicBase)
+ FORMAT_BOOL("genericClass", d->m_genericClass)
+ FORMAT_BOOL("deleteInMainThread", d->m_deleteInMainThread)
+ if (d->m_typeFlags != 0)
+ debug << ", typeFlags=" << d->m_typeFlags;
+ debug << ", copyableFlag=" << d->m_copyableFlag
+ << ", except=" << int(d->m_exceptionHandling)
+ << ", snakeCase=" << int(d->m_snakeCase);
+ FORMAT_NONEMPTY_STRING("defaultSuperclass", d->m_defaultSuperclass)
+ FORMAT_NONEMPTY_STRING("polymorphicIdValue", d->m_polymorphicIdValue)
+ FORMAT_NONEMPTY_STRING("targetType", d->m_targetType)
+ FORMAT_NONEMPTY_STRING("hash", d->m_hashFunction)
+ FORMAT_LIST_SIZE("addedFunctions", d->m_addedFunctions)
+ formatList(debug, "functionMods", d->m_functionMods, ", ");
+ FORMAT_LIST_SIZE("codeSnips", d->m_codeSnips)
+ FORMAT_LIST_SIZE("fieldMods", d->m_fieldMods)
+}
+
+void CustomTypeEntry::formatDebug(QDebug &debug) const
+{
+ S_D(const CustomTypeEntry);
+ TypeEntry::formatDebug(debug);
+ debug << ", checkFunction=" << d->m_checkFunction;
+}
+
+void PythonTypeEntry::formatDebug(QDebug &debug) const
+{
+ S_D(const PythonTypeEntry);
+
+ CustomTypeEntry::formatDebug(debug);
+ debug << ", type=" << int(d->m_cPythonType);
+}
+
+void FunctionTypeEntry::formatDebug(QDebug &debug) const
+{
+ S_D(const FunctionTypeEntry);
+
+ TypeEntry::formatDebug(debug);
+ debug << "signatures=" << d->m_signatures;
+}
+
+void TypedefEntry::formatDebug(QDebug &debug) const
+{
+ S_D(const TypedefEntry);
+
+ ComplexTypeEntry::formatDebug(debug);
+ debug << ", sourceType=\"" << d->m_sourceType << '"'
+ << ", source=" << d->m_source << ", target=" << d->m_target;
+}
+
+void EnumTypeEntry::formatDebug(QDebug &debug) const
+{
+ S_D(const EnumTypeEntry);
+
+ TypeEntry::formatDebug(debug);
+ if (d->m_pythonEnumType != TypeSystem::PythonEnumType::Unspecified)
+ debug << ", python-type=" << int(d->m_pythonEnumType);
+ if (d->m_flags)
+ debug << ", flags=(" << d->m_flags << ')';
+}
+
+void NamespaceTypeEntry::formatDebug(QDebug &debug) const
+{
+ S_D(const NamespaceTypeEntry);
+
+ ComplexTypeEntry::formatDebug(debug);
+ auto pattern = d->m_filePattern.pattern();
+ FORMAT_NONEMPTY_STRING("pattern", pattern)
+ debug << ",visibility=" << d->m_visibility;
+ if (d->m_inlineNamespace)
+ debug << "[inline]";
+}
+
+QDebug operator<<(QDebug d, const OpaqueContainer &oc)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "OpaqueContainer(\"" << oc.name << "\": " << oc.templateParameters() << ')';
+ return d;
+}
+
+void ContainerTypeEntry::formatDebug(QDebug &debug) const
+{
+ S_D(const ContainerTypeEntry);
+
+ ComplexTypeEntry::formatDebug(debug);
+ debug << ", type=" << d->m_containerKind << '"';
+ if (!d->m_opaqueContainers.isEmpty())
+ debug << ", opaque-containers=[" << d->m_opaqueContainers << ']';
+}
+
+void SmartPointerTypeEntry::formatDebug(QDebug &debug) const
+{
+ S_D(const SmartPointerTypeEntry);
+
+ ComplexTypeEntry::formatDebug(debug);
+ if (!d->m_instantiations.isEmpty()) {
+ debug << "type=" << d->m_type << ", instantiations["
+ << d->m_instantiations.size() << "]=(";
+ for (const auto &i : d->m_instantiations) {
+ debug << i.typeEntry->name() << ',';
+ if (!i.name.isEmpty())
+ debug << "=\"" << i.name << '"';
+ }
+ debug << ')';
+ }
+}
+
+QDebug operator<<(QDebug d, const TypeEntry *te)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "TypeEntry(";
+ if (te)
+ te->formatDebug(d);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const TypeEntryCPtr &te)
+{
+ d << te.get();
+ return d;
+}
+
+QDebug operator<<(QDebug d, const TemplateEntry *te)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "TemplateEntry(";
+ if (te) {
+ d << '"' << te->name() << '"';
+ } else {
+ d << '0';
+ }
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const TemplateEntryCPtr &te)
+{
+ d << te.get();
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/ApiExtractor/typesystem.h b/sources/shiboken6/ApiExtractor/typesystem.h
new file mode 100644
index 000000000..a2e4debc8
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typesystem.h
@@ -0,0 +1,215 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPESYSTEM_H
+#define TYPESYSTEM_H
+
+#include "include.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/qobjectdefs.h>
+#include <QtCore/QString>
+#include <QtCore/QScopedPointer>
+
+class AbstractMetaType;
+class CustomTypeEntry;
+class PrimitiveTypeEntry;
+class SourceLocation;
+class TypeSystemTypeEntry;
+
+class TypeEntryPrivate;
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+class QVersionNumber;
+QT_END_NAMESPACE
+
+class TypeEntry
+{
+ Q_GADGET
+public:
+ Q_DISABLE_COPY_MOVE(TypeEntry)
+
+ enum Type {
+ PrimitiveType,
+ VoidType,
+ VarargsType,
+ FlagsType,
+ EnumType,
+ EnumValue,
+ ConstantValueType,
+ TemplateArgumentType,
+ BasicValueType,
+ ContainerType,
+ ObjectType,
+ NamespaceType,
+ ArrayType,
+ TypeSystemType,
+ CustomType,
+ PythonType,
+ FunctionType,
+ SmartPointerType,
+ TypedefType
+ };
+ Q_ENUM(Type)
+
+ enum CodeGeneration {
+ GenerateNothing, // Rejection, private type, ConstantValueTypeEntry or similar
+ GenerationDisabled, // generate='no' in type system
+ GenerateCode, // Generate code
+ GenerateForSubclass, // Inherited from a loaded dependent type system.
+ };
+ Q_ENUM(CodeGeneration)
+
+ explicit TypeEntry(const QString &entryName, Type t, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+ virtual ~TypeEntry();
+
+ Type type() const;
+
+ TypeEntryCPtr parent() const;
+ void setParent(const TypeEntryCPtr &);
+ bool isChildOf(const TypeEntryCPtr &p) const;
+
+ bool isPrimitive() const;
+ bool isEnum() const;
+ bool isFlags() const;
+ bool isObject() const;
+ bool isNamespace() const;
+ bool isContainer() const;
+ bool isSmartPointer() const;
+ bool isUniquePointer() const;
+ bool isArray() const;
+ bool isTemplateArgument() const;
+ bool isVoid() const;
+ bool isVarargs() const;
+ bool isCustom() const;
+ bool isTypeSystem() const;
+ bool isFunction() const;
+ bool isEnumValue() const;
+
+ bool stream() const;
+ void setStream(bool b);
+
+ bool isBuiltIn() const;
+ void setBuiltIn(bool b);
+
+ bool isPrivate() const;
+ void setPrivate(bool b);
+
+ // The type's name in C++, fully qualified
+ QString name() const;
+ // C++ excluding inline namespaces
+ QString shortName() const;
+ // Name as specified in XML
+ QString entryName() const;
+
+ CodeGeneration codeGeneration() const;
+ void setCodeGeneration(CodeGeneration cg);
+
+ // Returns true if code must be generated for this entry,
+ // it will return false in case of types coming from typesystems
+ // included for reference only.
+ // NOTE: 'GenerateForSubclass' means 'generate="no"'
+ // on 'load-typesystem' tag
+ bool generateCode() const;
+
+ /// Returns whether the C++ generators should generate this entry
+ bool shouldGenerate() const;
+
+ int revision() const;
+ void setRevision(int r); // see typedatabase.cpp
+ int sbkIndex() const; // see typedatabase.cpp
+ void setSbkIndex(int i);
+
+ virtual QString qualifiedCppName() const;
+
+ /// Its type's name in target language API.
+ /// The target language API name represents how this type is referred on
+ /// low level code for the target language. Examples: for Java this would
+ /// be a JNI name, for Python it should represent the CPython type name.
+ /// \return string representing the target language API name
+ /// Currently used only for PrimitiveTypeEntry (attribute "target").
+ CustomTypeEntryCPtr targetLangApiType() const;
+ bool hasTargetLangApiType() const;
+ void setTargetLangApiType(const CustomTypeEntryPtr &cte);
+ QString targetLangApiName() const;
+
+ // The type's name in TargetLang
+ QString targetLangName() const; // "Foo.Bar"
+ void setTargetLangName(const QString &n);
+ QString targetLangEntryName() const; // "Bar"
+
+ // The package
+ QString targetLangPackage() const;
+ void setTargetLangPackage(const QString &p);
+
+ QString qualifiedTargetLangName() const;
+
+ virtual bool isValue() const;
+ virtual bool isComplex() const;
+
+ const IncludeList &extraIncludes() const;
+ void setExtraIncludes(const IncludeList &includes);
+ void addExtraInclude(const Include &newInclude);
+
+ Include include() const;
+ void setInclude(const Include &inc);
+
+ QVersionNumber version() const;
+
+ // View on: Type to use for function argument conversion, fex
+ // std::string_view -> std::string for foo(std::string_view).
+ // cf AbstractMetaType::viewOn()
+ TypeEntryPtr viewOn() const;
+ void setViewOn(const TypeEntryPtr &v);
+
+ virtual TypeEntry *clone() const;
+
+ void useAsTypedef(const TypeEntryCPtr &source);
+
+ SourceLocation sourceLocation() const;
+ void setSourceLocation(const SourceLocation &sourceLocation);
+
+ // Query functions for generators
+ /// Returns true if the type passed has a Python wrapper for it.
+ /// Although namespace has a Python wrapper, it's not considered a type.
+ bool isWrapperType() const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ virtual void formatDebug(QDebug &d) const;
+#endif
+
+protected:
+ explicit TypeEntry(TypeEntryPrivate *d);
+
+ const TypeEntryPrivate *d_func() const;
+ TypeEntryPrivate *d_func();
+
+ virtual QString buildTargetLangName() const;
+
+private:
+ bool setRevisionHelper(int r);
+ int sbkIndexHelper() const;
+ QScopedPointer<TypeEntryPrivate> m_d;
+};
+
+TypeSystemTypeEntryCPtr typeSystemTypeEntry(TypeEntryCPtr e);
+
+// cf AbstractMetaClass::targetLangEnclosingClass()
+TypeEntryCPtr targetLangEnclosingEntry(const TypeEntryCPtr &e);
+
+bool isCppPrimitive(const TypeEntryCPtr &e);
+
+/// Returns true if the type is a primitive but not a C++ primitive.
+bool isUserPrimitive(const TypeEntryCPtr &e);
+
+/// Returns true if the type is a C++ integral primitive,
+/// i.e. bool, char, int, long, and their unsigned counterparts.
+bool isCppIntegralPrimitive(const TypeEntryCPtr &e);
+
+/// Returns true if the type is an extended C++ primitive, a void*,
+/// a const char*, or a std::string (cf isCppPrimitive()).
+bool isExtendedCppPrimitive(const TypeEntryCPtr &e);
+
+#endif // TYPESYSTEM_H
diff --git a/sources/shiboken6/ApiExtractor/typesystem_enums.h b/sources/shiboken6/ApiExtractor/typesystem_enums.h
new file mode 100644
index 000000000..9ecbb08a1
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typesystem_enums.h
@@ -0,0 +1,113 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPESYSTEM_ENUMS_H
+#define TYPESYSTEM_ENUMS_H
+
+namespace TypeSystem
+{
+enum Language {
+ TargetLangCode = 0x0001,
+ NativeCode = 0x0002,
+ ShellCode = 0x0004,
+
+ // masks
+ All = TargetLangCode | NativeCode | ShellCode,
+
+ TargetLangAndNativeCode = TargetLangCode | NativeCode
+};
+
+enum class AllowThread {
+ Unspecified,
+ Allow,
+ Disallow,
+ Auto
+};
+
+enum Ownership {
+ UnspecifiedOwnership,
+ DefaultOwnership,
+ TargetLangOwnership,
+ CppOwnership
+};
+
+enum CodeSnipPosition {
+ CodeSnipPositionBeginning,
+ CodeSnipPositionEnd,
+ CodeSnipPositionDeclaration,
+ CodeSnipPositionPyOverride,
+ CodeSnipPositionAny
+};
+
+enum DocModificationMode {
+ DocModificationAppend,
+ DocModificationPrepend,
+ DocModificationReplace,
+ DocModificationXPathReplace
+};
+
+enum class ExceptionHandling {
+ Unspecified,
+ Off,
+ AutoDefaultToOff,
+ AutoDefaultToOn,
+ On
+};
+
+enum class SnakeCase {
+ Unspecified,
+ Disabled,
+ Enabled,
+ Both
+};
+
+enum Visibility { // For namespaces
+ Unspecified,
+ Visible,
+ Invisible,
+ Auto
+};
+
+enum class BoolCast { // Generate nb_bool (overriding command line)
+ Unspecified,
+ Disabled,
+ Enabled
+};
+
+enum class CPythonType
+{
+ Bool,
+ Float,
+ Integer,
+ String,
+ Other
+};
+
+enum class QtMetaTypeRegistration
+{
+ Unspecified,
+ Enabled,
+ BaseEnabled, // Registration only for the base class of a hierarchy
+ Disabled
+};
+
+enum class SmartPointerType {
+ Shared,
+ Unique,
+ Handle,
+ ValueHandle
+};
+
+enum class PythonEnumType {
+ Unspecified,
+ Enum,
+ IntEnum,
+ Flag,
+ IntFlag
+};
+
+enum : int { OverloadNumberUnset = -1, OverloadNumberDefault = 99999 };
+
+} // namespace TypeSystem
+
+#endif // TYPESYSTEM_ENUMS_H
diff --git a/sources/shiboken6/ApiExtractor/typesystem_typedefs.h b/sources/shiboken6/ApiExtractor/typesystem_typedefs.h
new file mode 100644
index 000000000..5a4e12ff2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typesystem_typedefs.h
@@ -0,0 +1,79 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPESYSTEM_TYPEDEFS_H
+#define TYPESYSTEM_TYPEDEFS_H
+
+#include <QtCore/QList>
+
+#include <memory>
+
+class ArrayTypeEntry;
+class ComplexTypeEntry;
+class ConfigurableTypeEntry;
+class ConstantValueTypeEntry;
+class ContainerTypeEntry;
+class CustomTypeEntry;
+class EnumTypeEntry;
+class EnumValueTypeEntry;
+class FlagsTypeEntry;
+class FunctionTypeEntry;
+class NamespaceTypeEntry;
+class ObjectTypeEntry;
+class PrimitiveTypeEntry;
+class SmartPointerTypeEntry;
+class TemplateEntry;
+class TypeEntry;
+class TypedefEntry;
+class TypeSystemTypeEntry;
+class ValueTypeEntry;
+
+using ArrayTypeEntryPtr = std::shared_ptr<ArrayTypeEntry>;
+using ComplexTypeEntryPtr = std::shared_ptr<ComplexTypeEntry>;
+using ConfigurableTypeEntryPtr = std::shared_ptr<ConfigurableTypeEntry>;
+using ConstantValueTypeEntryPtr = std::shared_ptr<ConstantValueTypeEntry>;
+using ContainerTypeEntryPtr = std::shared_ptr<ContainerTypeEntry>;
+using CustomTypeEntryPtr = std::shared_ptr<CustomTypeEntry>;
+using EnumTypeEntryPtr = std::shared_ptr<EnumTypeEntry>;
+using EnumValueTypeEntryPtr = std::shared_ptr<EnumValueTypeEntry>;
+using FlagsTypeEntryPtr = std::shared_ptr<FlagsTypeEntry>;
+using FunctionTypeEntryPtr = std::shared_ptr<FunctionTypeEntry>;
+using NamespaceTypeEntryPtr = std::shared_ptr<NamespaceTypeEntry>;
+using ObjectTypeEntryPtr = std::shared_ptr<ObjectTypeEntry>;
+using PrimitiveTypeEntryPtr = std::shared_ptr<PrimitiveTypeEntry>;
+using SmartPointerTypeEntryPtr = std::shared_ptr<SmartPointerTypeEntry>;
+using TemplateEntryPtr = std::shared_ptr<TemplateEntry>;
+using TypeEntryPtr = std::shared_ptr<TypeEntry>;
+using TypedefEntryPtr = std::shared_ptr<TypedefEntry>;
+using TypeSystemTypeEntryPtr = std::shared_ptr<TypeSystemTypeEntry>;
+using ValueTypeEntryPtr = std::shared_ptr<ValueTypeEntry>;
+
+using ArrayTypeEntryCPtr = std::shared_ptr<const ArrayTypeEntry>;
+using ComplexTypeEntryCPtr = std::shared_ptr<const ComplexTypeEntry>;
+using ConstantValueTypeEntryCPtr = std::shared_ptr<const ConstantValueTypeEntry>;
+using ConfigurableTypeEntryCPtr = std::shared_ptr<const ConfigurableTypeEntry>;
+using ContainerTypeEntryCPtr = std::shared_ptr<const ContainerTypeEntry>;
+using CustomTypeEntryCPtr = std::shared_ptr<const CustomTypeEntry>;
+using EnumTypeEntryCPtr = std::shared_ptr<const EnumTypeEntry>;
+using EnumValueTypeEntryCPtr = std::shared_ptr<const EnumValueTypeEntry>;
+using FlagsTypeEntryCPtr = std::shared_ptr<const FlagsTypeEntry>;
+using FunctionTypeEntryCPtr = std::shared_ptr<const FunctionTypeEntry>;
+using NamespaceTypeEntryCPtr = std::shared_ptr<const NamespaceTypeEntry>;
+using ObjectTypeEntryCPtr = std::shared_ptr<const ObjectTypeEntry>;
+using PrimitiveTypeEntryCPtr = std::shared_ptr<const PrimitiveTypeEntry>;
+using SmartPointerTypeEntryCPtr = std::shared_ptr<const SmartPointerTypeEntry>;
+using TemplateEntryCPtr = std::shared_ptr<const TemplateEntry>;
+using TypeEntryCPtr = std::shared_ptr<const TypeEntry>;
+using TypedefEntryCPtr = std::shared_ptr<const TypedefEntry>;
+using TypeSystemTypeEntryCPtr = std::shared_ptr<const TypeSystemTypeEntry>;
+using ValueTypeEntryCPtr = std::shared_ptr<const ValueTypeEntry>;
+
+using ComplexTypeEntryCList = QList<ComplexTypeEntryCPtr>;
+using ContainerTypeEntryCList = QList<ContainerTypeEntryCPtr>;
+using NamespaceTypeEntryList = QList<NamespaceTypeEntryPtr>;
+using PrimitiveTypeEntryCList = QList<PrimitiveTypeEntryCPtr>;
+using SmartPointerTypeEntryList = QList<SmartPointerTypeEntryCPtr>;
+using TypeEntryList = QList<TypeEntryPtr>;
+using TypeEntryCList = QList<TypeEntryCPtr>;
+
+#endif // TYPESYSTEM_TYPEDEFS_H
diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp
new file mode 100644
index 000000000..2b686e997
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp
@@ -0,0 +1,3648 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "typesystemparser_p.h"
+#include "anystringview_helpers.h"
+#include "addedfunction.h"
+#include "codesnip.h"
+#include "enumtypeentry.h"
+#include "containertypeentry.h"
+#include "customconversion.h"
+#include "customtypenentry.h"
+#include "flagstypeentry.h"
+#include "functiontypeentry.h"
+#include "namespacetypeentry.h"
+#include "objecttypeentry.h"
+#include "primitivetypeentry.h"
+#include "smartpointertypeentry.h"
+#include "typedefentry.h"
+#include "typesystemtypeentry.h"
+#include "valuetypeentry.h"
+#include "modifications.h"
+#include "typedatabase.h"
+#include "messages.h"
+#include "reporthandler.h"
+#include "sourcelocation.h"
+#include "conditionalstreamreader.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QSet>
+#include <QtCore/QStringView>
+#include <QtCore/QStringAlgorithms>
+#include <QtCore/QVersionNumber>
+#include <QtCore/QXmlStreamAttributes>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QXmlStreamEntityResolver>
+
+#include <algorithm>
+#include <optional>
+#include <memory>
+
+using namespace Qt::StringLiterals;
+
+constexpr auto allowThreadAttribute = "allow-thread"_L1;
+constexpr auto checkFunctionAttribute = "check-function"_L1;
+constexpr auto copyableAttribute = "copyable"_L1;
+constexpr auto accessAttribute = "access"_L1;
+constexpr auto actionAttribute = "action"_L1;
+constexpr auto quoteAfterLineAttribute = "quote-after-line"_L1;
+constexpr auto quoteBeforeLineAttribute = "quote-before-line"_L1;
+constexpr auto textAttribute = "text"_L1;
+constexpr auto nameAttribute = "name"_L1;
+constexpr auto sinceAttribute = "since"_L1;
+constexpr auto untilAttribute = "until"_L1;
+constexpr auto defaultSuperclassAttribute = "default-superclass"_L1;
+constexpr auto deleteInMainThreadAttribute = "delete-in-main-thread"_L1;
+constexpr auto deprecatedAttribute = "deprecated"_L1;
+constexpr auto disableWrapperAttribute = "disable-wrapper"_L1;
+constexpr auto docFileAttribute = "doc-file"_L1;
+constexpr auto exceptionHandlingAttribute = "exception-handling"_L1;
+constexpr auto extensibleAttribute = "extensible"_L1;
+constexpr auto fileNameAttribute = "file-name"_L1;
+constexpr auto fileAttribute = "file"_L1;
+constexpr auto flagsAttribute = "flags"_L1;
+constexpr auto forceAbstractAttribute = "force-abstract"_L1;
+constexpr auto forceIntegerAttribute = "force-integer"_L1;
+constexpr auto formatAttribute = "format"_L1;
+constexpr auto generateUsingAttribute = "generate-using"_L1;
+constexpr auto generateFunctionsAttribute = "generate-functions"_L1;
+constexpr auto classAttribute = "class"_L1;
+constexpr auto generateAttribute = "generate"_L1;
+constexpr auto generateGetSetDefAttribute = "generate-getsetdef"_L1;
+constexpr auto genericClassAttribute = "generic-class"_L1;
+constexpr auto indexAttribute = "index"_L1;
+constexpr auto invalidateAfterUseAttribute = "invalidate-after-use"_L1;
+constexpr auto isNullAttribute = "isNull"_L1;
+constexpr auto locationAttribute = "location"_L1;
+constexpr auto modifiedTypeAttribute = "modified-type"_L1;
+constexpr auto opaqueContainerAttribute = "opaque-containers"_L1;
+constexpr auto operatorBoolAttribute = "operator-bool"_L1;
+constexpr auto parentManagementAttribute = "parent-management"_L1;
+constexpr auto pyiTypeAttribute = "pyi-type"_L1;
+constexpr auto overloadNumberAttribute = "overload-number"_L1;
+constexpr auto ownershipAttribute = "owner"_L1;
+constexpr auto packageAttribute = "package"_L1;
+constexpr auto polymorphicBaseAttribute = "polymorphic-base"_L1;
+constexpr auto positionAttribute = "position"_L1;
+constexpr auto preferredConversionAttribute = "preferred-conversion"_L1;
+constexpr auto preferredTargetLangTypeAttribute = "preferred-target-lang-type"_L1;
+constexpr auto pythonEnumTypeAttribute = "python-type"_L1;
+constexpr auto pythonOverrideAttribute = "python-override"_L1;
+constexpr auto cppEnumTypeAttribute = "cpp-type"_L1;
+constexpr auto qtMetaObjectFunctionsAttribute = "qt-metaobject"_L1;
+constexpr auto qtMetaTypeAttribute = "qt-register-metatype"_L1;
+constexpr auto removeAttribute = "remove"_L1;
+constexpr auto renameAttribute = "rename"_L1;
+constexpr auto readAttribute = "read"_L1;
+constexpr auto targetLangNameAttribute = "target-lang-name"_L1;
+constexpr auto writeAttribute = "write"_L1;
+constexpr auto opaqueContainerFieldAttribute = "opaque-container"_L1;
+constexpr auto replaceAttribute = "replace"_L1;
+constexpr auto toAttribute = "to"_L1;
+constexpr auto signatureAttribute = "signature"_L1;
+constexpr auto snippetAttribute = "snippet"_L1;
+constexpr auto snakeCaseAttribute = "snake-case"_L1;
+constexpr auto staticAttribute = "static"_L1;
+constexpr auto classmethodAttribute = "classmethod"_L1;
+constexpr auto threadAttribute = "thread"_L1;
+constexpr auto sourceAttribute = "source"_L1;
+constexpr auto streamAttribute = "stream"_L1;
+constexpr auto privateAttribute = "private"_L1;
+constexpr auto xPathAttribute = "xpath"_L1;
+constexpr auto virtualSlotAttribute = "virtual-slot"_L1;
+constexpr auto visibleAttribute = "visible"_L1;
+constexpr auto enumIdentifiedByValueAttribute = "identified-by-value"_L1;
+constexpr auto subModuleOfAttribute = "submodule-of"_L1;
+
+constexpr auto noAttributeValue = "no"_L1;
+constexpr auto yesAttributeValue = "yes"_L1;
+constexpr auto trueAttributeValue = "true"_L1;
+constexpr auto falseAttributeValue = "false"_L1;
+
+static bool isTypeEntry(StackElement el)
+{
+ return el >= StackElement::FirstTypeEntry && el <= StackElement::LastTypeEntry;
+}
+
+static bool isComplexTypeEntry(StackElement el)
+{
+ return el >= StackElement::FirstTypeEntry && el <= StackElement::LastComplexTypeEntry;
+}
+
+static bool isDocumentation(StackElement el)
+{
+ return el >= StackElement::FirstDocumentation && el <= StackElement::LastDocumentation;
+}
+
+static QList<CustomConversionPtr> customConversionsForReview;
+
+// Set a regular expression for rejection from text. By legacy, those are fixed
+// strings, except for '*' meaning 'match all'. Enclosing in "^..$"
+// indicates regular expression.
+static bool setRejectionRegularExpression(const QString &patternIn,
+ QRegularExpression *re,
+ QString *errorMessage)
+{
+ QString pattern;
+ if (patternIn.startsWith(u'^') && patternIn.endsWith(u'$'))
+ pattern = patternIn;
+ else if (patternIn == u"*")
+ pattern = "^.*$"_L1;
+ else
+ pattern = u'^' + QRegularExpression::escape(patternIn) + u'$';
+ re->setPattern(pattern);
+ if (!re->isValid()) {
+ *errorMessage = msgInvalidRegularExpression(patternIn, re->errorString());
+ return false;
+ }
+ return true;
+}
+
+static inline bool hasFileSnippetAttributes(const QXmlStreamAttributes *attributes)
+{
+ return attributes->hasAttribute(fileAttribute);
+}
+
+// Extract a snippet from a file within annotation "// @snippet label".
+std::optional<QString>
+ extractSnippet(const QString &code, const QString &snippetLabel)
+{
+ if (snippetLabel.isEmpty())
+ return code;
+ const QString pattern = R"(^\s*//\s*@snippet\s+)"_L1
+ + QRegularExpression::escape(snippetLabel)
+ + R"(\s*$)"_L1;
+ const QRegularExpression snippetRe(pattern);
+ Q_ASSERT(snippetRe.isValid());
+
+ bool useLine = false;
+ bool foundLabel = false;
+ QString result;
+ const auto lines = QStringView{code}.split(u'\n');
+ for (const auto &line : lines) {
+ if (snippetRe.matchView(line).hasMatch()) {
+ foundLabel = true;
+ useLine = !useLine;
+ if (!useLine)
+ break; // End of snippet reached
+ } else if (useLine)
+ result += line.toString() + u'\n';
+ }
+ if (!foundLabel)
+ return {};
+ return CodeSnipAbstract::fixSpaces(result);
+}
+
+template <class EnumType>
+struct EnumLookup
+{
+ QStringView name;
+ EnumType value;
+};
+
+// Helper macros to define lookup functions that take a QStringView needle
+// and an optional default return value.
+#define ENUM_LOOKUP_BEGIN(EnumType, caseSensitivity, functionName) \
+static std::optional<EnumType> functionName(QStringView needle) \
+{ \
+ using HaystackEntry = EnumLookup<EnumType>; \
+ constexpr auto cs = caseSensitivity; \
+ static constexpr HaystackEntry haystack[] =
+
+#define ENUM_LOOKUP_LINEAR_SEARCH \
+ auto pred = [cs, needle](const HaystackEntry &he) { \
+ return he.name.compare(needle, cs) == 0; \
+ }; \
+ auto end = std::cend(haystack); \
+ auto it = std::find_if(std::cbegin(haystack), end, pred); \
+ if (it != end) \
+ return it->value; \
+ return std::nullopt; \
+}
+
+ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive,
+ allowThreadFromAttribute)
+ {
+ {u"yes", TypeSystem::AllowThread::Allow},
+ {u"true", TypeSystem::AllowThread::Allow},
+ {u"auto", TypeSystem::AllowThread::Auto},
+ {u"no", TypeSystem::AllowThread::Disallow},
+ {u"false", TypeSystem::AllowThread::Disallow},
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+
+ENUM_LOOKUP_BEGIN(TypeSystem::BoolCast, Qt::CaseInsensitive,
+ boolCastFromAttribute)
+ {
+ {u"yes", TypeSystem::BoolCast::Enabled},
+ {u"true", TypeSystem::BoolCast::Enabled},
+ {u"no", TypeSystem::BoolCast::Disabled},
+ {u"false", TypeSystem::BoolCast::Disabled},
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeSystem::PythonEnumType, Qt::CaseSensitive,
+ pythonEnumTypeFromAttribute)
+ {
+ {u"Enum", TypeSystem::PythonEnumType::Enum},
+ {u"IntEnum", TypeSystem::PythonEnumType::IntEnum},
+ {u"Flag", TypeSystem::PythonEnumType::Flag},
+ {u"IntFlag", TypeSystem::PythonEnumType::IntFlag},
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeSystem::QtMetaTypeRegistration, Qt::CaseSensitive,
+ qtMetaTypeFromAttribute)
+ {
+ {u"yes", TypeSystem::QtMetaTypeRegistration::Enabled},
+ {u"true", TypeSystem::QtMetaTypeRegistration::Enabled},
+ {u"base", TypeSystem::QtMetaTypeRegistration::BaseEnabled},
+ {u"no", TypeSystem::QtMetaTypeRegistration::Disabled},
+ {u"false", TypeSystem::QtMetaTypeRegistration::Disabled},
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive,
+ languageFromAttribute)
+ {
+ {u"all", TypeSystem::All}, // sorted!
+ {u"native", TypeSystem::NativeCode}, // em algum lugar do cpp
+ {u"shell", TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe
+ {u"target", TypeSystem::TargetLangCode} // em algum lugar do cpp
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive,
+ ownershipFromFromAttribute)
+ {
+ {u"target", TypeSystem::TargetLangOwnership},
+ {u"c++", TypeSystem::CppOwnership},
+ {u"default", TypeSystem::DefaultOwnership}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive,
+ addedFunctionAccessFromAttribute)
+ {
+ {u"public", AddedFunction::Public},
+ {u"protected", AddedFunction::Protected},
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(FunctionModification::ModifierFlag, Qt::CaseSensitive,
+ modifierFromAttribute)
+ {
+ {u"private", FunctionModification::Private},
+ {u"public", FunctionModification::Public},
+ {u"protected", FunctionModification::Protected},
+ {u"rename", FunctionModification::Rename},
+ {u"final", FunctionModification::Final},
+ {u"non-final", FunctionModification::NonFinal}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive,
+ referenceCountFromAttribute)
+ {
+ {u"add", ReferenceCount::Add},
+ {u"add-all", ReferenceCount::AddAll},
+ {u"remove", ReferenceCount::Remove},
+ {u"set", ReferenceCount::Set},
+ {u"ignore", ReferenceCount::Ignore}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive,
+ argumentOwnerActionFromAttribute)
+ {
+ {u"add", ArgumentOwner::Add},
+ {u"remove", ArgumentOwner::Remove}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive,
+ codeSnipPositionFromAttribute)
+ {
+ {u"beginning", TypeSystem::CodeSnipPositionBeginning},
+ {u"end", TypeSystem::CodeSnipPositionEnd},
+ {u"declaration", TypeSystem::CodeSnipPositionDeclaration},
+ {u"override", TypeSystem::CodeSnipPositionPyOverride}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive,
+ locationFromAttribute)
+ {
+ {u"global", Include::IncludePath},
+ {u"local", Include::LocalPath},
+ {u"target", Include::TargetLangImport}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive,
+ docModificationFromAttribute)
+ {
+ {u"append", TypeSystem::DocModificationAppend},
+ {u"prepend", TypeSystem::DocModificationPrepend},
+ {u"replace", TypeSystem::DocModificationReplace}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(ContainerTypeEntry::ContainerKind, Qt::CaseSensitive,
+ containerTypeFromAttribute)
+ {
+ {u"list", ContainerTypeEntry::ListContainer},
+ {u"string-list", ContainerTypeEntry::ListContainer},
+ {u"linked-list", ContainerTypeEntry::ListContainer},
+ {u"vector", ContainerTypeEntry::ListContainer},
+ {u"stack", ContainerTypeEntry::ListContainer},
+ {u"queue", ContainerTypeEntry::ListContainer},
+ {u"set", ContainerTypeEntry::SetContainer},
+ {u"map", ContainerTypeEntry::MapContainer},
+ {u"multi-map", ContainerTypeEntry::MultiMapContainer},
+ {u"hash", ContainerTypeEntry::MapContainer},
+ {u"multi-hash", ContainerTypeEntry::MultiMapContainer},
+ {u"pair", ContainerTypeEntry::PairContainer},
+ {u"span", ContainerTypeEntry::SpanContainer}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive,
+ typeRejectionFromAttribute)
+ {
+ {u"class", TypeRejection::ExcludeClass},
+ {u"function-name", TypeRejection::Function},
+ {u"field-name", TypeRejection::Field},
+ {u"enum-name", TypeRejection::Enum },
+ {u"argument-type", TypeRejection::ArgumentType},
+ {u"return-type", TypeRejection::ReturnType}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive,
+ exceptionHandlingFromAttribute)
+{
+ {u"no", TypeSystem::ExceptionHandling::Off},
+ {u"false", TypeSystem::ExceptionHandling::Off},
+ {u"auto-off", TypeSystem::ExceptionHandling::AutoDefaultToOff},
+ {u"auto-on", TypeSystem::ExceptionHandling::AutoDefaultToOn},
+ {u"yes", TypeSystem::ExceptionHandling::On},
+ {u"true", TypeSystem::ExceptionHandling::On},
+};
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeSystem::SmartPointerType, Qt::CaseSensitive,
+ smartPointerTypeFromAttribute)
+{
+ {u"handle", TypeSystem::SmartPointerType::Handle},
+ {u"unique", TypeSystem::SmartPointerType::Unique},
+ {u"value-handle", TypeSystem::SmartPointerType::ValueHandle},
+ {u"shared", TypeSystem::SmartPointerType::Shared}
+};
+ENUM_LOOKUP_LINEAR_SEARCH
+
+template <class EnumType>
+static std::optional<EnumType>
+ lookupHashElement(const QHash<QStringView, EnumType> &hash,
+ QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive)
+{
+ auto end = hash.cend();
+ auto it = hash.constFind(needle);
+ if (it != end)
+ return it.value();
+ if (cs == Qt::CaseInsensitive) { // brute force search for the unlikely case mismatch
+ for (it = hash.cbegin(); it != end; ++it) {
+ if (it.key().compare(needle, cs) == 0)
+ return it.value();
+ }
+ }
+ return std::nullopt;
+}
+
+using StackElementHash = QHash<QStringView, StackElement>;
+
+static const StackElementHash &stackElementHash()
+{
+ static const StackElementHash result{
+ {u"add-conversion", StackElement::AddConversion},
+ {u"add-function", StackElement::AddFunction},
+ {u"add-pymethoddef", StackElement::AddPyMethodDef},
+ {u"array", StackElement::Array},
+ {u"configuration", StackElement::Configuration},
+ {u"container-type", StackElement::ContainerTypeEntry},
+ {u"conversion-rule", StackElement::ConversionRule},
+ {u"custom-constructor", StackElement::Unimplemented},
+ {u"custom-destructor", StackElement::Unimplemented},
+ {u"custom-type", StackElement::CustomTypeEntry},
+ {u"declare-function", StackElement::DeclareFunction},
+ {u"define-ownership", StackElement::DefineOwnership},
+ {u"enum-type", StackElement::EnumTypeEntry},
+ {u"extra-includes", StackElement::ExtraIncludes},
+ {u"function", StackElement::FunctionTypeEntry},
+ {u"import-file", StackElement::ImportFile},
+ {u"include", StackElement::Include},
+ {u"inject-code", StackElement::InjectCode},
+ {u"inject-documentation", StackElement::InjectDocumentation},
+ {u"insert-template", StackElement::InsertTemplate},
+ {u"interface-type", StackElement::InterfaceTypeEntry},
+ {u"load-typesystem", StackElement::LoadTypesystem},
+ {u"modify-argument", StackElement::ModifyArgument},
+ {u"modify-documentation", StackElement::ModifyDocumentation},
+ {u"modify-field", StackElement::ModifyField},
+ {u"modify-function", StackElement::ModifyFunction},
+ {u"namespace-type", StackElement::NamespaceTypeEntry},
+ {u"native-to-target", StackElement::NativeToTarget},
+ {u"no-null-pointer", StackElement::NoNullPointers},
+ {u"object-type", StackElement::ObjectTypeEntry},
+ {u"opaque-container", StackElement::OpaqueContainer},
+ {u"parent", StackElement::ParentOwner},
+ {u"primitive-type", StackElement::PrimitiveTypeEntry},
+ {u"property", StackElement::Property},
+ {u"reference-count", StackElement::ReferenceCount},
+ {u"reject-enum-value", StackElement::RejectEnumValue},
+ {u"rejection", StackElement::Rejection},
+ {u"remove-argument", StackElement::RemoveArgument},
+ {u"remove-default-expression", StackElement::RemoveDefaultExpression},
+ {u"rename", StackElement::Rename}, // ### fixme PySide7: remove
+ {u"replace", StackElement::Replace},
+ {u"replace-default-expression", StackElement::ReplaceDefaultExpression},
+ {u"replace-type", StackElement::ReplaceType},
+ {u"smart-pointer-type", StackElement::SmartPointerTypeEntry},
+ {u"suppress-warning", StackElement::SuppressedWarning},
+ {u"system-include", StackElement::SystemInclude},
+ {u"target-to-native", StackElement::TargetToNative},
+ {u"template", StackElement::Template},
+ {u"typedef-type", StackElement::TypedefTypeEntry},
+ {u"typesystem", StackElement::Root},
+ {u"value-type", StackElement::ValueTypeEntry},
+ };
+ return result;
+}
+
+static std::optional<StackElement> elementFromTag(QStringView needle)
+{
+ return lookupHashElement(stackElementHash(), needle,
+ Qt::CaseInsensitive); // FIXME PYSIDE-7: case sensitive
+}
+
+static QStringView tagFromElement(StackElement st)
+{
+ return stackElementHash().key(st);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, StackElement st)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << tagFromElement(st);
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM
+
+ENUM_LOOKUP_BEGIN(TypeSystem::SnakeCase, Qt::CaseSensitive,
+ snakeCaseFromAttribute)
+{
+ {u"no", TypeSystem::SnakeCase::Disabled},
+ {u"false", TypeSystem::SnakeCase::Disabled},
+ {u"yes", TypeSystem::SnakeCase::Enabled},
+ {u"true", TypeSystem::SnakeCase::Enabled},
+ {u"both", TypeSystem::SnakeCase::Both},
+};
+ENUM_LOOKUP_LINEAR_SEARCH
+
+ENUM_LOOKUP_BEGIN(TypeSystem::Visibility, Qt::CaseSensitive,
+ visibilityFromAttribute)
+{
+ {u"no", TypeSystem::Visibility::Invisible},
+ {u"false", TypeSystem::Visibility::Invisible},
+ {u"auto", TypeSystem::Visibility::Auto},
+ {u"yes", TypeSystem::Visibility::Visible},
+ {u"true", TypeSystem::Visibility::Visible},
+};
+ENUM_LOOKUP_LINEAR_SEARCH
+
+static int indexOfAttribute(const QXmlStreamAttributes &atts,
+ QAnyStringView name)
+{
+ for (qsizetype i = 0, size = atts.size(); i < size; ++i) {
+ if (atts.at(i).qualifiedName() == name)
+ return i;
+ }
+ return -1;
+}
+
+static QString msgMissingAttribute(const QString &a)
+{
+ return u"Required attribute '"_s + a
+ + u"' missing."_s;
+}
+
+QTextStream &operator<<(QTextStream &str, const QXmlStreamAttribute &attribute)
+{
+ str << attribute.qualifiedName() << "=\"" << attribute.value() << '"';
+ return str;
+}
+
+static QString msgInvalidAttributeValue(const QXmlStreamAttribute &attribute)
+{
+ QString result;
+ QTextStream(&result) << "Invalid attribute value:" << attribute;
+ return result;
+}
+
+static QString msgUnusedAttributes(QStringView tag, const QXmlStreamAttributes &attributes)
+{
+ QString result;
+ QTextStream str(&result);
+ str << attributes.size() << " attributes(s) unused on <" << tag << ">: ";
+ for (qsizetype i = 0, size = attributes.size(); i < size; ++i) {
+ if (i)
+ str << ", ";
+ str << attributes.at(i);
+ }
+ return result;
+}
+
+// QXmlStreamEntityResolver::resolveEntity(publicId, systemId) is not
+// implemented; resolve via undeclared entities instead.
+class TypeSystemEntityResolver : public QXmlStreamEntityResolver
+{
+public:
+ explicit TypeSystemEntityResolver(const QString &currentPath) :
+ m_currentPath(currentPath) {}
+
+ QString resolveUndeclaredEntity(const QString &name) override;
+
+private:
+ QString readFile(const QString &entityName, QString *errorMessage) const;
+
+ const QString m_currentPath;
+};
+
+QString TypeSystemEntityResolver::readFile(const QString &entityName, QString *errorMessage) const
+{
+ QString fileName = entityName;
+ if (!fileName.contains(u'.'))
+ fileName += u".xml"_s;
+ QString path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath);
+ if (!QFileInfo::exists(path)) // PySide6-specific hack
+ fileName.prepend(u"typesystem_"_s);
+ path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath);
+ if (!QFileInfo::exists(path)) {
+ *errorMessage = u"Unable to resolve: "_s + entityName;
+ return {};
+ }
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ *errorMessage = msgCannotOpenForReading(file);
+ return {};
+ }
+ QString result = QString::fromUtf8(file.readAll()).trimmed();
+ // Remove license header comments on which QXmlStreamReader chokes
+ if (result.startsWith(u"<!--")) {
+ const auto commentEnd = result.indexOf(u"-->");
+ if (commentEnd != -1) {
+ result.remove(0, commentEnd + 3);
+ result = result.trimmed();
+ }
+ }
+ return result;
+}
+
+QString TypeSystemEntityResolver::resolveUndeclaredEntity(const QString &name)
+{
+ QString errorMessage;
+ const QString result = readFile(name, &errorMessage);
+ if (result.isEmpty()) { // The parser will fail and display the line number.
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgCannotResolveEntity(name, errorMessage)));
+ }
+ return result;
+}
+
+// State depending on element stack
+enum class ParserState
+{
+ None,
+ PrimitiveTypeNativeToTargetConversion,
+ PrimitiveTypeTargetToNativeConversion,
+ ArgumentConversion, // Argument conversion rule with class attribute
+ ArgumentNativeToTargetConversion,
+ ArgumentTargetToNativeConversion,
+ FunctionCodeInjection,
+ TypeEntryCodeInjection,
+ TypeSystemCodeInjection,
+ Template
+};
+
+TypeSystemParser::TypeSystemParser(const std::shared_ptr<TypeDatabaseParserContext> &context,
+ bool generate) :
+ m_context(context),
+ m_generate(generate ? TypeEntry::GenerateCode : TypeEntry::GenerateForSubclass)
+{
+}
+
+TypeSystemParser::~TypeSystemParser() = default;
+
+static QString readerFileName(const ConditionalStreamReader &reader)
+{
+ const auto *file = qobject_cast<const QFile *>(reader.device());
+ return file != nullptr ? file->fileName() : QString();
+}
+
+static QString msgReaderMessage(const ConditionalStreamReader &reader,
+ const char *type,
+ const QString &what)
+{
+ QString message;
+ QTextStream str(&message);
+ const QString fileName = readerFileName(reader);
+ if (fileName.isEmpty())
+ str << "<stdin>:";
+ else
+ str << QDir::toNativeSeparators(fileName) << ':';
+ // Use a tab separator like SourceLocation for suppression detection
+ str << reader.lineNumber() << ':' << reader.columnNumber()
+ << ":\t" << type << ": " << what;
+ return message;
+}
+
+static QString msgReaderWarning(const ConditionalStreamReader &reader, const QString &what)
+{
+ return msgReaderMessage(reader, "Warning", what);
+}
+
+static QString msgReaderError(const ConditionalStreamReader &reader, const QString &what)
+{
+ return msgReaderMessage(reader, "Error", what);
+}
+
+static QString msgUnimplementedElementWarning(const ConditionalStreamReader &reader,
+ QAnyStringView name)
+{
+ QString message;
+ QTextStream(&message) << "The element \"" << name
+ << "\" is not implemented.";
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static QString msgUnimplementedAttributeWarning(const ConditionalStreamReader &reader,
+ QStringView name)
+{
+ QString message;
+ QTextStream(&message) << "The attribute \"" << name
+ << "\" is not implemented.";
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static inline QString msgUnimplementedAttributeWarning(const ConditionalStreamReader &reader,
+ const QXmlStreamAttribute &attribute)
+{
+ return msgUnimplementedAttributeWarning(reader, attribute.qualifiedName());
+}
+
+static QString
+ msgUnimplementedAttributeValueWarning(const ConditionalStreamReader &reader,
+ QAnyStringView name, QAnyStringView value)
+{
+ QString message;
+ QTextStream(&message) << "The value \"" << value
+ << "\" of the attribute \"" << name << "\" is not implemented.";
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static inline
+ QString msgUnimplementedAttributeValueWarning(const ConditionalStreamReader &reader,
+ const QXmlStreamAttribute &attribute)
+{
+ return msgUnimplementedAttributeValueWarning(reader,
+ attribute.qualifiedName(),
+ attribute.value());
+}
+
+static bool addRejection(TypeDatabase *database, bool generate, QXmlStreamAttributes *attributes,
+ QString *errorMessage)
+{
+ const auto classIndex = indexOfAttribute(*attributes, classAttribute);
+ if (classIndex == -1) {
+ *errorMessage = msgMissingAttribute(classAttribute);
+ return false;
+ }
+
+ TypeRejection rejection;
+ rejection.generate = generate;
+ const QString className = attributes->takeAt(classIndex).value().toString();
+ if (!setRejectionRegularExpression(className, &rejection.className, errorMessage))
+ return false;
+
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto &attribute = attributes->at(i);
+ const auto name = attribute.qualifiedName();
+ const auto typeOpt = typeRejectionFromAttribute(name);
+ if (!typeOpt.has_value()) {
+ *errorMessage = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ switch (typeOpt.value()) {
+ case TypeRejection::Function:
+ case TypeRejection::Field:
+ case TypeRejection::Enum:
+ case TypeRejection::ArgumentType:
+ case TypeRejection::ReturnType: {
+ const QString pattern = attributes->takeAt(i).value().toString();
+ if (!setRejectionRegularExpression(pattern, &rejection.pattern, errorMessage))
+ return false;
+ rejection.matchType = typeOpt.value();
+ database->addRejection(rejection);
+ return true;
+ }
+ case TypeRejection::ExcludeClass:
+ break;
+ }
+ }
+
+ // Special case: When all fields except class are empty, completely exclude class
+ if (className == u"*") {
+ *errorMessage = u"bad reject entry, neither 'class', 'function-name'"
+ " nor 'field' specified"_s;
+ return false;
+ }
+ rejection.matchType = TypeRejection::ExcludeClass;
+ database->addRejection(rejection);
+ return true;
+}
+
+bool TypeSystemParser::parse(ConditionalStreamReader &reader)
+{
+ m_error.clear();
+ m_currentPath.clear();
+ m_currentFile.clear();
+ return parseXml(reader);
+}
+
+bool TypeSystemParser::parseXml(ConditionalStreamReader &reader)
+{
+ const QString fileName = readerFileName(reader);
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ m_currentPath = fi.absolutePath();
+ m_currentFile = fi.absoluteFilePath();
+ }
+ m_entityResolver.reset(new TypeSystemEntityResolver(m_currentPath));
+ reader.setEntityResolver(m_entityResolver.data());
+
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::NoToken:
+ case QXmlStreamReader::Invalid:
+ m_error = msgReaderError(reader, reader.errorString());
+ return false;
+ case QXmlStreamReader::StartElement: {
+ const auto elementTypeOpt = elementFromTag(reader.name());
+ if (!elementTypeOpt.has_value()) {
+ m_error = u"Unknown tag name: '"_s + reader.name().toString() + u'\'';
+ return false;
+ }
+ m_stack.push(elementTypeOpt.value());
+ if (!startElement(reader, m_stack.top())) {
+ m_error = msgReaderError(reader, m_error);
+ return false;
+ }
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ if (!endElement(m_stack.top())) {
+ m_error = msgReaderError(reader, m_error);
+ return false;
+ }
+ m_stack.pop();
+ break;
+ case QXmlStreamReader::Characters:
+ if (!characters(reader.text())) {
+ m_error = msgReaderError(reader, m_error);
+ return false;
+ }
+ break;
+ case QXmlStreamReader::StartDocument:
+ case QXmlStreamReader::EndDocument:
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::DTD:
+ case QXmlStreamReader::EntityReference:
+ case QXmlStreamReader::ProcessingInstruction:
+ break;
+ }
+ }
+ return true;
+}
+
+bool TypeSystemParser::endElement(StackElement element)
+{
+ if (m_ignoreDepth) {
+ --m_ignoreDepth;
+ return true;
+ }
+
+ if (m_currentDroppedEntryDepth != 0) {
+ --m_currentDroppedEntryDepth;
+ return true;
+ }
+
+ if (element == StackElement::ImportFile)
+ return true;
+
+ if (m_contextStack.isEmpty())
+ return true;
+
+ const auto &top = m_contextStack.top();
+
+ switch (element) {
+ case StackElement::Unimplemented:
+ return true;
+ case StackElement::Root:
+ if (m_generate == TypeEntry::GenerateCode) {
+ TypeDatabase::instance()->addGlobalUserFunctions(top->addedFunctions);
+ TypeDatabase::instance()->addGlobalUserFunctionModifications(top->functionMods);
+ for (const auto &customConversion : std::as_const(customConversionsForReview)) {
+ TargetToNativeConversions &toNatives =
+ customConversion->targetToNativeConversions();
+ for (auto &toNative : toNatives)
+ toNative.setSourceType(m_context->db->findType(toNative.sourceTypeName()));
+ }
+ }
+ purgeEmptyCodeSnips(&std::static_pointer_cast<TypeSystemTypeEntry>(top->entry)->codeSnips());
+ break;
+ case StackElement::FunctionTypeEntry:
+ TypeDatabase::instance()->addGlobalUserFunctionModifications(top->functionMods);
+ break;
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::ContainerTypeEntry:
+ case StackElement::NamespaceTypeEntry: {
+ Q_ASSERT(top->entry);
+ Q_ASSERT(top->entry->isComplex());
+ auto centry = std::static_pointer_cast<ComplexTypeEntry>(top->entry);
+ purgeEmptyCodeSnips(&centry->codeSnips());
+ centry->setAddedFunctions(top->addedFunctions);
+ centry->setFunctionModifications(top->functionMods);
+ centry->setFieldModifications(top->fieldMods);
+ centry->setDocModification(top->docModifications);
+ }
+ break;
+
+ case StackElement::TypedefTypeEntry: {
+ auto centry = std::static_pointer_cast<TypedefEntry>(top->entry)->target();
+ centry->setAddedFunctions(centry->addedFunctions() + top->addedFunctions);
+ centry->setFunctionModifications(centry->functionModifications() + top->functionMods);
+ centry->setFieldModifications(centry->fieldModifications() + top->fieldMods);
+ centry->setDocModification(centry->docModifications() + top->docModifications);
+ if (top->entry->isComplex()) {
+ auto cte = std::static_pointer_cast<const ComplexTypeEntry>(top->entry);
+ centry->setCodeSnips(centry->codeSnips() + cte->codeSnips());
+ }
+ }
+ break;
+
+ case StackElement::AddFunction:
+ case StackElement::DeclareFunction: {
+ // Leaving add-function: Assign all modifications to the added function
+ const int modIndex = top->addedFunctionModificationIndex;
+ top->addedFunctionModificationIndex = -1;
+ Q_ASSERT(modIndex >= 0);
+ Q_ASSERT(!top->addedFunctions.isEmpty());
+ while (modIndex < top->functionMods.size())
+ top->addedFunctions.last()->modifications().append(top->functionMods.takeAt(modIndex));
+ }
+ break;
+ case StackElement::NativeToTarget:
+ case StackElement::AddConversion:
+ switch (parserState()) {
+ case ParserState::PrimitiveTypeNativeToTargetConversion:
+ case ParserState::PrimitiveTypeTargetToNativeConversion: {
+ auto customConversion = CustomConversion::getCustomConversion(top->entry);
+ if (!customConversion) {
+ m_error = msgMissingCustomConversion(top->entry);
+ return false;
+ }
+ QString code = top->conversionCodeSnips.constLast().code();
+ if (element == StackElement::AddConversion) {
+ if (customConversion->targetToNativeConversions().isEmpty()) {
+ m_error = u"CustomConversion's target to native conversions missing."_s;
+ return false;
+ }
+ customConversion->targetToNativeConversions().last().setConversion(code);
+ } else {
+ customConversion->setNativeToTargetConversion(code);
+ }
+ }
+ break;
+
+ case ParserState::ArgumentNativeToTargetConversion: {
+ top->conversionCodeSnips.last().language = TypeSystem::TargetLangCode;
+ auto &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods().last();
+ lastArgMod.conversionRules().append(top->conversionCodeSnips.constLast());
+ }
+ break;
+ case ParserState::ArgumentTargetToNativeConversion: {
+ top->conversionCodeSnips.last().language = TypeSystem::NativeCode;
+ auto &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods().last();
+ lastArgMod.conversionRules().append(top->conversionCodeSnips.constLast());
+ }
+ break;
+ default:
+ break;
+ }
+ top->conversionCodeSnips.clear();
+ break;
+
+ case StackElement::EnumTypeEntry:
+ m_currentEnum = nullptr;
+ break;
+ case StackElement::Template:
+ m_context->db->addTemplate(m_templateEntry);
+ m_templateEntry = nullptr;
+ break;
+ case StackElement::InsertTemplate:
+ if (auto *snip = injectCodeTarget(1))
+ snip->addTemplateInstance(m_templateInstance);
+ m_templateInstance.reset();
+ break;
+
+ case StackElement::ModifyArgument:
+ purgeEmptyCodeSnips(&top->functionMods.last().argument_mods().last().conversionRules());
+ break;
+
+ default:
+ break;
+ }
+
+ if (isTypeEntry(element) || element == StackElement::Root)
+ m_contextStack.pop();
+
+ return true;
+}
+
+ParserState TypeSystemParser::parserState(qsizetype offset) const
+{
+ const auto stackSize = m_stack.size() - offset;
+ if (stackSize <= 0 || m_contextStack.isEmpty())
+ return ParserState::None;
+
+ const auto last = stackSize - 1;
+
+ switch (m_stack.at(last)) {
+ // Primitive entry with conversion rule
+ case StackElement::NativeToTarget: // <conversion-rule><native-to-target>
+ if (stackSize > 2 && m_stack.at(last - 2) == StackElement::ModifyArgument)
+ return ParserState::ArgumentNativeToTargetConversion;
+ return ParserState::PrimitiveTypeNativeToTargetConversion;
+
+ case StackElement::AddConversion: // <conversion-rule><target-to-native><add-conversion>
+ if (stackSize > 3 && m_stack.at(last - 3) == StackElement::ModifyArgument)
+ return ParserState::ArgumentTargetToNativeConversion;
+ return ParserState::PrimitiveTypeTargetToNativeConversion;
+
+ case StackElement::ConversionRule:
+ if (stackSize > 1 && m_stack.at(last - 1) == StackElement::ModifyArgument)
+ return ParserState::ArgumentConversion;
+ break;
+
+ case StackElement::InjectCode:
+ switch (m_stack.value(last - 1, StackElement::None)) {
+ case StackElement::Root:
+ return ParserState::TypeSystemCodeInjection;
+ case StackElement::ModifyFunction:
+ case StackElement::AddFunction:
+ return ParserState::FunctionCodeInjection;
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ return ParserState::TypeEntryCodeInjection;
+ default:
+ break;
+ }
+ break;
+
+ case StackElement::Template:
+ return ParserState::Template;
+
+ default:
+ break;
+ }
+
+ return ParserState::None;
+}
+
+// Return where to add injected code depending on elements.
+CodeSnipAbstract *TypeSystemParser::injectCodeTarget(qsizetype offset) const
+{
+ const auto state = parserState(offset);
+ if (state == ParserState::None)
+ return nullptr;
+
+ const auto &top = m_contextStack.top();
+ switch (state) {
+ case ParserState::PrimitiveTypeNativeToTargetConversion:
+ case ParserState::PrimitiveTypeTargetToNativeConversion:
+ case ParserState::ArgumentNativeToTargetConversion:
+ case ParserState::ArgumentTargetToNativeConversion:
+ return &top->conversionCodeSnips.last();
+ case ParserState::ArgumentConversion:
+ return &top->functionMods.last().argument_mods().last().conversionRules().last();
+ case ParserState::FunctionCodeInjection: {
+ auto &funcMod = top->functionMods.last();
+ funcMod.setModifierFlag(FunctionModification::CodeInjection);
+ return &funcMod.snips().last();
+ }
+ case ParserState::TypeEntryCodeInjection:
+ Q_ASSERT(top->entry->isComplex());
+ return &std::static_pointer_cast<ComplexTypeEntry>(top->entry)->codeSnips().last();
+ case ParserState::TypeSystemCodeInjection:
+ Q_ASSERT(top->entry->isTypeSystem());
+ return &std::static_pointer_cast<TypeSystemTypeEntry>(top->entry)->codeSnips().last();
+ case ParserState::Template:
+ return m_templateEntry.get();
+ default:
+ break;
+ }
+
+ return nullptr;
+}
+
+template <class String> // QString/QStringRef
+bool TypeSystemParser::characters(const String &ch)
+{
+ const auto stackSize = m_stack.size();
+ if (m_currentDroppedEntryDepth != 0 || m_ignoreDepth != 0
+ || stackSize == 0 || m_stack.top() == StackElement::Unimplemented) {
+ return true;
+ }
+
+ const StackElement type = m_stack.top();
+
+ if (type == StackElement::Template) {
+ m_templateEntry->addCode(ch);
+ return true;
+ }
+
+ if (m_contextStack.isEmpty()) {
+ m_error = msgNoRootTypeSystemEntry();
+ return false;
+ }
+
+ if (auto *snip = injectCodeTarget()) {
+ snip->addCode(ch);
+ return true;
+ }
+
+ if (isDocumentation(type)) {
+ const bool isAddedFunction = m_stack.value(m_stack.size() - 2, StackElement::None)
+ == StackElement::AddFunction;
+ const auto &top = m_contextStack.top();
+ auto &docModifications = isAddedFunction
+ ? top->addedFunctions.last()->docModifications()
+ : top->docModifications;
+ docModifications.last().setCode(ch);
+ }
+
+ return true;
+}
+
+bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts)
+{
+ const QString fileName = atts.value(nameAttribute).toString();
+ if (fileName.isEmpty()) {
+ m_error = u"Required attribute 'name' missing for include-file tag."_s;
+ return false;
+ }
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ file.setFileName(u":/trolltech/generator/"_s + fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_error = msgCannotOpenForReading(file);
+ return false;
+ }
+ }
+
+ const auto quoteFrom = atts.value(quoteAfterLineAttribute);
+ bool foundFromOk = quoteFrom.isEmpty();
+ bool from = quoteFrom.isEmpty();
+
+ const auto quoteTo = atts.value(quoteBeforeLineAttribute);
+ bool foundToOk = quoteTo.isEmpty();
+ bool to = true;
+
+ QTextStream in(&file);
+ while (!in.atEnd()) {
+ QString line = in.readLine();
+ if (from && to && line.contains(quoteTo)) {
+ to = false;
+ foundToOk = true;
+ break;
+ }
+ if (from && to)
+ characters(line + u'\n');
+ if (!from && line.contains(quoteFrom)) {
+ from = true;
+ foundFromOk = true;
+ }
+ }
+ if (!foundFromOk || !foundToOk) {
+ QString fromError = QString::fromLatin1("Could not find quote-after-line='%1' in file '%2'.")
+ .arg(quoteFrom.toString(), fileName);
+ QString toError = QString::fromLatin1("Could not find quote-before-line='%1' in file '%2'.")
+ .arg(quoteTo.toString(), fileName);
+
+ if (!foundToOk)
+ m_error = toError;
+ if (!foundFromOk)
+ m_error = fromError;
+ if (!foundFromOk && !foundToOk)
+ m_error = fromError + u' ' + toError;
+ return false;
+ }
+
+ return true;
+}
+
+static bool convertBoolean(QStringView value, QAnyStringView attributeName, bool defaultValue)
+{
+ if (value.compare(trueAttributeValue, Qt::CaseInsensitive) == 0
+ || value.compare(yesAttributeValue, Qt::CaseInsensitive) == 0) {
+ return true;
+ }
+ if (value.compare(falseAttributeValue, Qt::CaseInsensitive) == 0
+ || value.compare(noAttributeValue, Qt::CaseInsensitive) == 0) {
+ return false;
+ }
+ qCWarning(lcShiboken).noquote().nospace() << "Boolean value '" << value
+ << "' not supported in attribute '" << attributeName
+ << "'. Use 'yes' or 'no'. Defaulting to '"
+ << (defaultValue ? yesAttributeValue : noAttributeValue) << "'.";
+ return defaultValue;
+}
+
+static bool convertRemovalAttribute(QStringView value)
+{
+ return value == u"all" // Legacy
+ || convertBoolean(value, removeAttribute, false);
+}
+
+// Check whether an entry should be dropped, allowing for dropping the module
+// name (match 'Class' and 'Module.Class').
+static bool shouldDropTypeEntry(const TypeDatabase *db,
+ const TypeSystemParser::ContextStack &stack ,
+ QString name)
+{
+ for (auto i = stack.size() - 1; i >= 0; --i) {
+ if (auto entry = stack.at(i)->entry) {
+ if (entry->type() == TypeEntry::TypeSystemType) {
+ if (db->shouldDropTypeEntry(name)) // Unqualified
+ return true;
+ }
+ name.prepend(u'.');
+ name.prepend(entry->name());
+ }
+ }
+ return db->shouldDropTypeEntry(name);
+}
+
+// Returns empty string if there's no error.
+static QString checkSignatureError(const QString& signature, const QString& tag)
+{
+ QString funcName = signature.left(signature.indexOf(u'(')).trimmed();
+ static const QRegularExpression whiteSpace("\\s"_L1);
+ Q_ASSERT(whiteSpace.isValid());
+ if (!funcName.startsWith(u"operator ") && funcName.contains(whiteSpace)) {
+ return QString::fromLatin1("Error in <%1> tag signature attribute '%2'.\n"
+ "White spaces aren't allowed in function names, "
+ "and return types should not be part of the signature.")
+ .arg(tag, signature);
+ }
+ return QString();
+}
+
+inline TypeEntryCPtr TypeSystemParser::currentParentTypeEntry() const
+{
+ const auto size = m_contextStack.size();
+ return size > 1 ? m_contextStack.at(size - 2)->entry : nullptr;
+}
+
+bool TypeSystemParser::checkRootElement()
+{
+ for (auto i = m_contextStack.size() - 1; i >= 0; --i) {
+ auto e = m_contextStack.at(i)->entry;
+ if (e && e->isTypeSystem())
+ return true;
+ }
+ m_error = msgNoRootTypeSystemEntry();
+ return false;
+}
+
+static TypeEntryPtr findViewedType(const QString &name)
+{
+ const auto range = TypeDatabase::instance()->entries().equal_range(name);
+ for (auto i = range.first; i != range.second; ++i) {
+ switch (i.value()->type()) {
+ case TypeEntry::BasicValueType:
+ case TypeEntry::PrimitiveType:
+ case TypeEntry::ContainerType:
+ case TypeEntry::ObjectType:
+ return i.value();
+ default:
+ break;
+ }
+ }
+ return nullptr;
+}
+
+bool TypeSystemParser::applyCommonAttributes(const ConditionalStreamReader &reader,
+ const TypeEntryPtr &type,
+ QXmlStreamAttributes *attributes)
+{
+ type->setSourceLocation(SourceLocation(m_currentFile,
+ reader.lineNumber()));
+ type->setCodeGeneration(m_generate);
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == u"revision") {
+ type->setRevision(attributes->takeAt(i).value().toInt());
+ } else if (name == u"view-on") {
+ const QString name = attributes->takeAt(i).value().toString();
+ TypeEntryPtr views = findViewedType(name);
+ if (!views) {
+ m_error = msgCannotFindView(name, type->name());
+ return false;
+ }
+ type->setViewOn(views);
+ }
+ }
+ return true;
+}
+
+CustomTypeEntryPtr TypeSystemParser::parseCustomTypeEntry(const ConditionalStreamReader &,
+ const QString &name,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (!checkRootElement())
+ return nullptr;
+ auto result = std::make_shared<CustomTypeEntry>(name, since, m_contextStack.top()->entry);
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == checkFunctionAttribute)
+ result->setCheckFunction(attributes->takeAt(i).value().toString());
+ }
+ return result;
+}
+
+FlagsTypeEntryPtr
+ TypeSystemParser::parseFlagsEntry(const ConditionalStreamReader &reader,
+ const EnumTypeEntryPtr &enumEntry, QString flagName,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+
+{
+ if (!checkRootElement())
+ return nullptr;
+ auto ftype = std::make_shared<FlagsTypeEntry>(u"QFlags<"_s + enumEntry->name() + u'>',
+ since,
+ typeSystemTypeEntry(currentParentTypeEntry()));
+ ftype->setOriginator(enumEntry);
+ ftype->setTargetLangPackage(enumEntry->targetLangPackage());
+ // Try toenumEntry get the guess the qualified flag name
+ if (!flagName.contains(u"::"_s)) {
+ auto eq = enumEntry->qualifier();
+ if (!eq.isEmpty())
+ flagName.prepend(eq + u"::"_s);
+ }
+
+ ftype->setOriginalName(flagName);
+ if (!applyCommonAttributes(reader, ftype, attributes))
+ return nullptr;
+
+ QStringList lst = flagName.split(u"::"_s);
+ const QString name = lst.takeLast();
+ const QString targetLangFlagName = lst.join(u'.');
+ const QString &targetLangQualifier = enumEntry->targetLangQualifier();
+ if (targetLangFlagName != targetLangQualifier) {
+ qCWarning(lcShiboken, "enum %s and flags %s (%s) differ in qualifiers",
+ qPrintable(targetLangQualifier), qPrintable(lst.value(0)),
+ qPrintable(targetLangFlagName));
+ }
+
+ ftype->setFlagsName(name);
+ enumEntry->setFlags(ftype);
+
+ m_context->db->addFlagsType(ftype);
+ m_context->db->addType(ftype);
+
+ const int revisionIndex =
+ indexOfAttribute(*attributes, u"flags-revision");
+ ftype->setRevision(revisionIndex != -1
+ ? attributes->takeAt(revisionIndex).value().toInt()
+ : enumEntry->revision());
+ return ftype;
+}
+
+SmartPointerTypeEntryPtr
+ TypeSystemParser::parseSmartPointerEntry(const ConditionalStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (!checkRootElement())
+ return nullptr;
+ TypeSystem::SmartPointerType smartPointerType = TypeSystem::SmartPointerType::Shared;
+ QString getter;
+ QString refCountMethodName;
+ QString valueCheckMethod;
+ QString nullCheckMethod;
+ QString resetMethod;
+ QString instantiations;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == u"type") {
+ const auto attribute = attributes->takeAt(i);
+ const auto typeOpt = smartPointerTypeFromAttribute(attribute.value());
+ if (!typeOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return nullptr;
+ }
+ smartPointerType = typeOpt.value();
+ } else if (name == u"getter") {
+ getter = attributes->takeAt(i).value().toString();
+ } else if (name == u"ref-count-method") {
+ refCountMethodName = attributes->takeAt(i).value().toString();
+ } else if (name == u"instantiations") {
+ instantiations = attributes->takeAt(i).value().toString();
+ } else if (name == u"value-check-method") {
+ valueCheckMethod = attributes->takeAt(i).value().toString();
+ } else if (name == u"null-check-method") {
+ nullCheckMethod = attributes->takeAt(i).value().toString();
+ } else if (name == u"reset-method") {
+ resetMethod = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (getter.isEmpty()) {
+ m_error = u"No function getter name specified for getting the raw pointer held by the smart pointer."_s;
+ return nullptr;
+ }
+
+ QString signature = getter + u"()"_s;
+ signature = TypeDatabase::normalizedSignature(signature);
+ if (signature.isEmpty()) {
+ m_error = u"No signature for the smart pointer getter found."_s;
+ return nullptr;
+ }
+
+ QString errorString = checkSignatureError(signature,
+ u"smart-pointer-type"_s);
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return nullptr;
+ }
+
+ if (smartPointerType == TypeSystem::SmartPointerType::Unique && resetMethod.isEmpty()) {
+ m_error = u"Unique pointers require a reset() method."_s;
+ return nullptr;
+ }
+
+ auto type = std::make_shared<SmartPointerTypeEntry>(name, getter, smartPointerType,
+ refCountMethodName, since,
+ currentParentTypeEntry());
+ if (!applyCommonAttributes(reader, type, attributes))
+ return nullptr;
+ applyComplexTypeAttributes(reader, type, attributes);
+ type->setNullCheckMethod(nullCheckMethod);
+ type->setValueCheckMethod(valueCheckMethod);
+ type->setResetMethod(resetMethod);
+ m_context->smartPointerInstantiations.insert(type, instantiations);
+ return type;
+}
+
+PrimitiveTypeEntryPtr
+ TypeSystemParser::parsePrimitiveTypeEntry(const ConditionalStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (!checkRootElement())
+ return nullptr;
+ auto type = std::make_shared<PrimitiveTypeEntry>(name, since, currentParentTypeEntry());
+ QString targetLangApiName;
+ if (!applyCommonAttributes(reader, type, attributes))
+ return nullptr;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == targetLangNameAttribute) {
+ type->setTargetLangName(attributes->takeAt(i).value().toString());
+ } else if (name == u"target-lang-api-name") {
+ targetLangApiName = attributes->takeAt(i).value().toString();
+ } else if (name == preferredConversionAttribute) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == preferredTargetLangTypeAttribute) {
+ const bool v = convertBoolean(attributes->takeAt(i).value(),
+ preferredTargetLangTypeAttribute, true);
+ type->setPreferredTargetLangType(v);
+ } else if (name == u"default-constructor") {
+ type->setDefaultConstructor(attributes->takeAt(i).value().toString());
+ }
+ }
+
+ if (!targetLangApiName.isEmpty()) {
+ auto e = m_context->db->findType(targetLangApiName);
+ if (!e || !e->isCustom()) {
+ m_error = msgInvalidTargetLanguageApiName(targetLangApiName);
+ return nullptr;
+ }
+ type->setTargetLangApiType(std::static_pointer_cast<CustomTypeEntry>(e));
+ }
+ type->setTargetLangPackage(m_defaultPackage);
+ return type;
+}
+
+// "int:QList_int;QString:QList_QString"
+bool TypeSystemParser::parseOpaqueContainers(QStringView s, OpaqueContainers *result)
+{
+ const auto entries = s.split(u';');
+ for (const auto &entry : entries) {
+ const auto values = entry.split(u':');
+ if (values.size() != 2) {
+ m_error = u"Error parsing the opaque container attribute: \""_s
+ + s.toString() + u"\"."_s;
+ return false;
+ }
+ OpaqueContainer oc;
+ oc.name = values.at(1).trimmed().toString();
+ const auto instantiations = values.at(0).split(u',', Qt::SkipEmptyParts);
+ for (const auto &instantiationV : instantiations) {
+ QString instantiation = instantiationV.trimmed().toString();
+ // Fix to match AbstractMetaType::signature() which is used for matching
+ // "Foo*" -> "Foo *"
+ const auto asteriskPos = instantiation.indexOf(u'*');
+ if (asteriskPos > 0 && !instantiation.at(asteriskPos - 1).isSpace())
+ instantiation.insert(asteriskPos, u' ');
+ oc.instantiations.append(instantiation);
+ }
+ result->append(oc);
+ }
+ return true;
+}
+
+ContainerTypeEntryPtr
+ TypeSystemParser::parseContainerTypeEntry(const ConditionalStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (!checkRootElement())
+ return nullptr;
+ const auto typeIndex = indexOfAttribute(*attributes, u"type");
+ if (typeIndex == -1) {
+ m_error = u"no 'type' attribute specified"_s;
+ return nullptr;
+ }
+ const auto typeName = attributes->at(typeIndex).value();
+ const auto containerTypeOpt = containerTypeFromAttribute(typeName);
+ if (!containerTypeOpt.has_value()) {
+ m_error = u"there is no container of type "_s + typeName.toString();
+ return nullptr;
+ }
+ attributes->removeAt(typeIndex);
+ auto type = std::make_shared<ContainerTypeEntry>(name, containerTypeOpt.value(),
+ since, currentParentTypeEntry());
+ if (!applyCommonAttributes(reader, type, attributes))
+ return nullptr;
+ applyComplexTypeAttributes(reader, type, attributes);
+
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == opaqueContainerAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ OpaqueContainers oc;
+ if (!parseOpaqueContainers(attribute.value(), &oc))
+ return nullptr;
+ type->appendOpaqueContainers(oc);
+ }
+ }
+
+ return type;
+}
+
+bool TypeSystemParser::parseOpaqueContainerElement(QXmlStreamAttributes *attributes)
+{
+ QString containerName;
+ OpaqueContainers oc;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute) {
+ containerName = attributes->takeAt(i).value().toString();
+ } else if (name == opaqueContainerAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ if (!parseOpaqueContainers(attribute.value(), &oc))
+ return false;
+ }
+ }
+ if (containerName.isEmpty()) {
+ m_error = msgMissingAttribute(nameAttribute);
+ return false;
+ }
+ m_context->opaqueContainerHash[containerName].append(oc);
+ return true;
+}
+
+EnumTypeEntryPtr
+ TypeSystemParser::parseEnumTypeEntry(const ConditionalStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (!checkRootElement())
+ return nullptr;
+ auto entry = std::make_shared<EnumTypeEntry>(name, since, currentParentTypeEntry());
+ applyCommonAttributes(reader, entry, attributes);
+ entry->setTargetLangPackage(m_defaultPackage);
+
+ QString flagNames;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == u"upper-bound") {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == u"lower-bound") {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == docFileAttribute) {
+ entry->setDocFile(attributes->takeAt(i).value().toString());
+ } else if (name == forceIntegerAttribute) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == pythonEnumTypeAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto typeOpt = pythonEnumTypeFromAttribute(attribute.value());
+ if (typeOpt.has_value()) {
+ entry->setPythonEnumType(typeOpt.value());
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == cppEnumTypeAttribute) {
+ entry->setCppType(attributes->takeAt(i).value().toString());
+ } else if (name == extensibleAttribute) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == flagsAttribute) {
+ flagNames = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ // put in the flags parallel...
+ if (!flagNames.isEmpty()) {
+ const QStringList &flagNameList = flagNames.split(u',');
+ for (const QString &flagName : flagNameList)
+ parseFlagsEntry(reader, entry, flagName.trimmed(), since, attributes);
+ }
+ return entry;
+}
+
+
+NamespaceTypeEntryPtr
+ TypeSystemParser::parseNamespaceTypeEntry(const ConditionalStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (!checkRootElement())
+ return nullptr;
+ auto result = std::make_shared<NamespaceTypeEntry>(name, since, currentParentTypeEntry());
+ auto visibility = TypeSystem::Visibility::Unspecified;
+ applyCommonAttributes(reader, result, attributes);
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto attributeName = attributes->at(i).qualifiedName();
+ if (attributeName == u"files") {
+ const QString pattern = attributes->takeAt(i).value().toString();
+ QRegularExpression re(pattern);
+ if (!re.isValid()) {
+ m_error = msgInvalidRegularExpression(pattern, re.errorString());
+ return nullptr;
+ }
+ result->setFilePattern(re);
+ } else if (attributeName == u"extends") {
+ const auto extendsPackageName = attributes->at(i).value();
+ auto allEntries = TypeDatabase::instance()->findNamespaceTypes(name);
+ auto extendsIt = std::find_if(allEntries.cbegin(), allEntries.cend(),
+ [extendsPackageName] (const NamespaceTypeEntryCPtr &e) {
+ return e->targetLangPackage() == extendsPackageName;
+ });
+ if (extendsIt == allEntries.cend()) {
+ m_error = msgCannotFindNamespaceToExtend(name, extendsPackageName.toString());
+ return nullptr;
+ }
+ result->setExtends(*extendsIt);
+ attributes->removeAt(i);
+ } else if (attributeName == visibleAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto visibilityOpt = visibilityFromAttribute(attribute.value());
+ if (!visibilityOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return nullptr;
+ }
+ visibility = visibilityOpt.value();
+ } else if (attributeName == generateAttribute) {
+ if (!convertBoolean(attributes->takeAt(i).value(), generateAttribute, true))
+ visibility = TypeSystem::Visibility::Invisible;
+ } else if (attributeName == generateUsingAttribute) {
+ result->setGenerateUsing(convertBoolean(attributes->takeAt(i).value(),
+ generateUsingAttribute, true));
+ }
+ }
+
+ if (visibility != TypeSystem::Visibility::Unspecified)
+ result->setVisibility(visibility);
+ // Handle legacy "generate" before the common handling
+ applyComplexTypeAttributes(reader, result, attributes);
+
+ if (result->extends() && !result->hasPattern()) {
+ m_error = msgExtendingNamespaceRequiresPattern(name);
+ return {};
+ }
+
+ return result;
+}
+
+ValueTypeEntryPtr
+ TypeSystemParser::parseValueTypeEntry(const ConditionalStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (!checkRootElement())
+ return nullptr;
+ auto typeEntry = std::make_shared<ValueTypeEntry>(name, since, currentParentTypeEntry());
+ if (!applyCommonAttributes(reader, typeEntry, attributes))
+ return nullptr;
+ applyComplexTypeAttributes(reader, typeEntry, attributes);
+ const int defaultCtIndex =
+ indexOfAttribute(*attributes, u"default-constructor");
+ if (defaultCtIndex != -1)
+ typeEntry->setDefaultConstructor(attributes->takeAt(defaultCtIndex).value().toString());
+ return typeEntry;
+}
+
+FunctionTypeEntryPtr
+ TypeSystemParser::parseFunctionTypeEntry(const ConditionalStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (!checkRootElement())
+ return nullptr;
+
+ FunctionModification mod;
+ const auto oldAttributesSize = attributes->size();
+ if (!parseModifyFunctionAttributes(attributes, &mod))
+ return nullptr;
+ const bool hasModification = attributes->size() < oldAttributesSize;
+
+ QString originalSignature;
+ QString docFile;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == signatureAttribute)
+ originalSignature = attributes->takeAt(i).value().toString().simplified();
+ else if (name == docFileAttribute)
+ docFile = attributes->takeAt(i).value().toString();
+ }
+
+ const QString signature = TypeDatabase::normalizedSignature(originalSignature);
+ if (signature.isEmpty()) {
+ m_error = msgMissingAttribute(signatureAttribute);
+ return nullptr;
+ }
+
+ if (hasModification) {
+ mod.setOriginalSignature(originalSignature);
+ mod.setSignature(signature);
+ m_contextStack.top()->functionMods << mod;
+ }
+
+ TypeEntryPtr existingType = m_context->db->findType(name);
+
+ if (!existingType) {
+ auto result = std::make_shared<FunctionTypeEntry>(name, signature, since,
+ currentParentTypeEntry());
+ result->setTargetLangPackage(m_defaultPackage);
+ result->setDocFile(docFile);
+ applyCommonAttributes(reader, result, attributes);
+ return result;
+ }
+
+ if (existingType->type() != TypeEntry::FunctionType) {
+ m_error = name + " expected to be a function, but isn't! Maybe it was already declared as a class or something else."_L1;
+ return nullptr;
+ }
+
+ auto result = std::static_pointer_cast<FunctionTypeEntry>(existingType);
+ result->addSignature(signature);
+ return result;
+}
+
+TypedefEntryPtr
+ TypeSystemParser::parseTypedefEntry(const ConditionalStreamReader &reader,
+ const QString &name, StackElement topElement,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (!checkRootElement())
+ return nullptr;
+ if (topElement != StackElement::Root
+ && topElement != StackElement::NamespaceTypeEntry) {
+ m_error = u"typedef entries must be nested in namespaces or type system."_s;
+ return nullptr;
+ }
+ const auto sourceIndex = indexOfAttribute(*attributes, sourceAttribute);
+ if (sourceIndex == -1) {
+ m_error = msgMissingAttribute(sourceAttribute);
+ return nullptr;
+ }
+ const QString sourceType = attributes->takeAt(sourceIndex).value().toString();
+ auto result = std::make_shared<TypedefEntry>(name, sourceType, since,
+ currentParentTypeEntry());
+ if (!applyCommonAttributes(reader, result, attributes))
+ return nullptr;
+ applyComplexTypeAttributes(reader, result, attributes);
+ return result;
+}
+
+void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader &reader,
+ const ComplexTypeEntryPtr &ctype,
+ QXmlStreamAttributes *attributes) const
+{
+ bool generate = true;
+ ctype->setCopyable(ComplexTypeEntry::Unknown);
+ auto exceptionHandling = m_exceptionHandling;
+ auto allowThread = m_allowThread;
+
+ QString package = m_defaultPackage;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == streamAttribute) {
+ ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute, false));
+ } else if (name == privateAttribute) {
+ ctype->setPrivate(convertBoolean(attributes->takeAt(i).value(),
+ privateAttribute, false));
+ } else if (name == generateAttribute) {
+ generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute, true);
+ } else if (name ==packageAttribute) {
+ package = attributes->takeAt(i).value().toString();
+ } else if (name == defaultSuperclassAttribute) {
+ ctype->setDefaultSuperclass(attributes->takeAt(i).value().toString());
+ } else if (name == genericClassAttribute) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ const bool v = convertBoolean(attributes->takeAt(i).value(),
+ genericClassAttribute, false);
+ ctype->setGenericClass(v);
+ } else if (name == targetLangNameAttribute) {
+ ctype->setTargetLangName(attributes->takeAt(i).value().toString());
+ } else if (name == polymorphicBaseAttribute) {
+ const bool v = convertBoolean(attributes->takeAt(i).value(),
+ polymorphicBaseAttribute, false);
+ ctype->setIsPolymorphicBase(v);
+ } else if (name == u"polymorphic-name-function") {
+ ctype->setPolymorphicNameFunction(attributes->takeAt(i).value().toString());
+ } else if (name == u"polymorphic-id-expression") {
+ ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
+ } else if (name == copyableAttribute) {
+ const bool v = convertBoolean(attributes->takeAt(i).value(),
+ copyableAttribute, false);
+ ctype->setCopyable(v ? ComplexTypeEntry::CopyableSet : ComplexTypeEntry::NonCopyableSet);
+ } else if (name == exceptionHandlingAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value());
+ if (exceptionOpt.has_value()) {
+ exceptionHandling = exceptionOpt.value();
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == allowThreadAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto allowThreadOpt = allowThreadFromAttribute(attribute.value());
+ if (allowThreadOpt.has_value()) {
+ allowThread = allowThreadOpt.value();
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == u"held-type") {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == u"hash-function") {
+ ctype->setHashFunction(attributes->takeAt(i).value().toString());
+ } else if (name == forceAbstractAttribute) {
+ if (convertBoolean(attributes->takeAt(i).value(), forceAbstractAttribute, false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
+ } else if (name == deprecatedAttribute) {
+ if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute, false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
+ } else if (name == disableWrapperAttribute) {
+ if (convertBoolean(attributes->takeAt(i).value(), disableWrapperAttribute, false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DisableWrapper);
+ } else if (name == deleteInMainThreadAttribute) {
+ if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute, false))
+ ctype->setDeleteInMainThread(true);
+ } else if (name == qtMetaObjectFunctionsAttribute) {
+ if (!convertBoolean(attributes->takeAt(i).value(),
+ qtMetaObjectFunctionsAttribute, true)) {
+ ctype->setTypeFlags(ctype->typeFlags()
+ | ComplexTypeEntry::DisableQtMetaObjectFunctions);
+ }
+ } else if (name == generateFunctionsAttribute) {
+ const auto names = attributes->takeAt(i).value();
+ const auto nameList = names.split(u';', Qt::SkipEmptyParts);
+ QSet<QString> nameSet;
+ for (const auto &name : nameList)
+ nameSet.insert(name.trimmed().toString());
+ ctype->setGenerateFunctions(nameSet);
+ } else if (name == u"target-type") {
+ ctype->setTargetType(attributes->takeAt(i).value().toString());
+ } else if (name == snakeCaseAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value());
+ if (snakeCaseOpt.has_value()) {
+ ctype->setSnakeCase(snakeCaseOpt.value());
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == isNullAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto boolCastOpt = boolCastFromAttribute(attribute.value());
+ if (boolCastOpt.has_value()) {
+ ctype->setIsNullMode(boolCastOpt.value());
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == operatorBoolAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto boolCastOpt = boolCastFromAttribute(attribute.value());
+ if (boolCastOpt.has_value()) {
+ ctype->setOperatorBoolMode(boolCastOpt.value());
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == qtMetaTypeAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto qtMetaTypeOpt = qtMetaTypeFromAttribute(attribute.value());
+ if (qtMetaTypeOpt.has_value()) {
+ ctype->setQtMetaTypeRegistration(qtMetaTypeOpt.value());
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == parentManagementAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ if (convertBoolean(attribute.value(), parentManagementAttribute, false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ParentManagement);
+ ComplexTypeEntry::setParentManagementEnabled(true);
+ }
+ }
+
+ if (exceptionHandling != TypeSystem::ExceptionHandling::Unspecified)
+ ctype->setExceptionHandling(exceptionHandling);
+ if (allowThread != TypeSystem::AllowThread::Unspecified)
+ ctype->setAllowThread(allowThread);
+
+ // The generator code relies on container's package being empty.
+ if (ctype->type() != TypeEntry::ContainerType)
+ ctype->setTargetLangPackage(package);
+
+ if (generate)
+ ctype->setCodeGeneration(m_generate);
+ else
+ ctype->setCodeGeneration(TypeEntry::GenerationDisabled);
+}
+
+bool TypeSystemParser::parseConfiguration(StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!isComplexTypeEntry(topElement)
+ && topElement != StackElement::EnumTypeEntry) {
+ m_error = u"<configuration> must be nested into a complex or enum type entry."_s;
+ return false;
+ }
+ QString condition;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == u"condition") {
+ condition = attributes->takeAt(i).value().toString();
+ }
+ }
+ if (condition.isEmpty()) {
+ m_error = u"<configuration> requires a \"condition\" attribute."_s;
+ return false;
+ }
+ const auto topEntry = m_contextStack.top()->entry;
+ const auto configurableEntry = std::dynamic_pointer_cast<ConfigurableTypeEntry>(topEntry);
+ Q_ASSERT(configurableEntry);
+ configurableEntry->setConfigCondition(condition);
+ return true;
+}
+
+bool TypeSystemParser::parseRenameFunction(const ConditionalStreamReader &,
+ QString *name, QXmlStreamAttributes *attributes)
+{
+ QString signature;
+ QString rename;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == signatureAttribute) {
+ // Do not remove as it is needed for the type entry later on
+ signature = attributes->at(i).value().toString().simplified();
+ } else if (name == renameAttribute) {
+ rename = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (signature.isEmpty()) {
+ m_error = msgMissingAttribute(signatureAttribute);
+ return false;
+ }
+
+ *name = signature.left(signature.indexOf(u'(')).trimmed();
+
+ QString errorString = checkSignatureError(signature, u"function"_s);
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ if (!rename.isEmpty()) {
+ static const QRegularExpression functionNameRegExp(u"^[a-zA-Z_][a-zA-Z0-9_]*$"_s);
+ Q_ASSERT(functionNameRegExp.isValid());
+ if (!functionNameRegExp.match(rename).hasMatch()) {
+ m_error = u"can not rename '"_s + signature + u"', '"_s
+ + rename + u"' is not a valid function name"_s;
+ return false;
+ }
+ FunctionModification mod;
+ if (!mod.setSignature(signature, &m_error))
+ return false;
+ mod.setRenamedToName(rename);
+ mod.setModifierFlag(FunctionModification::Rename);
+ m_contextStack.top()->functionMods << mod;
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ const bool isAddFunction = topElement == StackElement::AddFunction;
+ const bool validParent = isTypeEntry(topElement)
+ || topElement == StackElement::ModifyFunction
+ || topElement == StackElement::ModifyField
+ || isAddFunction;
+ if (!validParent) {
+ m_error = u"inject-documentation must be inside modify-function, add-function"
+ "modify-field or other tags that creates a type"_s;
+ return false;
+ }
+
+ TypeSystem::DocModificationMode mode = TypeSystem::DocModificationReplace;
+ TypeSystem::Language lang = TypeSystem::NativeCode;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == u"mode") {
+ const auto attribute = attributes->takeAt(i);
+ const auto modeOpt = docModificationFromAttribute(attribute.value());
+ if (!modeOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ mode = modeOpt.value();
+ } else if (name == formatAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto langOpt = languageFromAttribute(attribute.value());
+ if (!langOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ lang = langOpt.value();
+ }
+ }
+
+ QString signature = isTypeEntry(topElement) ? QString() : m_currentSignature;
+ DocModification mod(mode, signature);
+ mod.setFormat(lang);
+ if (hasFileSnippetAttributes(attributes)) {
+ const auto snippetOptional = readFileSnippet(attributes);
+ if (!snippetOptional.has_value())
+ return false;
+ mod.setCode(snippetOptional.value().content);
+ }
+ auto &top = m_contextStack.top();
+ if (isAddFunction)
+ top->addedFunctions.last()->addDocModification(mod);
+ else
+ top->docModifications << mod;
+ return true;
+}
+
+bool TypeSystemParser::parseModifyDocumentation(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ const bool validParent = isTypeEntry(topElement)
+ || topElement == StackElement::ModifyFunction
+ || topElement == StackElement::ModifyField;
+ if (!validParent) {
+ m_error = u"modify-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type"_s;
+ return false;
+ }
+
+ const auto xpathIndex = indexOfAttribute(*attributes, xPathAttribute);
+ if (xpathIndex == -1) {
+ m_error = msgMissingAttribute(xPathAttribute);
+ return false;
+ }
+
+ const QString xpath = attributes->takeAt(xpathIndex).value().toString();
+ QString signature = isTypeEntry(topElement) ? QString() : m_currentSignature;
+ m_contextStack.top()->docModifications
+ << DocModification(xpath, signature);
+ return true;
+}
+
+// m_exceptionHandling
+TypeSystemTypeEntryPtr TypeSystemParser::parseRootElement(const ConditionalStreamReader &,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified;
+ QString subModuleOf;
+ QString namespaceBegin;
+ QString namespaceEnd;
+
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == packageAttribute) {
+ m_defaultPackage = attributes->takeAt(i).value().toString();
+ } else if (name == defaultSuperclassAttribute) {
+ m_defaultSuperclass = attributes->takeAt(i).value().toString();
+ } else if (name == exceptionHandlingAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value());
+ if (exceptionOpt.has_value()) {
+ m_exceptionHandling = exceptionOpt.value();
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == allowThreadAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto allowThreadOpt = allowThreadFromAttribute(attribute.value());
+ if (allowThreadOpt.has_value()) {
+ m_allowThread = allowThreadOpt.value();
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == snakeCaseAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value());
+ if (snakeCaseOpt.has_value()) {
+ snakeCase = snakeCaseOpt.value();
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == subModuleOfAttribute) {
+ subModuleOf = attributes->takeAt(i).value().toString();
+ } else if (name == "namespace-begin"_L1) {
+ namespaceBegin = attributes->takeAt(i).value().toString();
+ } else if (name == "namespace-end"_L1) {
+ namespaceEnd = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (m_defaultPackage.isEmpty()) { // Extending default, see addBuiltInContainerTypes()
+ auto moduleEntry = std::const_pointer_cast<TypeSystemTypeEntry>(m_context->db->defaultTypeSystemType());
+ Q_ASSERT(moduleEntry);
+ m_defaultPackage = moduleEntry->name();
+ return moduleEntry;
+ }
+
+ auto moduleEntry =
+ std::const_pointer_cast<TypeSystemTypeEntry>(m_context->db->findTypeSystemType(m_defaultPackage));
+ const bool add = !moduleEntry;
+ if (add) {
+ moduleEntry.reset(new TypeSystemTypeEntry(m_defaultPackage, since,
+ currentParentTypeEntry()));
+ moduleEntry->setSubModule(subModuleOf);
+ }
+ moduleEntry->setCodeGeneration(m_generate);
+ moduleEntry->setSnakeCase(snakeCase);
+ if (!namespaceBegin.isEmpty())
+ moduleEntry->setNamespaceBegin(namespaceBegin);
+ if (!namespaceEnd.isEmpty())
+ moduleEntry->setNamespaceEnd(namespaceEnd);
+
+ if ((m_generate == TypeEntry::GenerateForSubclass ||
+ m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty())
+ TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage);
+
+ if (add)
+ m_context->db->addTypeSystemType(moduleEntry);
+ return moduleEntry;
+}
+
+bool TypeSystemParser::loadTypesystem(const ConditionalStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ QString typeSystemName;
+ bool generateChild = true;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute)
+ typeSystemName = attributes->takeAt(i).value().toString();
+ else if (name == generateAttribute)
+ generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute, true);
+ }
+ if (typeSystemName.isEmpty()) {
+ m_error = u"No typesystem name specified"_s;
+ return false;
+ }
+ const bool result =
+ m_context->db->parseFile(m_context, typeSystemName, m_currentPath,
+ generateChild && m_generate == TypeEntry::GenerateCode);
+ if (!result)
+ m_error = u"Failed to parse: '"_s + typeSystemName + u'\'';
+ return result;
+}
+
+bool TypeSystemParser::parseRejectEnumValue(const ConditionalStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ if (!m_currentEnum) {
+ m_error = u"<reject-enum-value> node must be used inside a <enum-type> node"_s;
+ return false;
+ }
+ const auto nameIndex = indexOfAttribute(*attributes, nameAttribute);
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute);
+ return false;
+ }
+ m_currentEnum->addEnumValueRejection(attributes->takeAt(nameIndex).value().toString());
+ return true;
+}
+
+bool TypeSystemParser::parseReplaceArgumentType(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::ModifyArgument) {
+ m_error = u"Type replacement can only be specified for argument modifications"_s;
+ return false;
+ }
+ const auto modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute);
+ if (modifiedTypeIndex == -1) {
+ m_error = u"Type replacement requires 'modified-type' attribute"_s;
+ return false;
+ }
+ m_contextStack.top()->functionMods.last().argument_mods().last().setModifiedType(
+ attributes->takeAt(modifiedTypeIndex).value().toString());
+ return true;
+}
+
+bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::ModifyArgument
+ && topElement != StackElement::ValueTypeEntry
+ && topElement != StackElement::PrimitiveTypeEntry
+ && topElement != StackElement::ContainerTypeEntry) {
+ m_error = u"Conversion rules can only be specified for argument modification, "
+ "value-type, primitive-type or container-type conversion."_s;
+ return false;
+ }
+
+ QString sourceFile;
+ QString snippetLabel;
+ TypeSystem::Language lang = TypeSystem::NativeCode;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == classAttribute) {
+ const auto languageAttribute = attributes->takeAt(i);
+ const auto langOpt = languageFromAttribute(languageAttribute.value());
+ if (!langOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(languageAttribute);
+ return false;
+ }
+ lang = langOpt.value();
+ } else if (name == u"file") {
+ sourceFile = attributes->takeAt(i).value().toString();
+ } else if (name == snippetAttribute) {
+ snippetLabel = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ const auto &top = m_contextStack.top();
+ if (topElement == StackElement::ModifyArgument) {
+ CodeSnip snip;
+ snip.language = lang;
+ top->functionMods.last().argument_mods().last().conversionRules().append(snip);
+ return true;
+ }
+
+ ValueTypeEntryPtr valueTypeEntry;
+ if (top->entry->isValue()) {
+ valueTypeEntry = std::static_pointer_cast<ValueTypeEntry>(top->entry);
+ if (valueTypeEntry->hasTargetConversionRule() || valueTypeEntry->hasCustomConversion()) {
+ m_error = u"Types can have only one conversion rule"_s;
+ return false;
+ }
+ }
+
+ // The old conversion rule tag that uses a file containing the conversion
+ // will be kept temporarily for compatibility reasons. FIXME PYSIDE7: Remove
+ if (valueTypeEntry != nullptr && !sourceFile.isEmpty()) {
+ if (m_generate != TypeEntry::GenerateForSubclass
+ && m_generate != TypeEntry::GenerateNothing) {
+ qWarning(lcShiboken, "Specifying conversion rules by \"file\" is deprecated.");
+ if (lang != TypeSystem::TargetLangCode)
+ return true;
+
+ QFile conversionSource(sourceFile);
+ if (!conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_error = msgCannotOpenForReading(conversionSource);
+ return false;
+ }
+ const auto conversionRuleOptional =
+ extractSnippet(QString::fromUtf8(conversionSource.readAll()), snippetLabel);
+ if (!conversionRuleOptional.has_value()) {
+ m_error = msgCannotFindSnippet(sourceFile, snippetLabel);
+ return false;
+ }
+ valueTypeEntry->setTargetConversionRule(conversionRuleOptional.value());
+ }
+ return true;
+ }
+
+ auto customConversion = std::make_shared<CustomConversion>(top->entry);
+ if (top->entry->isPrimitive())
+ std::static_pointer_cast<PrimitiveTypeEntry>(top->entry)->setCustomConversion(customConversion);
+ else if (top->entry->isContainer())
+ std::static_pointer_cast<ContainerTypeEntry>(top->entry)->setCustomConversion(customConversion);
+ else if (top->entry->isValue())
+ std::static_pointer_cast<ValueTypeEntry>(top->entry)->setCustomConversion(customConversion);
+ customConversionsForReview.append(customConversion);
+ return true;
+}
+
+bool TypeSystemParser::parseNativeToTarget(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::ConversionRule) {
+ m_error = u"Native to Target conversion code can only be specified for custom conversion rules."_s;
+ return false;
+ }
+ CodeSnip snip;
+ if (!readCodeSnippet(attributes, &snip))
+ return false;
+ m_contextStack.top()->conversionCodeSnips.append(snip);
+ return true;
+}
+
+bool TypeSystemParser::parseAddConversion(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::TargetToNative) {
+ m_error = u"Target to Native conversions can only be added inside 'target-to-native' tags."_s;
+ return false;
+ }
+ QString sourceTypeName;
+ QString typeCheck;
+ CodeSnip snip;
+ if (!readCodeSnippet(attributes, &snip))
+ return false;
+
+ const auto &top = m_contextStack.top();
+ top->conversionCodeSnips.append(snip);
+
+ if (parserState() == ParserState::ArgumentTargetToNativeConversion)
+ return true;
+
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == u"type")
+ sourceTypeName = attributes->takeAt(i).value().toString();
+ else if (name == u"check")
+ typeCheck = attributes->takeAt(i).value().toString();
+ }
+
+ if (sourceTypeName.isEmpty()) {
+ m_error = u"Target to Native conversions must specify the input type with the 'type' attribute."_s;
+ return false;
+ }
+ auto customConversion = CustomConversion::getCustomConversion(top->entry);
+ if (!customConversion) {
+ m_error = msgMissingCustomConversion(top->entry);
+ return false;
+ }
+ customConversion->addTargetToNativeConversion(sourceTypeName, typeCheck);
+ return true;
+}
+
+static bool parseIndex(const QString &index, int *result, QString *errorMessage)
+{
+ bool ok = false;
+ *result = index.toInt(&ok);
+ if (!ok)
+ *errorMessage = QString::fromLatin1("Cannot convert '%1' to integer").arg(index);
+ return ok;
+}
+
+static bool parseArgumentIndex(const QString &index, int *result, QString *errorMessage)
+{
+ if (index == u"return") {
+ *result = 0;
+ return true;
+ }
+ if (index == u"this") {
+ *result = -1;
+ return true;
+ }
+ return parseIndex(index, result, errorMessage);
+}
+
+bool TypeSystemParser::parseModifyArgument(const ConditionalStreamReader &,
+ StackElement topElement, QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::ModifyFunction
+ && topElement != StackElement::AddFunction
+ && topElement != StackElement::DeclareFunction) {
+ m_error = u"Argument modification requires <modify-function>,"
+ " <add-function> or <declare-function> as parent, was "_s
+ + tagFromElement(topElement).toString();
+ return false;
+ }
+
+ QString index;
+ QString renameTo;
+ QString pyiType;
+ bool resetAfterUse = false;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute) {
+ index = attributes->takeAt(i).value().toString();
+ } else if (name == invalidateAfterUseAttribute) {
+ resetAfterUse = convertBoolean(attributes->takeAt(i).value(),
+ invalidateAfterUseAttribute, false);
+ } else if (name == renameAttribute) {
+ renameTo = attributes->takeAt(i).value().toString();
+ } else if (name == pyiTypeAttribute) {
+ pyiType = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (index.isEmpty()) {
+ m_error = msgMissingAttribute(indexAttribute);
+ return false;
+ }
+
+ int idx;
+ if (!parseArgumentIndex(index, &idx, &m_error))
+ return false;
+
+ ArgumentModification argumentModification = ArgumentModification(idx);
+ argumentModification.setResetAfterUse(resetAfterUse);
+ argumentModification.setRenamedToName(renameTo);
+ argumentModification.setPyiType(pyiType);
+ m_contextStack.top()->functionMods.last().argument_mods().append(argumentModification);
+ return true;
+}
+
+bool TypeSystemParser::parseNoNullPointer(const ConditionalStreamReader &reader,
+ StackElement topElement, QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::ModifyArgument) {
+ m_error = u"no-null-pointer requires argument modification as parent"_s;
+ return false;
+ }
+
+ ArgumentModification &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods().last();
+ lastArgMod.setNoNullPointers(true);
+
+ const int defaultValueIndex =
+ indexOfAttribute(*attributes, u"default-value");
+ if (defaultValueIndex != -1) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(defaultValueIndex);
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, attribute)));
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::ModifyArgument) {
+ m_error = u"define-ownership requires argument modification as parent"_s;
+ return false;
+ }
+
+ TypeSystem::Language lang = TypeSystem::TargetLangCode;
+ std::optional<TypeSystem::Ownership> ownershipOpt;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == classAttribute) {
+ const auto classAttribute = attributes->takeAt(i);
+ const auto langOpt = languageFromAttribute(classAttribute.value());
+ if (!langOpt.has_value() || langOpt.value() == TypeSystem::ShellCode) {
+ m_error = msgInvalidAttributeValue(classAttribute);
+ return false;
+ }
+ lang = langOpt.value();
+ } else if (name == ownershipAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ ownershipOpt = ownershipFromFromAttribute(attribute.value());
+ if (!ownershipOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ }
+ }
+
+ if (!ownershipOpt.has_value()) {
+ m_error = "unspecified ownership"_L1;
+ return false;
+ }
+ auto &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods().last();
+ switch (lang) {
+ case TypeSystem::TargetLangCode:
+ lastArgMod.setTargetOwnerShip(ownershipOpt.value());
+ break;
+ case TypeSystem::NativeCode:
+ lastArgMod.setNativeOwnership(ownershipOpt.value());
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+// ### fixme PySide7: remove (replaced by attribute).
+bool TypeSystemParser::parseRename(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::ModifyArgument) {
+ m_error = u"Argument modification parent required"_s;
+ return false;
+ }
+
+ const auto toIndex = indexOfAttribute(*attributes, toAttribute);
+ if (toIndex == -1) {
+ m_error = msgMissingAttribute(toAttribute);
+ return false;
+ }
+ const QString renamed_to = attributes->takeAt(toIndex).value().toString();
+ m_contextStack.top()->functionMods.last().argument_mods().last().setRenamedToName(renamed_to);
+ return true;
+}
+
+bool TypeSystemParser::parseModifyField(const ConditionalStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ FieldModification fm;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute) {
+ fm.setName(attributes->takeAt(i).value().toString());
+ } else if (name == removeAttribute) {
+ fm.setRemoved(convertRemovalAttribute(attributes->takeAt(i).value()));
+ } else if (name == opaqueContainerFieldAttribute) {
+ fm.setOpaqueContainer(convertBoolean(attributes->takeAt(i).value(),
+ opaqueContainerFieldAttribute, false));
+ } else if (name == readAttribute) {
+ fm.setReadable(convertBoolean(attributes->takeAt(i).value(), readAttribute, true));
+ } else if (name == writeAttribute) {
+ fm.setWritable(convertBoolean(attributes->takeAt(i).value(), writeAttribute, true));
+ } else if (name == renameAttribute) {
+ fm.setRenamedToName(attributes->takeAt(i).value().toString());
+ } else if (name == snakeCaseAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value());
+ if (snakeCaseOpt.has_value()) {
+ fm.setSnakeCase(snakeCaseOpt.value());
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ }
+ }
+ if (fm.name().isEmpty()) {
+ m_error = msgMissingAttribute(nameAttribute);
+ return false;
+ }
+ m_contextStack.top()->fieldMods << fm;
+ return true;
+}
+
+static bool parseOverloadNumber(const QXmlStreamAttribute &attribute, int *overloadNumber,
+ QString *errorMessage)
+{
+ bool ok;
+ *overloadNumber = attribute.value().toInt(&ok);
+ if (!ok || *overloadNumber < 0) {
+ *errorMessage = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseAddFunction(const ConditionalStreamReader &,
+ StackElement topElement,
+ StackElement t,
+ QXmlStreamAttributes *attributes)
+{
+ const bool validParent = isComplexTypeEntry(topElement)
+ || topElement == StackElement::Root
+ || topElement == StackElement::ContainerTypeEntry;
+ if (!validParent) {
+ m_error = QString::fromLatin1("Add/Declare function requires a complex/container type or a root tag as parent"
+ ", was=%1").arg(tagFromElement(topElement));
+ return false;
+ }
+
+ FunctionModification mod;
+ if (!(t == StackElement::AddFunction
+ ? parseBasicModifyFunctionAttributes(attributes, &mod)
+ : parseModifyFunctionAttributes(attributes, &mod))) {
+ return false;
+ }
+
+ QString originalSignature;
+ QString returnType;
+ bool staticFunction = false;
+ bool classMethod = false;
+ bool pythonOverride = false;
+ QString access;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == signatureAttribute) {
+ originalSignature = attributes->takeAt(i).value().toString().simplified();
+ } else if (name == u"return-type") {
+ returnType = attributes->takeAt(i).value().toString();
+ } else if (name == staticAttribute) {
+ staticFunction = convertBoolean(attributes->takeAt(i).value(),
+ staticAttribute, false);
+ } else if (name == classmethodAttribute) {
+ classMethod = convertBoolean(attributes->takeAt(i).value(),
+ classmethodAttribute, false);
+ } else if (name == accessAttribute) {
+ access = attributes->takeAt(i).value().toString();
+ } else if (name == pythonOverrideAttribute) {
+ pythonOverride = convertBoolean(attributes->takeAt(i).value(),
+ pythonOverrideAttribute, false);
+ }
+ }
+
+ QString signature = TypeDatabase::normalizedAddedFunctionSignature(originalSignature);
+ if (signature.isEmpty()) {
+ m_error = u"No signature for the added function"_s;
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, u"add-function"_s);
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ AddedFunctionPtr func = AddedFunction::createAddedFunction(signature, returnType, &errorString);
+ if (!func) {
+ m_error = errorString;
+ return false;
+ }
+
+ func->setStatic(staticFunction);
+ func->setClassMethod(classMethod);
+ func->setPythonOverride(pythonOverride);
+ func->setTargetLangPackage(m_defaultPackage);
+
+ // Create signature for matching modifications
+ signature = TypeDatabase::normalizedSignature(originalSignature);
+ if (!signature.contains(u'('))
+ signature += u"()"_s;
+ m_currentSignature = signature;
+
+ if (!access.isEmpty()) {
+ const auto acessOpt = addedFunctionAccessFromAttribute(access);
+ if (!acessOpt.has_value()) {
+ m_error = u"Bad access type '"_s + access + u'\'';
+ return false;
+ }
+ func->setAccess(acessOpt.value());
+ }
+ func->setDeclaration(t == StackElement::DeclareFunction);
+
+ m_contextStack.top()->addedFunctions << func;
+ m_contextStack.top()->addedFunctionModificationIndex =
+ m_contextStack.top()->functionMods.size();
+
+ if (!mod.setSignature(m_currentSignature, &m_error))
+ return false;
+ mod.setOriginalSignature(originalSignature);
+ m_contextStack.top()->functionMods << mod;
+ return true;
+}
+
+bool TypeSystemParser::parseAddPyMethodDef(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!isComplexTypeEntry(topElement)) {
+ m_error = u"add-pymethoddef requires a complex type as parent, was="_s
+ + tagFromElement(topElement).toString();
+ return false;
+ }
+
+ TypeSystemPyMethodDefEntry def;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute) {
+ def.name = attributes->takeAt(i).value().toString();
+ } else if (name == u"doc") {
+ def.doc = attributes->takeAt(i).value().toString();
+ } else if (name == u"function") {
+ def.function = attributes->takeAt(i).value().toString();
+ } else if (name == u"flags") {
+ auto attribute = attributes->takeAt(i);
+ const auto flags = attribute.value().split(u'|', Qt::SkipEmptyParts);
+ for (const auto &flag : flags)
+ def.methFlags.append(flag.toString().toUtf8());
+ } else if (name == u"signatures") {
+ auto attribute = attributes->takeAt(i);
+ const auto signatures = attribute.value().split(u';', Qt::SkipEmptyParts);
+ for (const auto &signature : signatures)
+ def.signatures.append(signature.toString());
+ }
+ }
+
+ if (def.name.isEmpty() || def.function.isEmpty()) {
+ m_error = u"add-pymethoddef requires at least a name and a function attribute"_s;
+ return false;
+ }
+ std::static_pointer_cast<ComplexTypeEntry>(m_contextStack.top()->entry)->addPyMethodDef(def);
+ return true;
+}
+
+bool TypeSystemParser::parseProperty(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!isComplexTypeEntry(topElement)) {
+ m_error = QString::fromLatin1("Add property requires a complex type as parent"
+ ", was=%1").arg(tagFromElement(topElement));
+ return false;
+ }
+
+ TypeSystemProperty property;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute) {
+ property.name = attributes->takeAt(i).value().toString();
+ } else if (name == u"get") {
+ property.read = attributes->takeAt(i).value().toString();
+ } else if (name == u"type") {
+ property.type = attributes->takeAt(i).value().toString();
+ } else if (name == u"set") {
+ property.write = attributes->takeAt(i).value().toString();
+ } else if (name == generateGetSetDefAttribute) {
+ property.generateGetSetDef =
+ convertBoolean(attributes->takeAt(i).value(),
+ generateGetSetDefAttribute, false);
+ }
+ }
+ if (!property.isValid()) {
+ m_error = u"<property> element is missing required attibutes (name/type/get)."_s;
+ return false;
+ }
+ std::static_pointer_cast<ComplexTypeEntry>(m_contextStack.top()->entry)->addProperty(property);
+ return true;
+}
+
+// Parse basic attributes applicable to <add-function>/<declare-function>/<function>
+// and <modify-function> (all that is not done by injected code).
+bool TypeSystemParser::parseBasicModifyFunctionAttributes(QXmlStreamAttributes *attributes,
+ FunctionModification *mod)
+{
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == overloadNumberAttribute) {
+ int overloadNumber = TypeSystem::OverloadNumberUnset;
+ if (!parseOverloadNumber(attributes->takeAt(i), &overloadNumber, &m_error))
+ return false;
+ mod->setOverloadNumber(overloadNumber);
+ }
+ }
+ return true;
+}
+
+// Parse attributes applicable to <declare-function>/<function>
+// and <modify-function>.
+bool TypeSystemParser::parseModifyFunctionAttributes(QXmlStreamAttributes *attributes,
+ FunctionModification *mod)
+{
+ if (!parseBasicModifyFunctionAttributes(attributes, mod))
+ return false;
+
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == allowThreadAttribute) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(i);
+ const auto allowThreadOpt = allowThreadFromAttribute(attribute.value());
+ if (!allowThreadOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ mod->setAllowThread(allowThreadOpt.value());
+ } else if (name == exceptionHandlingAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value());
+ if (!exceptionOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ mod->setExceptionHandling(exceptionOpt.value());
+ } else if (name == snakeCaseAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value());
+ if (!snakeCaseOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ mod->setSnakeCase(snakeCaseOpt.value());
+ } else if (name == deprecatedAttribute) {
+ const bool deprecated = convertBoolean(attributes->takeAt(i).value(),
+ deprecatedAttribute, false);
+ mod->setModifierFlag(deprecated ? FunctionModification::Deprecated
+ : FunctionModification::Undeprecated);
+ }
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ const bool validParent = isComplexTypeEntry(topElement)
+ || topElement == StackElement::TypedefTypeEntry
+ || topElement == StackElement::FunctionTypeEntry;
+ if (!validParent) {
+ m_error = QString::fromLatin1("Modify function requires complex type as parent"
+ ", was=%1").arg(tagFromElement(topElement));
+ return false;
+ }
+
+ QString originalSignature;
+ FunctionModification mod;
+ if (!parseModifyFunctionAttributes(attributes, &mod))
+ return false;
+
+ QString access;
+ bool removed = false;
+ QString rename;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == signatureAttribute) {
+ originalSignature = attributes->takeAt(i).value().toString().simplified();
+ } else if (name == accessAttribute) {
+ access = attributes->takeAt(i).value().toString();
+ } else if (name == renameAttribute) {
+ rename = attributes->takeAt(i).value().toString();
+ } else if (name == removeAttribute) {
+ removed = convertRemovalAttribute(attributes->takeAt(i).value());
+ } else if (name == virtualSlotAttribute || name == threadAttribute) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ }
+ }
+
+ // Child of global <function>
+ const auto &top = m_contextStack.top();
+ if (originalSignature.isEmpty() && top->entry->isFunction()) {
+ auto f = std::static_pointer_cast<const FunctionTypeEntry>(top->entry);
+ originalSignature = f->signatures().value(0);
+ }
+
+ const QString signature = TypeDatabase::normalizedSignature(originalSignature);
+ if (signature.isEmpty()) {
+ m_error = u"No signature for modified function"_s;
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, u"modify-function"_s);
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ if (!mod.setSignature(signature, &m_error))
+ return false;
+ mod.setOriginalSignature(originalSignature);
+ m_currentSignature = signature;
+
+ if (!access.isEmpty()) {
+ const auto modifierFlagOpt = modifierFromAttribute(access);
+ if (!modifierFlagOpt.has_value()) {
+ m_error = u"Bad access type '"_s + access + u'\'';
+ return false;
+ }
+ const FunctionModification::ModifierFlag m = modifierFlagOpt.value();
+ if (m == FunctionModification::NonFinal) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader,
+ accessAttribute, access)));
+ }
+ mod.setModifierFlag(m);
+ }
+
+ mod.setRemoved(removed);
+
+ if (!rename.isEmpty()) {
+ mod.setRenamedToName(rename);
+ mod.setModifierFlag(FunctionModification::Rename);
+ }
+
+ top->functionMods << mod;
+ return true;
+}
+
+bool TypeSystemParser::parseReplaceDefaultExpression(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement & StackElement::ModifyArgument)) {
+ m_error = u"Replace default expression only allowed as child of argument modification"_s;
+ return false;
+ }
+ const auto withIndex = indexOfAttribute(*attributes, u"with");
+ if (withIndex == -1 || attributes->at(withIndex).value().isEmpty()) {
+ m_error = u"Default expression replaced with empty string. Use remove-default-expression instead."_s;
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods().last().setReplacedDefaultExpression(
+ attributes->takeAt(withIndex).value().toString());
+ return true;
+}
+
+bool TypeSystemParser::parseReferenceCount(const ConditionalStreamReader &reader,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::ModifyArgument) {
+ m_error = u"reference-count must be child of modify-argument"_s;
+ return false;
+ }
+
+ ReferenceCount rc;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == actionAttribute) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(i);
+ const auto actionOpt = referenceCountFromAttribute(attribute.value());
+ if (!actionOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ rc.action = actionOpt.value();
+ switch (rc.action) {
+ case ReferenceCount::AddAll:
+ case ReferenceCount::Ignore:
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader, attribute)));
+ break;
+ default:
+ break;
+ }
+ } else if (name == u"variable-name") {
+ rc.varName = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods().last().addReferenceCount(rc);
+ return true;
+}
+
+bool TypeSystemParser::parseParentOwner(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::ModifyArgument) {
+ m_error = u"parent-policy must be child of modify-argument"_s;
+ return false;
+ }
+ ArgumentOwner ao;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute) {
+ const QString index = attributes->takeAt(i).value().toString();
+ if (!parseArgumentIndex(index, &ao.index, &m_error))
+ return false;
+ } else if (name == actionAttribute) {
+ const auto action = attributes->takeAt(i);
+ const auto actionOpt = argumentOwnerActionFromAttribute(action.value());
+ if (!actionOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(action);
+ return false;
+ }
+ ao.action = actionOpt.value();
+ }
+ }
+ m_contextStack.top()->functionMods.last().argument_mods().last().setOwner(ao);
+ return true;
+}
+
+std::optional<TypeSystemParser::Snippet>
+ TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes)
+{
+ Snippet result;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == fileAttribute) {
+ result.fileName = attributes->takeAt(i).value().toString();
+ } else if (name == snippetAttribute) {
+ result.snippetLabel = attributes->takeAt(i).value().toString();
+ }
+ }
+ if (result.fileName.isEmpty()) {
+ m_error = "Snippet missing file name"_L1;
+ return std::nullopt;
+ }
+ const QString resolved = m_context->db->modifiedTypesystemFilepath(result.fileName,
+ m_currentPath);
+ if (!QFile::exists(resolved)) {
+ m_error = u"File for inject code not exist: "_s
+ + QDir::toNativeSeparators(result.fileName);
+ return std::nullopt;
+ }
+ QFile codeFile(resolved);
+ if (!codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ m_error = msgCannotOpenForReading(codeFile);
+ return std::nullopt;
+ }
+ const auto contentOptional = extractSnippet(QString::fromUtf8(codeFile.readAll()),
+ result.snippetLabel);
+ codeFile.close();
+ if (!contentOptional.has_value()) {
+ m_error = msgCannotFindSnippet(resolved, result.snippetLabel);
+ return std::nullopt;
+ }
+ result.content = contentOptional.value();
+ return result;
+}
+
+bool TypeSystemParser::readCodeSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip)
+{
+ if (!hasFileSnippetAttributes(attributes))
+ return true; // Expecting inline content.
+ const auto snippetOptional = readFileSnippet(attributes);
+ if (!snippetOptional.has_value())
+ return false;
+ const auto snippet = snippetOptional.value();
+
+ QString source = snippet.fileName;
+ if (!snippet.snippetLabel.isEmpty())
+ source += " ("_L1 + snippet.snippetLabel + u')';
+ QString content;
+ QTextStream str(&content);
+ str << "// ========================================================================\n"
+ "// START of custom code block [file: "
+ << source << "]\n" << snippet.content
+ << "// END of custom code block [file: " << source
+ << "]\n// ========================================================================\n";
+ snip->addCode(content);
+ return true;
+}
+
+bool TypeSystemParser::parseInjectCode(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!isComplexTypeEntry(topElement)
+ && (topElement != StackElement::AddFunction)
+ && (topElement != StackElement::ModifyFunction)
+ && (topElement != StackElement::Root)) {
+ m_error = u"wrong parent type for code injection"_s;
+ return false;
+ }
+
+ TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionBeginning;
+ TypeSystem::Language lang = TypeSystem::TargetLangCode;
+ CodeSnip snip;
+ if (!readCodeSnippet(attributes, &snip))
+ return false;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == classAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto langOpt = languageFromAttribute(attribute.value());
+ if (!langOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ lang = langOpt.value();
+ } else if (name == positionAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto positionOpt = codeSnipPositionFromAttribute(attribute.value());
+ if (!positionOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ position = positionOpt.value();
+ }
+ }
+
+ snip.position = position;
+ snip.language = lang;
+
+ switch (topElement) {
+ case StackElement::ModifyFunction:
+ case StackElement::AddFunction: {
+ FunctionModification &mod = m_contextStack.top()->functionMods.last();
+ mod.appendSnip(snip);
+ if (!snip.code().isEmpty())
+ mod.setModifierFlag(FunctionModification::CodeInjection);
+ }
+ break;
+ case StackElement::Root:
+ std::static_pointer_cast<TypeSystemTypeEntry>(m_contextStack.top()->entry)->addCodeSnip(snip);
+ break;
+ default:
+ std::static_pointer_cast<ComplexTypeEntry>(m_contextStack.top()->entry)->addCodeSnip(snip);
+ break;
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseInclude(const ConditionalStreamReader &,
+ StackElement topElement,
+ const TypeEntryPtr &entry, QXmlStreamAttributes *attributes)
+{
+ QString fileName;
+ Include::IncludeType location = Include::IncludePath;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == fileNameAttribute) {
+ fileName = attributes->takeAt(i).value().toString();
+ } else if (name == locationAttribute) {
+ const auto attribute = attributes->takeAt(i);
+ const auto locationOpt = locationFromAttribute(attribute.value());
+ if (!locationOpt.has_value()) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ location = locationOpt.value();
+ }
+ }
+
+ Include inc(location, fileName);
+ if (isComplexTypeEntry(topElement)
+ || topElement == StackElement::PrimitiveTypeEntry
+ || topElement == StackElement::ContainerTypeEntry
+ || topElement == StackElement::SmartPointerTypeEntry
+ || topElement == StackElement::TypedefTypeEntry) {
+ entry->setInclude(inc);
+ } else if (topElement == StackElement::ExtraIncludes) {
+ entry->addExtraInclude(inc);
+ } else {
+ m_error = u"Only supported parent tags are primitive-type, complex types or extra-includes"_s;
+ return false;
+ }
+ return true;
+}
+
+bool TypeSystemParser::parseSystemInclude(const ConditionalStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ const auto index = indexOfAttribute(*attributes, fileNameAttribute);
+ if (index == -1) {
+ m_error = msgMissingAttribute(fileNameAttribute);
+ return false;
+ }
+ TypeDatabase::instance()->addForceProcessSystemInclude(attributes->takeAt(index).value().toString());
+ return true;
+}
+
+TemplateInstance *
+ TypeSystemParser::parseInsertTemplate(const ConditionalStreamReader &,
+ StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if ((topElement != StackElement::InjectCode) &&
+ (topElement != StackElement::Template) &&
+ (topElement != StackElement::NativeToTarget) &&
+ (topElement != StackElement::AddConversion) &&
+ (topElement != StackElement::ConversionRule)) {
+ m_error = u"Can only insert templates into code snippets, templates, "\
+ "conversion-rule, native-to-target or add-conversion tags."_s;
+ return nullptr;
+ }
+ const auto nameIndex = indexOfAttribute(*attributes, nameAttribute);
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute);
+ return nullptr;
+ }
+ return new TemplateInstance(attributes->takeAt(nameIndex).value().toString());
+}
+
+bool TypeSystemParser::parseReplace(const ConditionalStreamReader &,
+ StackElement topElement, QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::InsertTemplate) {
+ m_error = u"Can only insert replace rules into insert-template."_s;
+ return false;
+ }
+ QString from;
+ QString to;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == u"from")
+ from = attributes->takeAt(i).value().toString();
+ else if (name == toAttribute)
+ to = attributes->takeAt(i).value().toString();
+ }
+ m_templateInstance->addReplaceRule(from, to);
+ return true;
+}
+
+// Check for a duplicated type entry and return whether to add the new one.
+// We need to be able to have duplicate primitive type entries,
+// or it's not possible to cover all primitive target language
+// types (which we need to do in order to support fake meta objects)
+bool TypeSystemParser::checkDuplicatedTypeEntry(const ConditionalStreamReader &reader,
+ StackElement t,
+ const QString &name) const
+{
+ if (t == StackElement::PrimitiveTypeEntry || t == StackElement::FunctionTypeEntry)
+ return true;
+ const auto duplicated = m_context->db->findType(name);
+ if (!duplicated || duplicated->isNamespace())
+ return true;
+ if (duplicated->isBuiltIn()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgReaderMessage(reader, "Warning",
+ msgDuplicateBuiltInTypeEntry(name))));
+ return false;
+ }
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgReaderMessage(reader, "Warning",
+ msgDuplicateTypeEntry(name))));
+ return true;
+}
+
+static bool parseVersion(const QString &versionSpec, const QString &package,
+ QVersionNumber *result, QString *errorMessage)
+{
+ *result = QVersionNumber::fromString(versionSpec);
+ if (result->isNull()) {
+ *errorMessage = msgInvalidVersion(versionSpec, package);
+ return false;
+ }
+ return true;
+}
+
+bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, StackElement element)
+{
+ if (m_ignoreDepth) {
+ ++m_ignoreDepth;
+ return true;
+ }
+
+ const auto tagName = reader.name();
+ QXmlStreamAttributes attributes = reader.attributes();
+
+ VersionRange versionRange;
+ for (auto i = attributes.size() - 1; i >= 0; --i) {
+ const auto name = attributes.at(i).qualifiedName();
+ if (name == sinceAttribute) {
+ if (!parseVersion(attributes.takeAt(i).value().toString(),
+ m_defaultPackage, &versionRange.since, &m_error)) {
+ return false;
+ }
+ } else if (name == untilAttribute) {
+ if (!parseVersion(attributes.takeAt(i).value().toString(),
+ m_defaultPackage, &versionRange.until, &m_error)) {
+ return false;
+ }
+ }
+ }
+
+ if (!m_defaultPackage.isEmpty() && !versionRange.isNull()) {
+ auto *td = TypeDatabase::instance();
+ if (!td->checkApiVersion(m_defaultPackage, versionRange)) {
+ ++m_ignoreDepth;
+ return true;
+ }
+ }
+
+ if (element == StackElement::ImportFile)
+ return importFileElement(attributes);
+
+ if (m_currentDroppedEntryDepth) {
+ ++m_currentDroppedEntryDepth;
+ return true;
+ }
+
+ if (element == StackElement::Root && m_generate == TypeEntry::GenerateCode)
+ customConversionsForReview.clear();
+
+ if (element == StackElement::Unimplemented) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedElementWarning(reader, tagName)));
+ return true;
+ }
+
+ if (isTypeEntry(element) || element == StackElement::Root)
+ m_contextStack.push(std::make_shared<StackElementContext>());
+
+ if (m_contextStack.isEmpty()) {
+ m_error = msgNoRootTypeSystemEntry();
+ return false;
+ }
+
+ const auto &top = m_contextStack.top();
+ const StackElement topElement = m_stack.value(m_stack.size() - 2, StackElement::None);
+
+ if (isTypeEntry(element)) {
+ QString name;
+ if (element != StackElement::FunctionTypeEntry) {
+ const auto nameIndex = indexOfAttribute(attributes, nameAttribute);
+ if (nameIndex != -1) {
+ name = attributes.takeAt(nameIndex).value().toString();
+ } else if (element != StackElement::EnumTypeEntry) { // anonymous enum?
+ m_error = msgMissingAttribute(nameAttribute);
+ return false;
+ }
+ }
+ // Allow for primitive and/or std:: types only, else require proper nesting.
+ if (element != StackElement::PrimitiveTypeEntry && name.contains(u':')
+ && !name.contains(u"std::")) {
+ m_error = msgIncorrectlyNestedName(name);
+ return false;
+ }
+
+ if (m_context->db->hasDroppedTypeEntries()) {
+ const QString identifier = element == StackElement::FunctionTypeEntry
+ ? attributes.value(signatureAttribute).toString().simplified() : name;
+ if (shouldDropTypeEntry(m_context->db, m_contextStack, identifier)) {
+ m_currentDroppedEntryDepth = 1;
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug)) {
+ qCInfo(lcShiboken, "Type system entry '%s' was intentionally dropped from generation.",
+ qPrintable(identifier));
+ }
+ m_contextStack.pop();
+ return true;
+ }
+ }
+
+ // The top level tag 'function' has only the 'signature' tag
+ // and we should extract the 'name' value from it.
+ if (element == StackElement::FunctionTypeEntry
+ && !parseRenameFunction(reader, &name, &attributes)) {
+ return false;
+ }
+
+ // We need to be able to have duplicate primitive type entries,
+ // or it's not possible to cover all primitive target language
+ // types (which we need to do in order to support fake meta objects)
+ if (element != StackElement::PrimitiveTypeEntry
+ && element != StackElement::FunctionTypeEntry) {
+ TypeEntryPtr tmp = m_context->db->findType(name);
+ if (tmp && !tmp->isNamespace())
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Duplicate type entry: '" << name << '\'';
+ }
+
+ if (element == StackElement::EnumTypeEntry) {
+ const auto enumIdentifiedByIndex =
+ indexOfAttribute(attributes, enumIdentifiedByValueAttribute);
+ const QString identifiedByValue = enumIdentifiedByIndex != -1
+ ? attributes.takeAt(enumIdentifiedByIndex).value().toString() : QString();
+ if (name.isEmpty()) {
+ name = identifiedByValue;
+ } else if (!identifiedByValue.isEmpty()) {
+ m_error = u"can't specify both 'name' and 'identified-by-value' attributes"_s;
+ return false;
+ }
+ }
+
+ if (name.isEmpty()) {
+ m_error = u"no 'name' attribute specified"_s;
+ return false;
+ }
+
+ switch (element) {
+ case StackElement::CustomTypeEntry:
+ top->entry = parseCustomTypeEntry(reader, name, versionRange.since, &attributes);
+ if (Q_UNLIKELY(!top->entry))
+ return false;
+ break;
+ case StackElement::PrimitiveTypeEntry:
+ top->entry = parsePrimitiveTypeEntry(reader, name, versionRange.since, &attributes);
+ if (Q_UNLIKELY(!top->entry))
+ return false;
+ break;
+ case StackElement::ContainerTypeEntry:
+ top->entry = parseContainerTypeEntry(reader, name, versionRange.since, &attributes);
+ if (top->entry == nullptr)
+ return false;
+ break;
+
+ case StackElement::SmartPointerTypeEntry:
+ top->entry = parseSmartPointerEntry(reader, name, versionRange.since, &attributes);
+ if (top->entry == nullptr)
+ return false;
+ break;
+ case StackElement::EnumTypeEntry:
+ m_currentEnum = parseEnumTypeEntry(reader, name, versionRange.since, &attributes);
+ if (Q_UNLIKELY(!m_currentEnum))
+ return false;
+ top->entry = m_currentEnum;
+ break;
+
+ case StackElement::ValueTypeEntry:
+ top->entry = parseValueTypeEntry(reader, name, versionRange.since, &attributes);
+ if (top->entry == nullptr)
+ return false;
+ break;
+ case StackElement::NamespaceTypeEntry:
+ top->entry = parseNamespaceTypeEntry(reader, name, versionRange.since, &attributes);
+ if (top->entry == nullptr)
+ return false;
+ break;
+ case StackElement::ObjectTypeEntry:
+ case StackElement::InterfaceTypeEntry: {
+ if (!checkRootElement())
+ return false;
+ auto ce = std::make_shared<ObjectTypeEntry>(name, versionRange.since, currentParentTypeEntry());
+ top->entry = ce;
+ applyCommonAttributes(reader, top->entry, &attributes);
+ applyComplexTypeAttributes(reader, ce, &attributes);
+ }
+ break;
+ case StackElement::FunctionTypeEntry:
+ top->entry = parseFunctionTypeEntry(reader, name, versionRange.since, &attributes);
+ if (Q_UNLIKELY(!top->entry))
+ return false;
+ break;
+ case StackElement::TypedefTypeEntry:
+ top->entry = parseTypedefEntry(reader, name, topElement,
+ versionRange.since, &attributes);
+ if (top->entry == nullptr)
+ return false;
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+
+ if (top->entry) {
+ if (checkDuplicatedTypeEntry(reader, element, top->entry->name())
+ && !m_context->db->addType(top->entry, &m_error)) {
+ return false;
+ }
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << u"Type: "_s + name + u" was rejected by typesystem"_s;
+ }
+
+ } else if (element == StackElement::InjectDocumentation) {
+ if (!parseInjectDocumentation(reader, topElement, &attributes))
+ return false;
+ } else if (element == StackElement::ModifyDocumentation) {
+ if (!parseModifyDocumentation(reader, topElement, &attributes))
+ return false;
+ } else if (element != StackElement::None) {
+ bool topLevel = element == StackElement::Root
+ || element == StackElement::SuppressedWarning
+ || element == StackElement::Rejection
+ || element == StackElement::LoadTypesystem
+ || element == StackElement::InjectCode
+ || element == StackElement::ExtraIncludes
+ || element == StackElement::SystemInclude
+ || element == StackElement::ConversionRule
+ || element == StackElement::AddFunction
+ || element == StackElement::DeclareFunction
+ || element == StackElement::Template
+ || element == StackElement::OpaqueContainer;
+
+ if (!topLevel && m_stack.at(m_stack.size() - 2) == StackElement::Root) {
+ m_error = u"Tag requires parent: '"_s + tagName.toString() + u'\'';
+ return false;
+ }
+
+ switch (element) {
+ case StackElement::Root:
+ top->entry = parseRootElement(reader, versionRange.since, &attributes);
+ break;
+ case StackElement::LoadTypesystem:
+ if (!loadTypesystem(reader, &attributes))
+ return false;
+ break;
+ case StackElement::RejectEnumValue:
+ if (!parseRejectEnumValue(reader, &attributes))
+ return false;
+ break;
+ case StackElement::ReplaceType:
+ if (!parseReplaceArgumentType(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ConversionRule:
+ if (!TypeSystemParser::parseCustomConversion(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::NativeToTarget:
+ if (!parseNativeToTarget(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::TargetToNative: {
+ if (topElement != StackElement::ConversionRule) {
+ m_error = u"Target to Native conversions can only be specified for custom conversion rules."_s;
+ return false;
+ }
+
+ const auto topParent = m_stack.value(m_stack.size() - 3, StackElement::None);
+ if (isTypeEntry(topParent)) {
+ const auto replaceIndex = indexOfAttribute(attributes, replaceAttribute);
+ const bool replace = replaceIndex == -1
+ || convertBoolean(attributes.takeAt(replaceIndex).value(),
+ replaceAttribute, true);
+ auto customConversion = CustomConversion::getCustomConversion(top->entry);
+ if (!customConversion) {
+ m_error = msgMissingCustomConversion(top->entry);
+ return false;
+ }
+ customConversion->setReplaceOriginalTargetToNativeConversions(replace);
+ }
+ }
+ break;
+ case StackElement::AddConversion:
+ if (!parseAddConversion(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ModifyArgument:
+ if (!parseModifyArgument(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::NoNullPointers:
+ if (!parseNoNullPointer(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::DefineOwnership:
+ if (!parseDefineOwnership(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::SuppressedWarning: {
+ const auto textIndex = indexOfAttribute(attributes, textAttribute);
+ if (textIndex == -1) {
+ qCWarning(lcShiboken) << "Suppressed warning with no text specified";
+ } else {
+ const QString suppressedWarning =
+ attributes.takeAt(textIndex).value().toString();
+ if (!m_context->db->addSuppressedWarning(suppressedWarning,
+ m_generate == TypeEntry::GenerateCode,
+ &m_error)) {
+ return false;
+ }
+ }
+ }
+ break;
+ case StackElement::Rename:
+ if (!parseRename(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::RemoveArgument:
+ if (topElement != StackElement::ModifyArgument) {
+ m_error = u"Removing argument requires argument modification as parent"_s;
+ return false;
+ }
+
+ top->functionMods.last().argument_mods().last().setRemoved(true);
+ break;
+
+ case StackElement::ModifyField:
+ if (!parseModifyField(reader, &attributes))
+ return false;
+ break;
+ case StackElement::DeclareFunction:
+ case StackElement::AddFunction:
+ if (!parseAddFunction(reader, topElement, element, &attributes))
+ return false;
+ break;
+ case StackElement::AddPyMethodDef:
+ if (!parseAddPyMethodDef(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::Property:
+ if (!parseProperty(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ModifyFunction:
+ if (!parseModifyFunction(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ReplaceDefaultExpression:
+ if (!parseReplaceDefaultExpression(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::RemoveDefaultExpression:
+ top->functionMods.last().argument_mods().last().setRemovedDefaultExpression(true);
+ break;
+ case StackElement::ReferenceCount:
+ if (!parseReferenceCount(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::ParentOwner:
+ if (!parseParentOwner(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::Array:
+ if (topElement != StackElement::ModifyArgument) {
+ m_error = u"array must be child of modify-argument"_s;
+ return false;
+ }
+ top->functionMods.last().argument_mods().last().setArray(true);
+ break;
+ case StackElement::InjectCode:
+ if (!parseInjectCode(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::Include:
+ if (!parseInclude(reader, topElement, top->entry, &attributes))
+ return false;
+ break;
+ case StackElement::Rejection:
+ if (!addRejection(m_context->db, m_generate == TypeEntry::GenerateCode,
+ &attributes, &m_error)) {
+ return false;
+ }
+ break;
+ case StackElement::SystemInclude:
+ if (!parseSystemInclude(reader, &attributes))
+ return false;
+ break;
+ case StackElement::Template: {
+ const auto nameIndex = indexOfAttribute(attributes, nameAttribute);
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute);
+ return false;
+ }
+ m_templateEntry.reset(new TemplateEntry(attributes.takeAt(nameIndex).value().toString()));
+ }
+ break;
+ case StackElement::InsertTemplate:
+ m_templateInstance.reset(parseInsertTemplate(reader, topElement, &attributes));
+ if (!m_templateInstance)
+ return false;
+ break;
+ case StackElement::Replace:
+ if (!parseReplace(reader, topElement, &attributes))
+ return false;
+ break;
+ case StackElement::OpaqueContainer:
+ if (!parseOpaqueContainerElement(&attributes))
+ case StackElement::Configuration:
+ if (!parseConfiguration(topElement, &attributes))
+ return false;
+ break;
+ default:
+ break; // nada
+ }
+ }
+
+ if (!attributes.isEmpty()) {
+ const QString message = msgUnusedAttributes(tagName, attributes);
+ qCWarning(lcShiboken, "%s", qPrintable(msgReaderWarning(reader, message)));
+ }
+
+ return true;
+}
diff --git a/sources/shiboken6/ApiExtractor/typesystemparser_p.h b/sources/shiboken6/ApiExtractor/typesystemparser_p.h
new file mode 100644
index 000000000..4d9d4fd92
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typesystemparser_p.h
@@ -0,0 +1,297 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#ifndef TYPESYSTEMPARSER_H
+#define TYPESYSTEMPARSER_H
+
+#include "typesystem.h"
+#include "containertypeentry.h"
+#include "typedatabase.h"
+#include "typedatabase_p.h"
+#include "typesystem_typedefs.h"
+#include "codesnip.h"
+
+#include <QtCore/QStack>
+#include <QtCore/QHash>
+#include <QtCore/QScopedPointer>
+
+#include <memory>
+#include <optional>
+
+QT_FORWARD_DECLARE_CLASS(QVersionNumber)
+QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes)
+QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
+
+class ConditionalStreamReader;
+
+class TypeSystemEntityResolver;
+class TypeDatabase;
+
+class FlagsTypeEntry;
+class TypeSystemTypeEntry;
+class ValueTypeEntry;
+class EnumTypeEntry;
+
+enum class ParserState;
+
+enum class StackElement {
+ None,
+
+ // Type tags
+ ObjectTypeEntry,
+ FirstTypeEntry = ObjectTypeEntry,
+ ValueTypeEntry,
+ InterfaceTypeEntry,
+ NamespaceTypeEntry,
+ LastComplexTypeEntry = NamespaceTypeEntry,
+
+ // Non-complex type tags
+ PrimitiveTypeEntry,
+ EnumTypeEntry,
+ ContainerTypeEntry,
+ FunctionTypeEntry,
+ CustomTypeEntry,
+ SmartPointerTypeEntry,
+ TypedefTypeEntry,
+ LastTypeEntry = TypedefTypeEntry,
+
+ // Documentation tags
+ InjectDocumentation,
+ FirstDocumentation = InjectDocumentation,
+ ModifyDocumentation,
+ LastDocumentation = ModifyDocumentation,
+
+ // Simple tags
+ ExtraIncludes,
+ Include,
+ ModifyFunction,
+ ModifyField,
+ Root,
+ SuppressedWarning,
+ Rejection,
+ LoadTypesystem,
+ RejectEnumValue,
+ Template,
+ InsertTemplate,
+ Replace,
+ AddFunction,
+ AddPyMethodDef,
+ DeclareFunction,
+ NativeToTarget,
+ TargetToNative,
+ AddConversion,
+ SystemInclude,
+ Property,
+
+ // Code snip tags
+ InjectCode,
+
+ // Function modifier tags
+ Rename, // (modify-argument)
+ ModifyArgument,
+ Thread,
+
+ // Argument modifier tags
+ ConversionRule,
+ ReplaceType,
+ ReplaceDefaultExpression,
+ RemoveArgument,
+ DefineOwnership,
+ RemoveDefaultExpression,
+ NoNullPointers,
+ ReferenceCount,
+ ParentOwner,
+ Array,
+ ArgumentModifiers,
+
+ ImportFile,
+ OpaqueContainer,
+ Configuration,
+ Unimplemented
+};
+
+inline uint64_t operator&(StackElement s1, StackElement s2)
+{
+ return uint64_t(s1) & uint64_t(s2);
+}
+
+inline StackElement operator|(StackElement s1, StackElement s2)
+{
+ return StackElement(uint64_t(s1) | uint64_t(s2));
+}
+
+struct StackElementContext
+{
+ CodeSnipList conversionCodeSnips;
+ AddedFunctionList addedFunctions;
+ FunctionModificationList functionMods;
+ FieldModificationList fieldMods;
+ DocModificationList docModifications;
+ TypeEntryPtr entry;
+ int addedFunctionModificationIndex = -1;
+};
+
+class TypeSystemParser
+{
+public:
+ Q_DISABLE_COPY_MOVE(TypeSystemParser)
+
+ using StackElementContextPtr = std::shared_ptr<StackElementContext>;
+ using ContextStack = QStack<StackElementContextPtr>;
+
+ explicit TypeSystemParser(const std::shared_ptr<TypeDatabaseParserContext> &context,
+ bool generate);
+ ~TypeSystemParser();
+
+ bool parse(ConditionalStreamReader &reader);
+
+ QString errorString() const { return m_error; }
+
+private:
+ struct Snippet
+ {
+ QString content;
+ QString fileName;
+ QString snippetLabel;
+ };
+
+ bool parseXml(ConditionalStreamReader &reader);
+ bool setupSmartPointerInstantiations();
+ bool startElement(const ConditionalStreamReader &reader, StackElement element);
+ SmartPointerTypeEntryPtr parseSmartPointerEntry(const ConditionalStreamReader &,
+ const QString &name,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes);
+ bool endElement(StackElement element);
+ template <class String> // QString/QStringRef
+ bool characters(const String &ch);
+
+ bool importFileElement(const QXmlStreamAttributes &atts);
+
+ TypeEntryCPtr currentParentTypeEntry() const;
+ bool checkRootElement();
+ bool applyCommonAttributes(const ConditionalStreamReader &reader,
+ const TypeEntryPtr &type,
+ QXmlStreamAttributes *attributes);
+ PrimitiveTypeEntryPtr
+ parsePrimitiveTypeEntry(const ConditionalStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ CustomTypeEntryPtr
+ parseCustomTypeEntry(const ConditionalStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ bool parseOpaqueContainers(QStringView s, OpaqueContainers *result);
+ ContainerTypeEntryPtr
+ parseContainerTypeEntry(const ConditionalStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ bool parseOpaqueContainerElement(QXmlStreamAttributes *attributes);
+ EnumTypeEntryPtr
+ parseEnumTypeEntry(const ConditionalStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ FlagsTypeEntryPtr
+ parseFlagsEntry(const ConditionalStreamReader &, const EnumTypeEntryPtr &enumEntry,
+ QString flagName, const QVersionNumber &since,
+ QXmlStreamAttributes *);
+
+ NamespaceTypeEntryPtr
+ parseNamespaceTypeEntry(const ConditionalStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes);
+
+ ValueTypeEntryPtr
+ parseValueTypeEntry(const ConditionalStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ FunctionTypeEntryPtr
+ parseFunctionTypeEntry(const ConditionalStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ TypedefEntryPtr
+ parseTypedefEntry(const ConditionalStreamReader &, const QString &name,
+ StackElement topElement,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ void applyComplexTypeAttributes(const ConditionalStreamReader &, const ComplexTypeEntryPtr &ctype,
+ QXmlStreamAttributes *) const;
+ bool parseConfiguration(StackElement topElement,
+ QXmlStreamAttributes *attributes);
+ bool parseRenameFunction(const ConditionalStreamReader &, QString *name,
+ QXmlStreamAttributes *);
+ bool parseInjectDocumentation(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseModifyDocumentation(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ TypeSystemTypeEntryPtr
+ parseRootElement(const ConditionalStreamReader &, const QVersionNumber &since,
+ QXmlStreamAttributes *);
+ bool loadTypesystem(const ConditionalStreamReader &, QXmlStreamAttributes *);
+ bool parseRejectEnumValue(const ConditionalStreamReader &, QXmlStreamAttributes *);
+ bool parseReplaceArgumentType(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseCustomConversion(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseAddConversion(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseNativeToTarget(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *attributes);
+ bool parseModifyArgument(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *attributes);
+ bool parseNoNullPointer(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *attributes);
+ bool parseDefineOwnership(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseRename(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseModifyField(const ConditionalStreamReader &, QXmlStreamAttributes *);
+ bool parseAddFunction(const ConditionalStreamReader &, StackElement topElement,
+ StackElement t, QXmlStreamAttributes *);
+ bool parseAddPyMethodDef(const ConditionalStreamReader &,
+ StackElement topElement, QXmlStreamAttributes *attributes);
+ bool parseProperty(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseBasicModifyFunctionAttributes(QXmlStreamAttributes *,
+ FunctionModification *mod);
+ bool parseModifyFunctionAttributes(QXmlStreamAttributes *,
+ FunctionModification *mod);
+ bool parseModifyFunction(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseReplaceDefaultExpression(const ConditionalStreamReader &,
+ StackElement topElement, QXmlStreamAttributes *);
+ bool parseReferenceCount(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseParentOwner(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ std::optional<Snippet> readFileSnippet(QXmlStreamAttributes *attributes);
+ bool readCodeSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip);
+ bool parseInjectCode(const ConditionalStreamReader &, StackElement topElement, QXmlStreamAttributes *);
+ bool parseInclude(const ConditionalStreamReader &, StackElement topElement,
+ const TypeEntryPtr &entry, QXmlStreamAttributes *);
+ bool parseSystemInclude(const ConditionalStreamReader &, QXmlStreamAttributes *);
+ TemplateInstance
+ *parseInsertTemplate(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool parseReplace(const ConditionalStreamReader &, StackElement topElement,
+ QXmlStreamAttributes *);
+ bool checkDuplicatedTypeEntry(const ConditionalStreamReader &reader,
+ StackElement t, const QString &name) const;
+ ParserState parserState(qsizetype offset = 0) const;
+ CodeSnipAbstract *injectCodeTarget(qsizetype offset = 0) const;
+
+ std::shared_ptr<TypeDatabaseParserContext> m_context;
+ QStack<StackElement> m_stack;
+ int m_currentDroppedEntryDepth = 0;
+ int m_ignoreDepth = 0;
+ QString m_defaultPackage;
+ QString m_defaultSuperclass;
+ TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+ TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified;
+ QString m_error;
+ const TypeEntry::CodeGeneration m_generate;
+
+ EnumTypeEntryPtr m_currentEnum;
+ TemplateInstancePtr m_templateInstance;
+ TemplateEntryPtr m_templateEntry;
+ ContextStack m_contextStack;
+
+ QString m_currentSignature;
+ QString m_currentPath;
+ QString m_currentFile;
+ QScopedPointer<TypeSystemEntityResolver> m_entityResolver;
+};
+
+#endif // TYPESYSTEMPARSER_H
diff --git a/sources/shiboken6/ApiExtractor/typesystemtypeentry.h b/sources/shiboken6/ApiExtractor/typesystemtypeentry.h
new file mode 100644
index 000000000..9b9670696
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/typesystemtypeentry.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPESYSTEMTYPEENTRY_H
+#define TYPESYSTEMTYPEENTRY_H
+
+#include "typesystem.h"
+#include "modifications_typedefs.h"
+#include "typesystem_enums.h"
+#include "typesystem_typedefs.h"
+
+class TypeSystemTypeEntry : public TypeEntry
+{
+public:
+ explicit TypeSystemTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ TypeEntry *clone() const override;
+
+ TypeSystem::SnakeCase snakeCase() const;
+ void setSnakeCase(TypeSystem::SnakeCase sc);
+
+ const CodeSnipList &codeSnips() const;
+ CodeSnipList &codeSnips();
+ void addCodeSnip(const CodeSnip &codeSnip);
+
+ QString subModuleOf() const;
+ void setSubModule(const QString &);
+
+ const QString &namespaceBegin() const;
+ void setNamespaceBegin(const QString &n);
+
+ const QString &namespaceEnd() const;
+ void setNamespaceEnd(const QString &n);
+
+protected:
+ explicit TypeSystemTypeEntry(TypeEntryPrivate *d);
+};
+
+#endif // TYPESYSTEMTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/usingmember.h b/sources/shiboken6/ApiExtractor/usingmember.h
new file mode 100644
index 000000000..346eab13c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/usingmember.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef USINGMEMBER_H
+#define USINGMEMBER_H
+
+#include "abstractmetalang_typedefs.h"
+#include "parser/codemodel_enums.h"
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+struct UsingMember // Introducing a base class member via 'using' directive
+{
+ QString memberName;
+ AbstractMetaClassCPtr baseClass;
+ Access access;
+};
+
+QDebug operator<<(QDebug debug, const UsingMember &d);
+
+#endif // USINGMEMBER_H
diff --git a/sources/shiboken6/ApiExtractor/valuetypeentry.h b/sources/shiboken6/ApiExtractor/valuetypeentry.h
new file mode 100644
index 000000000..97bc26803
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/valuetypeentry.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef VALUETYPEENTRY_H
+#define VALUETYPEENTRY_H
+
+#include "complextypeentry.h"
+#include "customconversion_typedefs.h"
+
+class ValueTypeEntry : public ComplexTypeEntry
+{
+public:
+ explicit ValueTypeEntry(const QString &entryName, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+
+ bool hasCustomConversion() const;
+ void setCustomConversion(const CustomConversionPtr &customConversion);
+ CustomConversionPtr customConversion() const;
+
+ // FIXME PYSIDE7: Remove
+ /// Set the target type conversion rule
+ void setTargetConversionRule(const QString &conversionRule);
+
+ /// Returns the target type conversion rule
+ QString targetConversionRule() const;
+
+ /// TODO-CONVERTER: mark as deprecated
+ bool hasTargetConversionRule() const;
+
+ bool isValue() const override;
+
+ TypeEntry *clone() const override;
+
+protected:
+ explicit ValueTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr,
+ const TypeEntryCPtr &parent);
+ explicit ValueTypeEntry(ComplexTypeEntryPrivate *d);
+};
+
+#endif // VALUETYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/varargstypeentry.h b/sources/shiboken6/ApiExtractor/varargstypeentry.h
new file mode 100644
index 000000000..b2a4f4d30
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/varargstypeentry.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef VARARGSTYPEENTRY_H
+#define VARARGSTYPEENTRY_H
+
+#include "typesystem.h"
+
+class VarargsTypeEntry : public TypeEntry
+{
+public:
+ VarargsTypeEntry();
+
+ TypeEntry *clone() const override;
+
+protected:
+ explicit VarargsTypeEntry(TypeEntryPrivate *d);
+};
+
+#endif // VARARGSTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/voidtypeentry.h b/sources/shiboken6/ApiExtractor/voidtypeentry.h
new file mode 100644
index 000000000..372c7c01f
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/voidtypeentry.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef VOIDTYPEENTRY_H
+#define VOIDTYPEENTRY_H
+
+#include "typesystem.h"
+
+class VoidTypeEntry : public TypeEntry
+{
+public:
+ VoidTypeEntry();
+
+ TypeEntry *clone() const override;
+
+protected:
+ explicit VoidTypeEntry(TypeEntryPrivate *d);
+};
+
+#endif // VOIDTYPEENTRY_H
diff --git a/sources/shiboken6/ApiExtractor/xmlutils.cpp b/sources/shiboken6/ApiExtractor/xmlutils.cpp
new file mode 100644
index 000000000..ccacd4ce7
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/xmlutils.cpp
@@ -0,0 +1,42 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "xmlutils.h"
+
+#include "xmlutils_libxslt.h"
+
+#include "qtcompat.h"
+
+using namespace Qt::StringLiterals;
+
+XQuery::XQuery() = default;
+
+XQuery::~XQuery() = default;
+
+QString XQuery::evaluate(QString xPathExpression, QString *errorMessage)
+{
+ // XQuery can't have invalid XML characters
+ xPathExpression.replace(u'&', u"&amp;"_s);
+ xPathExpression.replace(u'<', u"&lt;"_s);
+ return doEvaluate(xPathExpression, errorMessage);
+}
+
+std::shared_ptr<XQuery> XQuery::create(const QString &focus, QString *errorMessage)
+{
+#if defined(HAVE_LIBXSLT)
+ return libXml_createXQuery(focus, errorMessage);
+#else
+ *errorMessage = QLatin1StringView(__FUNCTION__) + u" is not implemented."_s;
+ return std::shared_ptr<XQuery>();
+#endif
+}
+
+QString xsl_transform(const QString &xml, const QString &xsl, QString *errorMessage)
+{
+#if defined(HAVE_LIBXSLT)
+ return libXslt_transform(xml, xsl, errorMessage);
+#else
+ *errorMessage = QLatin1StringView(__FUNCTION__) + u" is not implemented."_s;
+ return xml;
+#endif
+}
diff --git a/sources/shiboken6/ApiExtractor/xmlutils.h b/sources/shiboken6/ApiExtractor/xmlutils.h
new file mode 100644
index 000000000..ac23c9c9c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/xmlutils.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#ifndef XMLUTILS_H
+#define XMLUTILS_H
+
+#include <QtCore/QString>
+
+#include <memory>
+
+class XQuery
+{
+public:
+ Q_DISABLE_COPY_MOVE(XQuery)
+
+ virtual ~XQuery();
+
+ QString evaluate(QString xPathExpression, QString *errorMessage);
+
+ static std::shared_ptr<XQuery> create(const QString &focus, QString *errorMessage);
+
+protected:
+ XQuery();
+
+ virtual QString doEvaluate(const QString &xPathExpression, QString *errorMessage) = 0;
+};
+
+QString xsl_transform(const QString &xml, const QString &xsl, QString *errorMessage);
+
+#endif // XMLUTILS_H
diff --git a/sources/shiboken6/ApiExtractor/xmlutils_libxslt.cpp b/sources/shiboken6/ApiExtractor/xmlutils_libxslt.cpp
new file mode 100644
index 000000000..5a9a26913
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/xmlutils_libxslt.cpp
@@ -0,0 +1,208 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "xmlutils_libxslt.h"
+#include "xmlutils.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QString>
+
+#include <libxslt/xsltutils.h>
+#include <libxslt/transform.h>
+
+#include <libxml/xmlsave.h>
+#include <libxml/xpath.h>
+
+#include <cstdlib>
+#include <memory>
+
+using namespace Qt::StringLiterals;
+
+static void cleanup()
+{
+ xsltCleanupGlobals();
+ xmlCleanupParser();
+}
+
+static void ensureInitialized()
+{
+ static bool initialized = false;
+ if (!initialized) {
+ initialized = true;
+ xmlInitParser();
+ xsltInit();
+ qAddPostRoutine(cleanup);
+ }
+}
+
+// RAI Helpers for cleaning up libxml2/libxslt data
+
+struct XmlDocDeleter // for std::unique_ptr<xmlDoc>
+{
+ void operator()(xmlDocPtr xmlDoc) { xmlFreeDoc(xmlDoc); }
+};
+
+struct XmlXPathObjectDeleter
+{
+ void operator()(xmlXPathObjectPtr xPathObject) { xmlXPathFreeObject(xPathObject); }
+};
+
+struct XmlStyleSheetDeleter // for std::unique_ptr<xsltStylesheet>
+{
+ void operator()(xsltStylesheetPtr xslt) { xsltFreeStylesheet(xslt); }
+};
+
+struct XmlXPathContextDeleter
+{
+ void operator()(xmlXPathContextPtr xPathContext) { xmlXPathFreeContext(xPathContext); }
+};
+
+using XmlDocUniquePtr = std::unique_ptr<xmlDoc, XmlDocDeleter>;
+using XmlPathObjectUniquePtr = std::unique_ptr<xmlXPathObject, XmlXPathObjectDeleter>;
+using XmlStyleSheetUniquePtr = std::unique_ptr<xsltStylesheet, XmlStyleSheetDeleter>;
+using XmlXPathContextUniquePtr = std::unique_ptr<xmlXPathContext, XmlXPathContextDeleter>;
+
+// Helpers for formatting nodes obtained from XPATH queries
+
+static int qbXmlOutputWriteCallback(void *context, const char *buffer, int len)
+{
+ static_cast<QByteArray *>(context)->append(buffer, len);
+ return len;
+}
+
+static int qbXmlOutputCloseCallback(void * /* context */) { return 0; }
+
+static QByteArray formatNode(xmlNodePtr node, QString *errorMessage)
+{
+ QByteArray result;
+ xmlSaveCtxtPtr saveContext =
+ xmlSaveToIO(qbXmlOutputWriteCallback, qbXmlOutputCloseCallback,
+ &result, "UTF-8", 0);
+ if (!saveContext) {
+ *errorMessage = u"xmlSaveToIO() failed."_s;
+ return result;
+ }
+ const long saveResult = xmlSaveTree(saveContext, node);
+ xmlSaveClose(saveContext);
+ if (saveResult < 0)
+ *errorMessage = u"xmlSaveTree() failed."_s;
+ return result;
+}
+
+// XPath expressions
+class LibXmlXQuery : public XQuery
+{
+public:
+ explicit LibXmlXQuery(XmlDocUniquePtr &doc, XmlXPathContextUniquePtr &xpathContext) :
+ m_doc(std::move(doc)), m_xpathContext(std::move(xpathContext))
+ {
+ ensureInitialized();
+ }
+
+protected:
+ QString doEvaluate(const QString &xPathExpression, QString *errorMessage) override;
+
+private:
+ XmlDocUniquePtr m_doc;
+ XmlXPathContextUniquePtr m_xpathContext;
+};
+
+QString LibXmlXQuery::doEvaluate(const QString &xPathExpression, QString *errorMessage)
+{
+ const QByteArray xPathExpressionB = xPathExpression.toUtf8();
+ auto xPathExpressionX = reinterpret_cast<const xmlChar *>(xPathExpressionB.constData());
+
+ XmlPathObjectUniquePtr xPathObject(xmlXPathEvalExpression(xPathExpressionX, m_xpathContext.get()));
+ if (!xPathObject) {
+ *errorMessage = u"xmlXPathEvalExpression() failed for \""_s + xPathExpression
+ + u'"';
+ return QString();
+ }
+ QString result;
+ if (xmlNodeSetPtr nodeSet = xPathObject->nodesetval) {
+ for (int n = 0, count = nodeSet->nodeNr; n < count; ++n) {
+ auto node = nodeSet->nodeTab[n];
+ if (node->type == XML_ELEMENT_NODE) {
+ result += QString::fromLocal8Bit(formatNode(node, errorMessage));
+ if (!errorMessage->isEmpty())
+ return QString();
+ }
+ }
+ }
+ return result;
+}
+
+std::shared_ptr<XQuery> libXml_createXQuery(const QString &focus, QString *errorMessage)
+{
+ XmlDocUniquePtr doc(xmlReadFile(QFile::encodeName(focus).constData(),
+ "utf-8", XML_PARSE_NOENT));
+ if (!doc) {
+ *errorMessage = u"libxml2: Cannot set focus to "_s + QDir::toNativeSeparators(focus);
+ return {};
+ }
+ XmlXPathContextUniquePtr xpathContext(xmlXPathNewContext(doc.get()));
+ if (!xpathContext) {
+ *errorMessage = u"libxml2: xmlXPathNewContext() failed"_s;
+ return {};
+ }
+ return std::shared_ptr<XQuery>(new LibXmlXQuery(doc, xpathContext));
+}
+
+// XSLT transformation
+
+static constexpr auto xsltPrefix = R"(<?xml version="1.0" encoding="UTF-8" ?>
+ <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+)"_L1;
+
+QString libXslt_transform(const QString &xml, QString xsl, QString *errorMessage)
+{
+ ensureInitialized();
+ // Read XML data
+ if (!xsl.startsWith(u"<?xml")) {
+ xsl.prepend(xsltPrefix);
+ xsl.append(u"</xsl:transform>"_s);
+ }
+ const QByteArray xmlData = xml.toUtf8();
+
+ XmlDocUniquePtr xmlDoc(xmlReadMemory(xmlData.constData(), int(xmlData.size()),
+ "", "utf-8", XML_PARSE_NOENT));
+ if (!xmlDoc) {
+ *errorMessage = u"xmlParseMemory() failed for XML."_s;
+ return xml;
+ }
+
+ // Read XSL data as a XML file
+ const QByteArray xslData = xsl.toUtf8();
+ // xsltFreeStylesheet will delete this pointer
+ xmlDocPtr xslDoc = xmlParseMemory(xslData.constData(), xslData.size());
+ if (!xslDoc) {
+ *errorMessage = u"xmlParseMemory() failed for XSL \""_s + xsl + u"\"."_s;
+ return xml;
+ };
+
+ // Parse XSL data
+ XmlStyleSheetUniquePtr xslt(xsltParseStylesheetDoc(xslDoc));
+ if (!xslt) {
+ *errorMessage = u"xsltParseStylesheetDoc() failed."_s;
+ return xml;
+ }
+
+ // Apply XSL
+ XmlDocUniquePtr xslResult(xsltApplyStylesheet(xslt.get(), xmlDoc.get(), nullptr));
+ xmlChar *buffer = nullptr;
+ int bufferSize;
+ QString result;
+ if (xsltSaveResultToString(&buffer, &bufferSize, xslResult.get(), xslt.get()) == 0) {
+ result = QString::fromUtf8(reinterpret_cast<char*>(buffer), bufferSize);
+ std::free(buffer);
+ } else {
+ *errorMessage = u"xsltSaveResultToString() failed."_s;
+ result = xml;
+ }
+ return result.trimmed();
+}
diff --git a/sources/shiboken6/ApiExtractor/xmlutils_libxslt.h b/sources/shiboken6/ApiExtractor/xmlutils_libxslt.h
new file mode 100644
index 000000000..0dd8eafcb
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/xmlutils_libxslt.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#ifndef XMLUTILS_LIBXSLT_H
+#define XMLUTILS_LIBXSLT_H
+
+#include <QtCore/QString>
+
+#include <memory>
+
+class XQuery;
+
+std::shared_ptr<XQuery> libXml_createXQuery(const QString &focus, QString *errorMessage);
+
+QString libXslt_transform(const QString &xml, QString xsl, QString *errorMessage);
+
+#endif // XMLUTILS_LIBXSLT_H
diff --git a/sources/shiboken6/ApiExtractor/xmlutils_qt.h b/sources/shiboken6/ApiExtractor/xmlutils_qt.h
new file mode 100644
index 000000000..274827044
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/xmlutils_qt.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#ifndef XMLUTILS_QT_H
+#define XMLUTILS_QT_H
+
+#include <QtCore/QString>
+
+#include <memory>
+
+class XQuery;
+
+std::shared_ptr<XQuery> qt_createXQuery(const QString &focus, QString *errorMessage);
+
+QString qt_xsl_transform(const QString &xml, QString xsl, QString *errorMessage);
+
+#endif // XMLUTILS_QT_H
diff --git a/sources/shiboken6/CMakeLists.txt b/sources/shiboken6/CMakeLists.txt
new file mode 100644
index 000000000..9e1bb09b3
--- /dev/null
+++ b/sources/shiboken6/CMakeLists.txt
@@ -0,0 +1,36 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+Include(icecc.cmake)
+
+cmake_minimum_required(VERSION 3.18)
+cmake_policy(VERSION 3.18)
+
+set(CMAKE_BUILD_TYPE Release CACHE STRING "Build Type")
+
+include(".cmake.conf")
+project(shiboken6)
+include(cmake/ShibokenSetup.cmake)
+
+get_rpath_base_token(base)
+
+set(CMAKE_INSTALL_RPATH ${base}/)
+
+if(SHIBOKEN_BUILD_TOOLS)
+ add_subdirectory(ApiExtractor) # Uses libclang
+ add_subdirectory(generator) # Uses ApiExtractor And QtCore
+endif()
+
+if(SHIBOKEN_BUILD_LIBS)
+ add_subdirectory(libshiboken) # Uses Python
+ add_subdirectory(shibokenmodule) # Uses libshiboken
+ add_subdirectory(data)
+endif()
+
+add_subdirectory(doc)
+
+if(BUILD_TESTS)
+ enable_testing()
+ add_subdirectory(tests)
+endif()
+
diff --git a/sources/shiboken6/COPYING b/sources/shiboken6/COPYING
new file mode 100644
index 000000000..4ccd71466
--- /dev/null
+++ b/sources/shiboken6/COPYING
@@ -0,0 +1,342 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+-------------------------------------------------------------------------
diff --git a/sources/shiboken6/COPYING.libsample b/sources/shiboken6/COPYING.libsample
new file mode 100644
index 000000000..9315102f7
--- /dev/null
+++ b/sources/shiboken6/COPYING.libsample
@@ -0,0 +1,501 @@
+GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
diff --git a/sources/shiboken6/COPYING.libshiboken b/sources/shiboken6/COPYING.libshiboken
new file mode 100644
index 000000000..9315102f7
--- /dev/null
+++ b/sources/shiboken6/COPYING.libshiboken
@@ -0,0 +1,501 @@
+GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
diff --git a/sources/shiboken6/Doxyfile b/sources/shiboken6/Doxyfile
new file mode 100644
index 000000000..9be56a0e4
--- /dev/null
+++ b/sources/shiboken6/Doxyfile
@@ -0,0 +1,311 @@
+# Doxyfile 1.5.7.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = "Generator Runner"
+PROJECT_NUMBER = 0.1
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = /tmp/src/generatorrunner/
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+TYPEDEF_HIDES_STRUCT = NO
+SYMBOL_CACHE_SIZE = 0
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = /tmp/src/generatorrunner
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.vhd \
+ *.vhdl \
+ *.C \
+ *.CC \
+ *.C++ \
+ *.II \
+ *.I++ \
+ *.H \
+ *.HH \
+ *.H++ \
+ *.CS \
+ *.PHP \
+ *.PHP3 \
+ *.M \
+ *.MM \
+ *.PY \
+ *.F90 \
+ *.F \
+ *.VHD \
+ *.VHDL
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 3
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+HTML_DYNAMIC_SECTIONS = NO
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE = org.doxygen.Project
+QHP_VIRTUAL_FOLDER = doc
+QHG_LOCATION =
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NONE
+TREEVIEW_WIDTH = 250
+FORMULA_FONTSIZE = 10
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES = ../libgenrunner/libgenrunner.tag=../libgenrunner
+GENERATE_TAGFILE = generatorrunner.tag
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+MSCGEN_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+DOT_FONTNAME = FreeSans
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = NO
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = NO
+INCLUDED_BY_GRAPH = NO
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/sources/shiboken6/cmake/FindDocTools.cmake b/sources/shiboken6/cmake/FindDocTools.cmake
new file mode 100644
index 000000000..621a4ac15
--- /dev/null
+++ b/sources/shiboken6/cmake/FindDocTools.cmake
@@ -0,0 +1,39 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+find_program(SPHINX_BUILD sphinx-build DOC "Path to sphinx-build binary.")
+
+# graphviz dot appears to be used by sphinx and not by CMake directly. This is just found to check
+# if it exists.
+find_program(DOT_EXEC dot)
+
+# Lookup for qdoc and qhelpgenerator in multiple sources: ccache var, PATH or CMake package.
+set(qhelpgenerator_binary "")
+set(qdoc_binary "")
+if(QHELPGENERATOR_EXECUTABLE)
+ set(qhelpgenerator_binary "${QHELPGENERATOR_EXECUTABLE}")
+else()
+ find_package(Qt6 QUIET COMPONENTS Tools)
+ if(TARGET Qt6::qhelpgenerator)
+ get_target_property(qhelpgenerator_binary Qt6::qhelpgenerator IMPORTED_LOCATION)
+ else()
+ find_program(QHELPGENERATOR_EXECUTABLE qhelpgenerator DOC "Path to qhelpgenerator binary.")
+ if(QHELPGENERATOR_EXECUTABLE)
+ set(qhelpgenerator_binary "${QHELPGENERATOR_EXECUTABLE}")
+ endif()
+ endif()
+endif()
+
+if(QDOC_EXECUTABLE)
+ set(qdoc_binary "${QDOC_EXECUTABLE}")
+else()
+ find_package(Qt6 QUIET COMPONENTS Tools)
+ if(TARGET Qt6::qdoc)
+ get_target_property(qdoc_binary Qt6::qdoc IMPORTED_LOCATION)
+ else()
+ find_program(QDOC_EXECUTABLE qdoc DOC "Path to qdoc binary.")
+ if(QDOC_EXECUTABLE)
+ set(qdoc_binary "${QDOC_EXECUTABLE}")
+ endif()
+ endif()
+endif()
diff --git a/sources/shiboken6/cmake/ShibokenHelpers.cmake b/sources/shiboken6/cmake/ShibokenHelpers.cmake
new file mode 100644
index 000000000..cff6df95e
--- /dev/null
+++ b/sources/shiboken6/cmake/ShibokenHelpers.cmake
@@ -0,0 +1,889 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(CMakeParseArguments)
+
+macro(set_limited_api)
+ if (WIN32 AND NOT EXISTS "${PYTHON_LIMITED_LIBRARIES}")
+ message(FATAL_ERROR "The Limited API was enabled, but ${PYTHON_LIMITED_LIBRARIES} was not found!")
+ endif()
+ message(STATUS "******************************************************")
+ message(STATUS "** Limited API enabled ${PYTHON_LIMITED_LIBRARIES}")
+ message(STATUS "******************************************************")
+endmacro()
+
+macro(set_debug_build)
+ set(SHIBOKEN_BUILD_TYPE "Debug")
+
+ if(NOT Python_LIBRARIES)
+ message(WARNING "Python debug shared library not found; \
+ assuming python was built with shared library support disabled.")
+ endif()
+
+ if(NOT PYTHON_WITH_DEBUG)
+ message(WARNING "Compiling shiboken6 with debug enabled, \
+ but the python executable was not compiled with debug support.")
+ else()
+ set(SBK_PKG_CONFIG_PY_DEBUG_DEFINITION " -DPy_DEBUG")
+ endif()
+
+ if (PYTHON_WITH_COUNT_ALLOCS)
+ set(SBK_PKG_CONFIG_PY_DEBUG_DEFINITION "${SBK_PKG_CONFIG_PY_DEBUG_DEFINITION} -DCOUNT_ALLOCS")
+ endif()
+endmacro()
+
+macro(setup_sanitize_address)
+ # Currently this does not check that the clang / gcc version used supports Address sanitizer,
+ # so once again, use at your own risk.
+ add_compile_options("-fsanitize=address" "-g" "-fno-omit-frame-pointer")
+ # We need to add the sanitize address option to all linked executables / shared libraries
+ # so that proper sanitizer symbols are linked in.
+ #
+ # Note that when running tests, you may need to set an additional environment variable
+ # in set_tests_properties for shiboken6 / pyside tests, or exported in your shell. Address
+ # sanitizer will tell you what environment variable needs to be exported. For example:
+ # export DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/Toolchains/
+ # ./XcodeDefault.xctoolchain/usr/lib/clang/8.1.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib
+ set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_STANDARD_LIBRARIES} -fsanitize=address")
+endmacro()
+
+macro(set_cmake_cxx_flags)
+if(MSVC)
+ # Qt5: this flag has changed from /Zc:wchar_t- in Qt4.X
+ set(CMAKE_CXX_FLAGS "/Zc:wchar_t /GR /EHsc /DWIN32 /D_WINDOWS /D_SCL_SECURE_NO_WARNINGS")
+ #set(CMAKE_CXX_FLAGS "/Zc:wchar_t /GR /EHsc /DNOCOLOR /DWIN32 /D_WINDOWS /D_SCL_SECURE_NO_WARNINGS") # XXX
+else()
+ set (gcc_warnings_options "-Wall -Wextra -Wno-strict-aliasing")
+ # Clang has -Wno-bad-function-cast, but does not need it.
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ set (gcc_warnings_options "${gcc_warnings_options} -Wno-cast-function-type")
+ endif()
+ if(CMAKE_HOST_UNIX AND NOT CYGWIN)
+ add_definitions(-fPIC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${gcc_warnings_options} -fvisibility=hidden")
+ endif()
+ set(CMAKE_CXX_FLAGS_DEBUG "-g")
+ option(ENABLE_GCC_OPTIMIZATION "Enable specific GCC flags to optimization library \
+ size and performance. Only available on Release Mode" 0)
+ if(ENABLE_GCC_OPTIMIZATION)
+ set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -Os -Wl,-O1")
+ if(NOT CMAKE_HOST_APPLE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--hash-style=gnu")
+ endif()
+ endif()
+ if(CMAKE_HOST_APPLE)
+ # ALTERNATIVE_QT_INCLUDE_DIR is deprecated, because CMake takes care of finding the proper
+ # include folders using the qmake found in the environment. Only use it for now in case
+ # something goes wrong with the cmake process.
+ if(ALTERNATIVE_QT_INCLUDE_DIR AND NOT QT_INCLUDE_DIR)
+ set(QT_INCLUDE_DIR ${ALTERNATIVE_QT_INCLUDE_DIR})
+ endif()
+ endif()
+endif()
+
+endmacro()
+
+function(qfp_strip_library target)
+ # Strip unless macOS (/strip: error: symbols referenced by indirect symbol
+ # table entries that can't be stripped).
+ if (CMAKE_STRIP AND UNIX AND NOT APPLE AND NOT QFP_NO_STRIP
+ AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(post_command COMMAND ${CMAKE_STRIP} $<TARGET_FILE:${target}>)
+ add_custom_command(TARGET ${target} POST_BUILD ${post_command})
+ endif()
+
+endfunction()
+
+macro(shiboken_internal_set_python_site_packages)
+ # When cross-building, we can't run the target python executable to find out the information,
+ # so we allow an explicit variable assignment or use a default / sensible value.
+ if(SHIBOKEN_IS_CROSS_BUILD OR PYSIDE_IS_CROSS_BUILD OR QFP_FIND_NEW_PYTHON_PACKAGE)
+ # Allow manual assignment.
+ if(QFP_PYTHON_SITE_PACKAGES)
+ set(PYTHON_SITE_PACKAGES "${QFP_PYTHON_SITE_PACKAGES}")
+ else()
+ # Assumes POSIX.
+ # Convention can be checked in cpython's source code in
+ # Lib/sysconfig.py's _INSTALL_SCHEMES
+ set(__version_major_minor
+ "${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}")
+
+ set(PYTHON_SITE_PACKAGES_WITHOUT_PREFIX
+ "lib/python${__version_major_minor}/site-packages")
+ set(PYTHON_SITE_PACKAGES
+ "${CMAKE_INSTALL_PREFIX}/${PYTHON_SITE_PACKAGES_WITHOUT_PREFIX}")
+ unset(__version_major_minor)
+ endif()
+ else()
+ execute_process(
+ COMMAND ${Python_EXECUTABLE} -c "if True:
+ import sysconfig
+ from os.path import sep
+
+ # /home/qt/dev/env/lib/python3.9/site-packages
+ lib_path = sysconfig.get_path('purelib')
+
+ # /home/qt/dev/env
+ data_path = sysconfig.get_path('data')
+
+ # /lib/python3.9/site-packages
+ rel_path = lib_path.replace(data_path, '')
+
+ print(f'${CMAKE_INSTALL_PREFIX}{rel_path}'.replace(sep, '/'))
+ "
+ OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif()
+ if (NOT PYTHON_SITE_PACKAGES)
+ message(FATAL_ERROR "Could not detect Python module installation directory.")
+ elseif (APPLE)
+ message(STATUS "!!! The generated bindings will be installed on ${PYTHON_SITE_PACKAGES}, \
+ is it right!?")
+ endif()
+endmacro()
+
+macro(set_python_config_suffix)
+ if (PYTHON_LIMITED_API)
+ if(WIN32)
+ set(PYTHON_EXTENSION_SUFFIX "")
+ else()
+ set(PYTHON_EXTENSION_SUFFIX ".abi3")
+ endif()
+ set(PYTHON_CONFIG_SUFFIX ".abi3")
+ else()
+ set(PYTHON_CONFIG_SUFFIX "${PYTHON_EXTENSION_SUFFIX}")
+ endif()
+endmacro()
+
+macro(setup_clang)
+ # Find libclang using the environment variables LLVM_INSTALL_DIR,
+ # CLANG_INSTALL_DIR using standard cmake.
+ # Use CLANG_INCLUDE_DIRS and link to libclang.
+ if(DEFINED ENV{LLVM_INSTALL_DIR})
+ list(PREPEND CMAKE_PREFIX_PATH "$ENV{LLVM_INSTALL_DIR}")
+ list(PREPEND CMAKE_FIND_ROOT_PATH "$ENV{LLVM_INSTALL_DIR}")
+ elseif(DEFINED ENV{CLANG_INSTALL_DIR})
+ list(PREPEND CMAKE_PREFIX_PATH "$ENV{CLANG_INSTALL_DIR}")
+ list(PREPEND CMAKE_FIND_ROOT_PATH "$ENV{CLANG_INSTALL_DIR}")
+ endif()
+
+ find_package(Clang CONFIG REQUIRED)
+ # Need to explicitly handle the version check, because the Clang package doesn't.
+ if (LLVM_PACKAGE_VERSION AND LLVM_PACKAGE_VERSION VERSION_LESS "9.0")
+ message(FATAL_ERROR "You need LLVM version 9.0 or greater to build.")
+ endif()
+
+ # CLANG_LIBRARY is read out from the cmake cache to deploy libclang
+ get_target_property(CLANG_BUILD_TYPE libclang IMPORTED_CONFIGURATIONS)
+ get_target_property(CLANG_LIBRARY_NAME libclang IMPORTED_LOCATION_${CLANG_BUILD_TYPE})
+ set(CLANG_LIBRARY "${CLANG_LIBRARY_NAME}" CACHE FILEPATH "libclang")
+ message(STATUS "CLANG: ${Clang_DIR}, ${CLANG_LIBRARY} detected")
+endmacro()
+
+macro(set_quiet_build)
+ # Don't display "up-to-date / install" messages when installing, to reduce visual clutter.
+ set(CMAKE_INSTALL_MESSAGE NEVER)
+ # Override message not to display info messages when doing a quiet build.
+ function(message)
+ list(GET ARGV 0 MessageType)
+ if (MessageType STREQUAL FATAL_ERROR OR
+ MessageType STREQUAL SEND_ERROR OR
+ MessageType STREQUAL WARNING OR
+ MessageType STREQUAL AUTHOR_WARNING)
+ list(REMOVE_AT ARGV 0)
+ _message(${MessageType} "${ARGV}")
+ endif()
+ endfunction()
+endmacro()
+
+macro(get_python_extension_suffix)
+ # When cross-building, we can't run the target python executable to find out the information,
+ # so we rely on Python_SOABI being set by find_package(Python).
+ # Python_SOABI is only set by CMake 3.17+
+ # TODO: Lower this to CMake 3.16 if possible.
+ if(SHIBOKEN_IS_CROSS_BUILD)
+ if(NOT Python_SOABI)
+ message(FATAL_ERROR "Python_SOABI variable is empty.")
+ endif()
+ set(PYTHON_EXTENSION_SUFFIX ".${Python_SOABI}")
+ else()
+ # See PYSIDE-1841 / https://bugs.python.org/issue39825 for distutils vs sysconfig
+ execute_process(
+ COMMAND ${Python_EXECUTABLE} -c "if True:
+ import sys
+ if sys.version_info >= (3, 8, 2):
+ import sysconfig
+ suffix = sysconfig.get_config_var('EXT_SUFFIX')
+ else:
+ from distutils import sysconfig
+ suffix = sysconfig.get_config_var('EXT_SUFFIX')
+ pos = suffix.rfind('.')
+ if pos > 0:
+ print(suffix[:pos])
+ else:
+ print(f'Unable to determine PYTHON_EXTENSION_SUFFIX from EXT_SUFFIX: \"{suffix}\"',
+ file=sys.stderr)
+ "
+ OUTPUT_VARIABLE PYTHON_EXTENSION_SUFFIX
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif()
+ message(STATUS "PYTHON_EXTENSION_SUFFIX: " ${PYTHON_EXTENSION_SUFFIX})
+endmacro()
+
+macro(shiboken_parse_all_arguments prefix type flags options multiopts)
+ cmake_parse_arguments(${prefix} "${flags}" "${options}" "${multiopts}" ${ARGN})
+ if(DEFINED ${prefix}_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown arguments were passed to ${type} (${${prefix}_UNPARSED_ARGUMENTS}).")
+ endif()
+endmacro()
+
+macro(shiboken_check_if_limited_api)
+ # TODO: Figure out how to use limited API libs when cross-building to Windows, if that's ever
+ # needed. Perhaps use host python to walk the libs of the target python installation.
+
+ if(NOT SHIBOKEN_IS_CROSS_BUILD AND WIN32)
+ # On Windows, PYTHON_LIBRARIES can be a list. Example:
+ # optimized;C:/Python36/libs/python36.lib;debug;C:/Python36/libs/python36_d.lib
+ # On other platforms, this result is not used at all.
+ execute_process(
+ COMMAND ${Python_EXECUTABLE} -c "if True:
+ from pathlib import Path
+ libs = r'${Python_LIBRARIES}'
+ libs = libs.split(';')
+ for lib in libs:
+ if ('\\\\' in lib or '/' in lib) and Path(lib).is_file():
+ lib = Path(lib)
+ prefix = lib.parent
+ py = lib.name
+ if py.startswith('python3'):
+ print(prefix / 'python3.lib')
+ break
+ "
+ OUTPUT_VARIABLE PYTHON_LIMITED_LIBRARIES
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif()
+
+ message(STATUS "PYTHON_LIMITED_LIBRARIES: " ${PYTHON_LIMITED_LIBRARIES})
+
+ if(FORCE_LIMITED_API OR SHIBOKEN_PYTHON_LIMITED_API)
+ set(PYTHON_LIMITED_API 1)
+ if(WIN32)
+ set(SHIBOKEN_PYTHON_LIBRARIES ${PYTHON_LIMITED_LIBRARIES})
+ endif()
+ endif()
+endmacro()
+
+
+macro(shiboken_find_required_python)
+ set(_shiboken_find_python_version_args "")
+ if(${ARGC} GREATER 0)
+ list(APPEND _shiboken_find_python_version_args "${ARGV0}")
+ endif()
+ # This function can also be called by consumers of ShibokenConfig.cmake package like pyside,
+ # that's why we also check for PYSIDE_IS_CROSS_BUILD (which is set by pyside project)
+ # and QFP_FIND_NEW_PYTHON_PACKAGE for an explicit opt in.
+ #
+ # We have to use FindPython package instead of FindPythonInterp to get required target Python
+ # information.
+ if(SHIBOKEN_IS_CROSS_BUILD OR PYSIDE_IS_CROSS_BUILD OR QFP_FIND_NEW_PYTHON_PACKAGE)
+ # We want FindPython to look in the sysroot for the python-config executable,
+ # but toolchain files might set CMAKE_FIND_ROOT_PATH_MODE_PROGRAM to NEVER because
+ # programs are mostly found for running and you usually can't run a target executable on
+ # a host platform. python-config can likely be ran though, because it's a shell script
+ # to be run on a host Linux.
+ set(_shiboken_backup_CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
+ "${CMAKE_FIND_ROOT_PATH_MODE_PROGRAM}")
+ set(_shiboken_backup_CMAKE_FIND_ROOT_PATH
+ "${CMAKE_FIND_ROOT_PATH}")
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+ if(Python_ROOT_DIR)
+ list(PREPEND CMAKE_FIND_ROOT_PATH "${Python_ROOT_DIR}")
+ endif()
+
+ # We can't look for the Python interpreter because FindPython tries to execute it, which
+ # usually won't work on a host platform due to different architectures / platforms.
+ # Thus we only look for the Python include and lib directories which are part of the
+ # Development component.
+ find_package(
+ Python
+ ${_shiboken_find_python_version_args}
+ REQUIRED
+ COMPONENTS Development
+ )
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
+ "${_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
+ ${_shiboken_find_python_version_args}
+ REQUIRED
+ COMPONENTS Interpreter Development
+ )
+ endif()
+
+ shiboken_validate_python_version()
+
+ set(SHIBOKEN_PYTHON_INTERPRETER "${Python_EXECUTABLE}")
+ set_property(GLOBAL PROPERTY SHIBOKEN_PYTHON_INTERPRETER "${Python_EXECUTABLE}")
+endmacro()
+
+macro(shiboken_validate_python_version)
+ if(Python_VERSION_MAJOR EQUAL "3" AND Python_VERSION_MINOR LESS "7")
+ message(FATAL_ERROR
+ "Shiboken requires Python 3.7+.")
+ endif()
+endmacro()
+
+macro(shiboken_compute_python_includes)
+ shiboken_parse_all_arguments(
+ "SHIBOKEN_COMPUTE_INCLUDES" "shiboken_compute_python_includes"
+ "IS_CALLED_FROM_EXPORT" "" "" ${ARGN})
+
+
+ # If the installed shiboken config file is used,
+ # append the found Python include dirs as an interface property on the libshiboken target.
+ # This needs to be dynamic because the user of the library might have python installed
+ # in a different path than when shiboken was originally built.
+ # Otherwise if shiboken is currently being built itself (either as standalone, or super project
+ # build) append the include dirs as PUBLIC.
+ if (SHIBOKEN_COMPUTE_INCLUDES_IS_CALLED_FROM_EXPORT)
+ #TODO target_include_directories works on imported targets only starting with v3.11.0.
+ set_property(TARGET Shiboken6::libshiboken
+ APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Python_INCLUDE_DIRS})
+ else()
+ target_include_directories(libshiboken
+ PUBLIC $<BUILD_INTERFACE:${Python_INCLUDE_DIRS}>)
+ endif()
+
+
+ set(SHIBOKEN_PYTHON_INCLUDE_DIRS "${Python_INCLUDE_DIRS}")
+
+ set_property(GLOBAL PROPERTY shiboken_python_include_dirs "${SHIBOKEN_PYTHON_INCLUDE_DIRS}")
+
+ message(STATUS
+ "SHIBOKEN_PYTHON_INCLUDE_DIRS computed to value: '${SHIBOKEN_PYTHON_INCLUDE_DIRS}'")
+endmacro()
+
+# Given a list of the following form:
+# optimized;C:/Python36/libs/python36.lib;debug;C:/Python36/libs/python36_d.lib
+# choose the corresponding library to use, based on the current configuration type.
+function(shiboken_get_library_for_current_config library_list current_config out_var)
+ list(FIND library_list "optimized" optimized_found)
+ list(FIND library_list "general" general_found)
+ list(FIND library_list "debug" debug_found)
+
+ if (optimized_found OR general_found OR debug_found)
+ # Iterate over library list to find the most appropriate library.
+ foreach(token ${library_list})
+ if(token STREQUAL "optimized" OR token STREQUAL "general")
+ set(is_debug 0)
+ set(token1 1)
+ set(lib "")
+ elseif(token STREQUAL "debug")
+ set(is_debug 1)
+ set(token1 1)
+ set(lib "")
+ elseif(EXISTS ${token})
+ set(lib ${token})
+ set(token2 1)
+ else()
+ set(token1 0)
+ set(token2 0)
+ set(lib "")
+ endif()
+
+ if(token1 AND token2)
+ if((is_debug AND lib AND current_config STREQUAL "Debug")
+ OR (NOT is_debug AND lib AND (NOT current_config STREQUAL "Debug")))
+ set(${out_var} ${lib} PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+ endforeach()
+ else()
+ # No configuration specific libraries found, just set the original value.
+ set(${out_var} "${library_list}" PARENT_SCOPE)
+ endif()
+
+endfunction()
+
+macro(shiboken_compute_python_libraries)
+ shiboken_parse_all_arguments(
+ "SHIBOKEN_COMPUTE_LIBS" "shiboken_compute_python_libraries"
+ "IS_CALLED_FROM_EXPORT" "" "" ${ARGN})
+
+ if (NOT SHIBOKEN_PYTHON_LIBRARIES)
+ set(SHIBOKEN_PYTHON_LIBRARIES "")
+ endif()
+
+ if(WIN32 AND NOT SHIBOKEN_PYTHON_LIBRARIES)
+ set(SHIBOKEN_PYTHON_LIBRARIES ${Python_LIBRARIES})
+ endif()
+
+ # If the resulting variable
+ # contains a "debug;X;optimized;Y" list like described in shiboken_check_if_limited_api,
+ # make sure to pick just one, so that the final generator expressions are valid.
+ shiboken_get_library_for_current_config("${SHIBOKEN_PYTHON_LIBRARIES}" "${CMAKE_BUILD_TYPE}" "SHIBOKEN_PYTHON_LIBRARIES")
+
+ if(APPLE)
+ set(SHIBOKEN_PYTHON_LIBRARIES "-undefined dynamic_lookup")
+ endif()
+
+ # If the installed shiboken config file is used,
+ # append the computed Python libraries as an interface property on the libshiboken target.
+ # This needs to be dynamic because the user of the library might have python installed
+ # in a different path than when shiboken was originally built.
+ # Otherwise if shiboken is currently being built itself (either as standalone, or super project
+ # build) append the libraries as PUBLIC.
+ if (SHIBOKEN_COMPUTE_LIBS_IS_CALLED_FROM_EXPORT)
+ #TODO target_link_libraries works on imported targets only starting with v3.11.0.
+ set_property(TARGET Shiboken6::libshiboken
+ APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${SHIBOKEN_PYTHON_LIBRARIES})
+ else()
+ target_link_libraries(libshiboken
+ PUBLIC $<BUILD_INTERFACE:${SHIBOKEN_PYTHON_LIBRARIES}>)
+ endif()
+
+ set_property(GLOBAL PROPERTY shiboken_python_libraries "${SHIBOKEN_PYTHON_LIBRARIES}")
+
+ message(STATUS "SHIBOKEN_PYTHON_LIBRARIES computed to value: '${SHIBOKEN_PYTHON_LIBRARIES}'")
+endmacro()
+
+function(shiboken_check_if_built_and_target_python_are_compatible)
+ if(NOT SHIBOKEN_PYTHON_VERSION_MAJOR STREQUAL Python_VERSION_MAJOR)
+ message(FATAL_ERROR "The detected Python major version is not \
+compatible with the Python major version which was used when Shiboken was built.
+Built with: '${SHIBOKEN_PYTHON_VERSION_MAJOR}.${SHIBOKEN_PYTHON_VERSION_MINOR}' \
+Detected: '${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}'")
+ else()
+ if(NOT SHIBOKEN_PYTHON_LIMITED_API
+ AND NOT SHIBOKEN_PYTHON_VERSION_MINOR STREQUAL Python_VERSION_MINOR)
+ message(FATAL_ERROR
+ "The detected Python minor version is not compatible with the Python minor \
+version which was used when Shiboken was built. Consider building shiboken with \
+FORCE_LIMITED_API set to '1', so that only the Python major version matters.
+Built with: '${SHIBOKEN_PYTHON_VERSION_MAJOR}.${SHIBOKEN_PYTHON_VERSION_MINOR}' \
+Detected: '${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}'")
+ endif()
+ endif()
+endfunction()
+
+function(shiboken_internal_disable_pkg_config)
+ # Disable pkg-config by setting an empty executable path. There's no documented way to
+ # mark the package as not found, but we can force all pkg_check_modules calls to do nothing
+ # by setting the variable to an empty value.
+ set(PKG_CONFIG_EXECUTABLE "" CACHE STRING "Disabled pkg-config usage." FORCE)
+endfunction()
+
+function(shiboken_internal_disable_pkg_config_if_needed)
+ if(SHIBOKEN_SKIP_PKG_CONFIG_ADJUSTMENT)
+ return()
+ endif()
+
+ # pkg-config should not be used by default on Darwin platforms.
+ if(APPLE)
+ set(pkg_config_enabled OFF)
+ else()
+ set(pkg_config_enabled ON)
+ endif()
+
+ if(NOT pkg_config_enabled)
+ shiboken_internal_disable_pkg_config()
+ endif()
+endfunction()
+
+function(shiboken_internal_detect_if_cross_building)
+ if(CMAKE_CROSSCOMPILING OR QFP_SHIBOKEN_HOST_PATH)
+ set(is_cross_build TRUE)
+ else()
+ set(is_cross_build FALSE)
+ endif()
+ set(SHIBOKEN_IS_CROSS_BUILD "${is_cross_build}" PARENT_SCOPE)
+ message(STATUS "SHIBOKEN_IS_CROSS_BUILD: ${is_cross_build}")
+endfunction()
+
+function(shiboken_internal_decide_parts_to_build)
+ set(build_libs_default ON)
+ option(SHIBOKEN_BUILD_LIBS "Build shiboken libraries" ${build_libs_default})
+ message(STATUS "SHIBOKEN_BUILD_LIBS: ${SHIBOKEN_BUILD_LIBS}")
+
+ if(SHIBOKEN_IS_CROSS_BUILD)
+ set(build_tools_default OFF)
+ else()
+ set(build_tools_default ON)
+ endif()
+ option(SHIBOKEN_BUILD_TOOLS "Build shiboken tools" ${build_tools_default})
+ message(STATUS "SHIBOKEN_BUILD_TOOLS: ${SHIBOKEN_BUILD_TOOLS}")
+
+ if(SHIBOKEN_IS_CROSS_BUILD)
+ set(_shiboken_build_tests_default OFF)
+ elseif(SHIBOKEN_BUILD_LIBS)
+ set(_shiboken_build_tests_default ON)
+ endif()
+ option(BUILD_TESTS "Build tests." ${_shiboken_build_tests_default})
+ message(STATUS "BUILD_TESTS: ${BUILD_TESTS}")
+endfunction()
+
+function(shiboken_internal_find_host_shiboken_tools)
+ if(SHIBOKEN_IS_CROSS_BUILD)
+ set(find_package_extra_args)
+ if(QFP_SHIBOKEN_HOST_PATH)
+ list(APPEND find_package_extra_args PATHS "${QFP_SHIBOKEN_HOST_PATH}/lib/cmake")
+ list(PREPEND CMAKE_FIND_ROOT_PATH "${QFP_SHIBOKEN_HOST_PATH}")
+ endif()
+ find_package(
+ Shiboken6Tools 6 CONFIG
+ ${find_package_extra_args}
+ )
+
+ if(NOT Shiboken6Tools_DIR)
+ message(FATAL_ERROR
+ "Shiboken6Tools package was not found. "
+ "Please set QFP_SHIBOKEN_HOST_PATH to the location where the Shiboken6Tools CMake "
+ "package is installed.")
+ endif()
+ endif()
+endfunction()
+
+function(shiboken_internal_set_up_extra_dependency_paths)
+ set(extra_root_path_vars
+ QFP_QT_TARGET_PATH
+ QFP_PYTHON_TARGET_PATH
+ )
+ foreach(root_path IN LISTS extra_root_path_vars)
+ set(new_root_path_value "${${root_path}}")
+ if(new_root_path_value)
+ set(new_prefix_path "${CMAKE_PREFIX_PATH}")
+ list(PREPEND new_prefix_path "${new_root_path_value}/lib/cmake")
+ set(CMAKE_PREFIX_PATH "${new_prefix_path}")
+ set(CMAKE_PREFIX_PATH "${new_prefix_path}" PARENT_SCOPE)
+
+ # Need to adjust the prefix and root paths so that find_package(Qt) and other 3rd
+ # party packages are found successfully when they are located outside of the
+ # default sysroot (whatever that maybe for the target platform).
+ if(SHIBOKEN_IS_CROSS_BUILD)
+ set(new_root_path "${CMAKE_FIND_ROOT_PATH}")
+ list(PREPEND new_root_path "${new_root_path_value}")
+ set(CMAKE_FIND_ROOT_PATH "${new_root_path}")
+ set(CMAKE_FIND_ROOT_PATH "${new_root_path}" PARENT_SCOPE)
+ endif()
+ endif()
+ endforeach()
+endfunction()
+
+macro(compute_config_py_values
+ full_version_var_name
+ )
+ set(QT_MACOS_DEPLOYMENT_TARGET "")
+ if (Qt${QT_MAJOR_VERSION}Core_FOUND)
+ get_target_property(darwin_target Qt6::Core QT_DARWIN_MIN_DEPLOYMENT_TARGET)
+ if(darwin_target)
+ set(QT_MACOS_DEPLOYMENT_TARGET
+ "__qt_macos_min_deployment_target__ = '${darwin_target}'")
+ endif()
+ elseif(APPLE)
+ message(FATAL_ERROR "Qt6::Core should be found before calling this macro")
+ endif()
+
+ string(TIMESTAMP PACKAGE_BUILD_DATE "%Y-%m-%dT%H:%M:%S+00:00" UTC)
+ if (PACKAGE_BUILD_DATE)
+ set(PACKAGE_BUILD_DATE "__build_date__ = '${PACKAGE_BUILD_DATE}'")
+ endif()
+
+ if (PACKAGE_SETUP_PY_PACKAGE_VERSION)
+ set(PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT "__setup_py_package_version__ = '${PACKAGE_SETUP_PY_PACKAGE_VERSION}'")
+ set(FINAL_PACKAGE_VERSION ${PACKAGE_SETUP_PY_PACKAGE_VERSION})
+ else()
+ set(FINAL_PACKAGE_VERSION ${${full_version_var_name}})
+ endif()
+
+ if (PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP)
+ set(PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT "__setup_py_package_timestamp__ = '${PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP}'")
+ else()
+ set(PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT "")
+ endif()
+
+ find_package(Git)
+ if(GIT_FOUND)
+ # Check if current source folder is inside a git repo, so that commit information can be
+ # queried.
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-parse --git-dir
+ OUTPUT_VARIABLE PACKAGE_SOURCE_IS_INSIDE_REPO
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(PACKAGE_SOURCE_IS_INSIDE_REPO)
+ # Force git dates to be UTC-based.
+ set(ENV{TZ} UTC)
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} --no-pager show --date=format-local:%Y-%m-%dT%H:%M:%S+00:00 -s --format=%cd HEAD
+ OUTPUT_VARIABLE PACKAGE_BUILD_COMMIT_DATE
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(PACKAGE_BUILD_COMMIT_DATE)
+ set(PACKAGE_BUILD_COMMIT_DATE "__build_commit_date__ = '${PACKAGE_BUILD_COMMIT_DATE}'")
+ endif()
+ unset(ENV{TZ})
+
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
+ OUTPUT_VARIABLE PACKAGE_BUILD_COMMIT_HASH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(PACKAGE_BUILD_COMMIT_HASH)
+ set(PACKAGE_BUILD_COMMIT_HASH "__build_commit_hash__ = '${PACKAGE_BUILD_COMMIT_HASH}'")
+ endif()
+
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} describe HEAD
+ OUTPUT_VARIABLE PACKAGE_BUILD_COMMIT_HASH_DESCRIBED
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(PACKAGE_BUILD_COMMIT_HASH_DESCRIBED)
+ set(PACKAGE_BUILD_COMMIT_HASH_DESCRIBED "__build_commit_hash_described__ = '${PACKAGE_BUILD_COMMIT_HASH_DESCRIBED}'")
+ endif()
+
+ endif()
+ endif()
+
+endmacro()
+
+# Creates a new target called "${library_name}_generator" which
+# depends on the mjb_rejected_classes.log file generated by shiboken.
+# This target is added as a dependency to ${library_name} target.
+# This file's timestamp informs cmake when the last generation was
+# done, without force-updating the timestamps of the generated class
+# cpp files.
+# In practical terms this means that changing some injection code in
+# an xml file that modifies only one specific class cpp file, will
+# not force rebuilding all the cpp files, and thus allow for better
+# incremental builds.
+macro(create_generator_target library_name)
+ add_custom_target(${library_name}_generator DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log")
+ add_dependencies(${library_name} ${library_name}_generator)
+endmacro()
+
+# Generate a shell script wrapper that sets environment variables for executing a specific tool.
+#
+# tool_name should be a unique tool name, preferably without spaces.
+# Returns the wrapper path in path_out_var.
+#
+# Currently adds the Qt lib dir and libclang to PATH / LD_LIBRARY_PATH / DYLD_LIBRARY_PATH.
+# Meant to be used as the first argument to add_custom_command's COMMAND option.
+# TODO: Remove tool_name as the tool_name for this function is always shiboken.
+function(shiboken_get_tool_shell_wrapper tool_name path_out_var)
+ # Generate the wrapper only once during the execution of CMake.
+ get_property(is_called GLOBAL PROPERTY "_shiboken_tool_wrapper_${tool_name}_created")
+
+ if(is_called)
+ get_property(wrapper_path GLOBAL PROPERTY "_shiboken_tool_wrapper_${tool_name}_path")
+ set(${path_out_var} "${wrapper_path}" PARENT_SCOPE)
+ return()
+ endif()
+
+ set(path_dirs "")
+ set(path_dirs_native "")
+
+ if(CMAKE_HOST_WIN32)
+ set(wrapper_script_extension ".bat")
+ else()
+ set(wrapper_script_extension ".sh")
+ endif()
+
+ # Try to get original host shiboken paths from exported target properties.
+ shiboken_get_host_tool_wrapper_properties(orig_qt_library_dir_absolute orig_libclang_lib_dir)
+
+ # Get path to the Qt bin/lib dir depending on the platform and developer input.
+ # Prefer values given on the command line, then the original host path if it exists, otherwise
+ # try to use the Qt install prefix and libclang env vars.
+ #
+ # Note that in a cross-compiling case, using the Qt install prefix is very likely
+ # wrong, because you want to use the location of the host Qt, not the target Qt. Same for
+ # libclang. Unfortunately we currently don't provide a host Qt and host libclang option via
+ # setup.py, so the manual cmake vars will have to suffice.
+ if(SHIBOKEN_WRAPPER_HOST_QT_LIB_PATH AND EXISTS "${SHIBOKEN_WRAPPER_HOST_QT_LIB_PATH}")
+ set(qt_library_dir_absolute "${SHIBOKEN_WRAPPER_HOST_QT_LIB_PATH}")
+ elseif(orig_qt_library_dir_absolute AND EXISTS "${orig_qt_library_dir_absolute}")
+ set(qt_library_dir_absolute "${orig_qt_library_dir_absolute}")
+ elseif(CMAKE_HOST_WIN32)
+ # in Windows the Qt dll are store `bin` in directory
+ set(qt_library_dir ${QT6_INSTALL_BINS})
+ else()
+ # in Unix the .so are stored in `lib` directory
+ set(qt_library_dir ${QT6_INSTALL_LIBS})
+ endif()
+
+ # Assert that Qt is already found.
+ if((QT6_INSTALL_PREFIX AND qt_library_dir) OR orig_qt_library_dir_absolute)
+ else()
+ message(FATAL_ERROR "Qt should have been found already by now.")
+ endif()
+
+ if(NOT qt_library_dir_absolute)
+ set(qt_library_dir_absolute "${QT6_INSTALL_PREFIX}/${qt_library_dir}")
+ endif()
+ list(APPEND path_dirs "${qt_library_dir_absolute}")
+
+ # Get libclang lib dir path.
+ # Prefer values given on the command line, then the original host path if it exists.
+ if(SHIBOKEN_WRAPPER_HOST_CLANG_LIB_PATH AND EXISTS "${SHIBOKEN_WRAPPER_HOST_CLANG_LIB_PATH}")
+ set(libclang_lib_dir "${SHIBOKEN_WRAPPER_HOST_CLANG_LIB_PATH}")
+ elseif(orig_libclang_lib_dir AND EXISTS "${orig_libclang_lib_dir}")
+ set(libclang_lib_dir "${orig_libclang_lib_dir}")
+ else()
+ # find libclang
+ find_libclang()
+ endif()
+
+ if(libclang_lib_dir)
+ list(APPEND path_dirs "${libclang_lib_dir}")
+ endif()
+
+ # Convert the paths from unix-style to native Windows style.
+ foreach(path_dir IN LISTS path_dirs)
+ if(EXISTS "${path_dir}")
+ file(TO_NATIVE_PATH "${path_dir}" path_dir_native)
+ list(APPEND path_dirs_native "${path_dir_native}")
+ endif()
+ endforeach()
+
+ set(wrapper_dir "${CMAKE_BINARY_DIR}/.qfp/bin")
+ file(MAKE_DIRECTORY "${wrapper_dir}")
+ set(wrapper_path "${wrapper_dir}/${tool_name}_wrapper${wrapper_script_extension}")
+
+ if(CMAKE_HOST_WIN32)
+ file(WRITE "${wrapper_path}" "@echo off
+set PATH=${path_dirs_native};%PATH%
+%*")
+ elseif(CMAKE_HOST_APPLE)
+ string(REPLACE ";" ":" path_dirs_native "${path_dirs_native}")
+ file(WRITE "${wrapper_path}" "#!/bin/bash
+export DYLD_LIBRARY_PATH=${path_dirs_native}:$DYLD_LIBRARY_PATH
+export DYLD_FRAMEWORK_PATH=${path_dirs_native}:$DYLD_FRAMEWORK_PATH
+$@")
+ else()
+ string(REPLACE ";" ":" path_dirs_native "${path_dirs_native}")
+ file(WRITE "${wrapper_path}" "#!/bin/bash
+export LD_LIBRARY_PATH=${path_dirs_native}:$LD_LIBRARY_PATH
+$@")
+ endif()
+
+ # Remember the creation of the file for a specific tool.
+ set_property(GLOBAL PROPERTY "_shiboken_tool_wrapper_${tool_name}_path" "${wrapper_path}")
+ set_property(GLOBAL PROPERTY "_shiboken_tool_wrapper_${tool_name}_created" TRUE)
+
+ # Save original host paths for future cross-builds.
+ shiboken_save_host_tool_wrapper_properties("${qt_library_dir_absolute}" "${libclang_lib_dir}")
+
+ # give execute permission to run the file
+ if(CMAKE_HOST_UNIX)
+ execute_process(COMMAND chmod +x ${wrapper_path})
+ endif()
+
+ set(${path_out_var} "${wrapper_path}" PARENT_SCOPE)
+endfunction()
+
+# Retrieve the original host shiboken runtime dependency paths from the installed (namespaced)
+# shiboken generator target.
+function(shiboken_get_host_tool_wrapper_properties out_qt_library_dir out_libclang_lib_dir)
+ if(TARGET Shiboken6::shiboken6)
+ get_target_property(qt_library_dir Shiboken6::shiboken6 _shiboken_original_qt_lib_dir)
+ if(NOT qt_library_dir)
+ set(qt_library_dir "")
+ endif()
+ get_target_property(libclang_lib_dir Shiboken6::shiboken6
+ _shiboken_original_libclang_lib_dir)
+ if(NOT libclang_lib_dir)
+ set(libclang_lib_dir "")
+ endif()
+ endif()
+
+ set(${out_qt_library_dir} "${qt_library_dir}" PARENT_SCOPE)
+ set(${out_libclang_lib_dir} "${libclang_lib_dir}" PARENT_SCOPE)
+endfunction()
+
+# Save original host shiboken runtime dependency paths as target properties, so they can be used
+# when generating the wrapper file for cross-builds.
+# Should only be done when shiboken is being built (aka it's a non-imported target).
+function(shiboken_save_host_tool_wrapper_properties qt_library_dir libclang_lib_dir)
+ if(TARGET shiboken6)
+ get_target_property(is_imported shiboken6 IMPORTED)
+ if(is_imported)
+ return()
+ endif()
+
+ set_target_properties(shiboken6 PROPERTIES
+ _shiboken_original_qt_lib_dir "${qt_library_dir}")
+ set_property(TARGET shiboken6 APPEND PROPERTY
+ EXPORT_PROPERTIES _shiboken_original_qt_lib_dir)
+ if(libclang_lib_dir)
+ set_target_properties(shiboken6 PROPERTIES
+ _shiboken_original_libclang_lib_dir "${libclang_lib_dir}")
+ set_property(TARGET shiboken6 APPEND PROPERTY
+ EXPORT_PROPERTIES _shiboken_original_libclang_lib_dir)
+ endif()
+ endif()
+endfunction()
+
+# Returns the platform-specific relative rpath base token, if it's supported.
+# If it's not supported, returns the string NO_KNOWN_RPATH_REL_BASE.
+function(get_rpath_base_token out_var)
+ if(APPLE)
+ set(rpath_rel_base "@loader_path")
+ elseif(UNIX)
+ set(rpath_rel_base "$ORIGIN")
+ else()
+ #has no effect on Windows
+ set(rpath_rel_base "NO_KNOWN_RPATH_REL_BASE")
+ endif()
+ set(${out_var} "${rpath_rel_base}" PARENT_SCOPE)
+endfunction()
+
+# Get path to libclang.dll/libclang.so depending on the platform
+macro(find_libclang)
+ if(CMAKE_HOST_WIN32)
+ set(libclang_directory_suffix "bin")
+ set(libclang_suffix ".dll")
+ else()
+ set(libclang_directory_suffix "lib")
+ if(CMAKE_HOST_APPLE)
+ set(libclang_suffix ".dylib")
+ else()
+ set(libclang_suffix ".so")
+ endif()
+ endif()
+
+ set(libclang_lib_dir "")
+ if(DEFINED ENV{LLVM_INSTALL_DIR})
+ set(libclang_lib_dir "$ENV{LLVM_INSTALL_DIR}/${libclang_directory_suffix}")
+ elseif(DEFINED ENV{CLANG_INSTALL_DIR})
+ set(libclang_lib_dir "$ENV{CLANG_INSTALL_DIR}/${libclang_directory_suffix}")
+ else()
+ message(WARNING
+ "Couldn't find libclang${libclang_suffix} "
+ "You will likely need to add it manually to PATH to ensure the build succeeds.")
+ endif()
+endmacro()
+
+# Allow setting a shiboken debug level from the the build system or from the environment
+# to all shiboken invocations.
+function(shiboken_get_debug_level out_var)
+ set(debug_level "")
+ if(SHIBOKEN_DEBUG_LEVEL)
+ set(debug_level "--debug-level=${SHIBOKEN_DEBUG_LEVEL}")
+ elseif(DEFINED $ENV{SHIBOKEN_DEBUG_LEVEL})
+ set(debug_level "--debug-level=$ENV{SHIBOKEN_DEBUG_LEVEL}")
+ endif()
+ set(${out_var} "${debug_level}" PARENT_SCOPE)
+endfunction()
diff --git a/sources/shiboken6/cmake/ShibokenSetup.cmake b/sources/shiboken6/cmake/ShibokenSetup.cmake
new file mode 100644
index 000000000..32823d9fa
--- /dev/null
+++ b/sources/shiboken6/cmake/ShibokenSetup.cmake
@@ -0,0 +1,192 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(CheckIncludeFileCXX)
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
+
+include(ShibokenHelpers)
+
+option(DISABLE_DOCSTRINGS "Disable documentation extraction." FALSE)
+
+shiboken_internal_disable_pkg_config_if_needed()
+shiboken_internal_detect_if_cross_building()
+
+# Note: For cross building, we rely on FindPython shipped with CMake 3.17+ to
+# provide the value of Python_SOABI.
+
+shiboken_internal_decide_parts_to_build()
+shiboken_internal_find_host_shiboken_tools()
+shiboken_internal_set_up_extra_dependency_paths()
+
+set(QT_MAJOR_VERSION 6)
+message(STATUS "Using Qt ${QT_MAJOR_VERSION}")
+find_package(Qt6 REQUIRED COMPONENTS Core)
+
+if(QUIET_BUILD)
+ set_quiet_build()
+endif()
+
+if(USE_PYTHON_VERSION)
+ shiboken_find_required_python(${USE_PYTHON_VERSION})
+else()
+ shiboken_find_required_python()
+endif()
+
+if(SHIBOKEN_BUILD_TOOLS)
+ setup_clang()
+endif()
+
+set(shiboken6_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}")
+set(shiboken6_library_so_version "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}")
+
+compute_config_py_values(shiboken6_VERSION)
+
+## For debugging the PYTHON* variables
+message(STATUS "Python_Development_FOUND: " ${Python_Development_FOUND})
+message(STATUS "Python_LIBRARIES: " ${Python_LIBRARIES})
+message(STATUS "Python_INCLUDE_DIRS: " ${Python_INCLUDE_DIRS})
+message(STATUS "Python_Interpreter_FOUND: " ${Python_Interpreter_FOUND})
+message(STATUS "Python_EXECUTABLE: " ${Python_EXECUTABLE})
+message(STATUS "Python_VERSION: " ${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}.${Python_VERSION_PATCH})
+
+if(NOT PYTHON_EXTENSION_SUFFIX)
+ get_python_extension_suffix()
+endif()
+
+option(FORCE_LIMITED_API "Enable the limited API." "yes")
+set(PYTHON_LIMITED_API 0)
+
+shiboken_check_if_limited_api()
+
+if(PYTHON_LIMITED_API)
+ set_limited_api()
+endif()
+
+if(NOT PYTHON_CONFIG_SUFFIX)
+ set_python_config_suffix()
+endif()
+
+set(PYTHON_SHARED_LIBRARY_SUFFIX "${PYTHON_CONFIG_SUFFIX}")
+
+if(NOT PYTHON_CONFIG_SUFFIX)
+ message(FATAL_ERROR
+ "PYTHON_CONFIG_SUFFIX is empty. It should never be empty. Please file a bug report.")
+endif()
+
+message(STATUS "PYTHON_EXTENSION_SUFFIX: ${PYTHON_EXTENSION_SUFFIX}")
+message(STATUS "PYTHON_CONFIG_SUFFIX: ${PYTHON_CONFIG_SUFFIX}")
+message(STATUS "PYTHON_SHARED_LIBRARY_SUFFIX: ${PYTHON_SHARED_LIBRARY_SUFFIX}")
+
+
+if(NOT PYTHON_SITE_PACKAGES)
+ shiboken_internal_set_python_site_packages()
+endif()
+
+set_cmake_cxx_flags()
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D QT_NO_CAST_FROM_ASCII -D QT_NO_CAST_TO_ASCII")
+
+# Force usage of the C++17 standard
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" )
+set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install \
+ prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE)
+set(BIN_INSTALL_DIR "bin" CACHE PATH "The subdirectory relative to the install prefix where \
+ dlls will be installed (default is /bin)" FORCE)
+
+if(WIN32)
+ set(PATH_SEP "\;")
+else()
+ set(PATH_SEP ":")
+endif()
+
+if(CMAKE_HOST_APPLE)
+ set(OSX_USE_LIBCPP "OFF" CACHE BOOL "Explicitly link the libc++ standard library \
+ (useful for macOS deployment targets lower than 10.9.")
+ if(OSX_USE_LIBCPP)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ endif()
+endif()
+
+# Build with Address sanitizer enabled if requested.
+# This may break things, so use at your own risk.
+if(SANITIZE_ADDRESS AND NOT MSVC)
+ setup_sanitize_address()
+endif()
+
+# Detect if the python libs were compiled in debug mode
+# On Linux distros there is no standard way to check that.
+execute_process(
+ COMMAND ${Python_EXECUTABLE} -c "if True:
+ import sys
+ import sysconfig
+ config_py_debug = sysconfig.get_config_var('Py_DEBUG')
+ print(bool(config_py_debug))
+ "
+ OUTPUT_VARIABLE PYTHON_WITH_DEBUG
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+# Detect if python interpeter was compiled with COUNT_ALLOCS define
+# Linux distros are inconsistent in setting the sysconfig.get_config_var('COUNT_ALLOCS') value
+# We can't detect it when cross-building, because we can't run the target python executable.
+# TODO: Is there another way to detect this and is it relevant for cross-built python interpreters?
+# At the very least, upstream CPython removed COUNT_ALLOCS support in Python 3.9.
+if(SHIBOKEN_IS_CROSS_BUILD)
+ set(PYTHON_WITH_COUNT_ALLOCS 0)
+else()
+ execute_process(
+ COMMAND ${Python_EXECUTABLE} -c "if True:
+ count_allocs = False
+ import sys
+ try:
+ if sys.getcounts:
+ count_allocs = True
+ except:
+ pass
+
+ print(bool(count_allocs))
+ "
+ OUTPUT_VARIABLE PYTHON_WITH_COUNT_ALLOCS
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+endif()
+
+
+set(SHIBOKEN_BUILD_TYPE "${CMAKE_BUILD_TYPE}")
+
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set_debug_build()
+endif()
+
+######################################################################
+## Define the Python files involved in the build process.
+##
+## They are installed into the file system (see shibokenmodule)
+## and embedded into the libshiboken binary through a .zip file.
+######################################################################
+
+set(shiboken_python_files
+ "signature/lib/__init__.py"
+ "signature/lib/enum_sig.py"
+ "signature/lib/pyi_generator.py"
+ "signature/lib/tool.py"
+ "signature/__init__.py"
+ "signature/errorhandler.py"
+ "signature/importhandler.py"
+ "signature/layout.py"
+ "signature/loader.py"
+ "signature/mapping.py"
+ "signature/parser.py"
+ "__init__.py"
+ "feature.py"
+ )
+
+# uninstall target
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
+add_custom_target(uninstall "${CMAKE_COMMAND}"
+ -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
+
+set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX})
diff --git a/sources/shiboken6/cmake_uninstall.cmake b/sources/shiboken6/cmake_uninstall.cmake
new file mode 100644
index 000000000..4031b4e1a
--- /dev/null
+++ b/sources/shiboken6/cmake_uninstall.cmake
@@ -0,0 +1,24 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+FOREACH(file ${files})
+ MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+ IF(EXISTS "$ENV{DESTDIR}${file}")
+ EXEC_PROGRAM(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ IF(NOT "${rm_retval}" STREQUAL 0)
+ MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+ ENDIF(NOT "${rm_retval}" STREQUAL 0)
+ ELSE(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
+ ENDIF(EXISTS "$ENV{DESTDIR}${file}")
+ENDFOREACH(file)
diff --git a/sources/shiboken6/config.tests/target_python_info/CMakeLists.txt b/sources/shiboken6/config.tests/target_python_info/CMakeLists.txt
new file mode 100644
index 000000000..b3f994017
--- /dev/null
+++ b/sources/shiboken6/config.tests/target_python_info/CMakeLists.txt
@@ -0,0 +1,47 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.18)
+project(proj LANGUAGES CXX)
+
+include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/ShibokenHelpers.cmake")
+
+shiboken_internal_detect_if_cross_building()
+shiboken_find_required_python()
+shiboken_internal_set_python_site_packages()
+
+message(STATUS "qfp:python_info:interpreter_found: ${Python_Interpreter_FOUND}")
+message(STATUS "qfp:python_info:development_found: ${Python_Development_FOUND}")
+message(STATUS "qfp:python_info:version: ${Python_VERSION}")
+message(STATUS "qfp:python_info:version_major: ${Python_VERSION_MAJOR}")
+message(STATUS "qfp:python_info:version_minor: ${Python_VERSION_MINOR}")
+message(STATUS "qfp:python_info:version_patch: ${Python_VERSION_PATCH}")
+message(STATUS "qfp:python_info:executable: ${Python_EXECUTABLE}")
+message(STATUS "qfp:python_info:include_dirs: ${Python_INCLUDE_DIRS}")
+message(STATUS "qfp:python_info:libraries: ${Python_LIBRARIES}")
+message(STATUS "qfp:python_info:library_dirs: ${Python_LIBRARY_DIRS}")
+message(STATUS "qfp:python_info:runtime_library_dirs: ${Python_RUNTIME_LIBRARY_DIRS}")
+# Python_SOABI will be empty with CMake < 3.17
+message(STATUS "qfp:python_info:so_abi: ${Python_SOABI}")
+message(STATUS "qfp:python_info:site_packages_dir: ${PYTHON_SITE_PACKAGES_WITHOUT_PREFIX}")
+message(STATUS "qfp:python_info:site_packages_dir_with_prefix: ${PYTHON_SITE_PACKAGES}")
+
+message(STATUS
+ "The following values might be unstable because they depend on private FindPython API")
+# This is using internal FindPython API and is subject to break.
+set(_PYTHON_PREFIX Python)
+if(COMMAND _python_get_config_var)
+ if(_${_PYTHON_PREFIX}_CONFIG)
+ message(STATUS "qfp:python_info:config_executable: ${_${_PYTHON_PREFIX}_CONFIG}")
+ endif()
+
+ _python_get_config_var(_${_PYTHON_PREFIX}_PREFIX PREFIX)
+ if(_${_PYTHON_PREFIX}_PREFIX)
+ message(STATUS "qfp:python_info:prefix: ${_${_PYTHON_PREFIX}_PREFIX}")
+ endif()
+ _python_get_config_var(_${_PYTHON_PREFIX}_CONFIGDIR CONFIGDIR)
+ if(_${_PYTHON_PREFIX}_CONFIGDIR)
+ message(STATUS "qfp:python_info:config_dir: ${_${_PYTHON_PREFIX}_CONFIGDIR}")
+ endif()
+endif()
+
diff --git a/sources/shiboken6/config.tests/target_qt_info/CMakeLists.txt b/sources/shiboken6/config.tests/target_qt_info/CMakeLists.txt
new file mode 100644
index 000000000..7cc6b6ffc
--- /dev/null
+++ b/sources/shiboken6/config.tests/target_qt_info/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.18)
+project(proj LANGUAGES CXX)
+
+include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/ShibokenHelpers.cmake")
+
+shiboken_internal_detect_if_cross_building()
+shiboken_internal_set_up_extra_dependency_paths()
+find_package(Qt6 REQUIRED COMPONENTS Core)
+
+include(FeatureSummary)
+
+feature_summary(INCLUDE_QUIET_PACKAGES
+ WHAT PACKAGES_FOUND
+ REQUIRED_PACKAGES_NOT_FOUND
+ RECOMMENDED_PACKAGES_NOT_FOUND
+ OPTIONAL_PACKAGES_NOT_FOUND
+ RUNTIME_PACKAGES_NOT_FOUND
+ FATAL_ON_MISSING_REQUIRED_PACKAGES)
+
+message(STATUS "qfp:qt_info:QT_VERSION: ${Qt6_VERSION}")
+message(STATUS "qfp:qt_info:QT_INSTALL_PREFIX: ${QT6_INSTALL_PREFIX}")
+message(STATUS "qfp:qt_info:QT_INSTALL_ARCHDATA: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_ARCHDATA}")
+message(STATUS "qfp:qt_info:QT_INSTALL_BINS: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_BINS}")
+message(STATUS "qfp:qt_info:QT_INSTALL_CONFIGURATION: ${QT6_INSTALL_CONFIGURATION}")
+message(STATUS "qfp:qt_info:QT_INSTALL_DATA: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}")
+message(STATUS "qfp:qt_info:QT_INSTALL_DOCS: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DOCS}")
+message(STATUS "qfp:qt_info:QT_INSTALL_EXAMPLES: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_EXAMPLES}")
+message(STATUS "qfp:qt_info:QT_INSTALL_HEADERS: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_HEADERS}")
+message(STATUS "qfp:qt_info:QT_INSTALL_LIBS: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_LIBS}")
+message(STATUS "qfp:qt_info:QT_INSTALL_LIBEXECS: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_LIBEXECS}")
+message(STATUS "qfp:qt_info:QT_INSTALL_PLUGINS: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_PLUGINS}")
+message(STATUS "qfp:qt_info:QT_INSTALL_QML: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_QML}")
+message(STATUS "qfp:qt_info:QT_INSTALL_TESTS: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_TESTS}")
+message(STATUS "qfp:qt_info:QT_INSTALL_TRANSLATIONS: ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_TRANSLATIONS}")
+message(STATUS "qfp:qt_info:is_shared: ${QT6_IS_SHARED_LIBS_BUILD}")
+
diff --git a/sources/shiboken6/config.tests/target_qt_mkspec/CMakeLists.txt b/sources/shiboken6/config.tests/target_qt_mkspec/CMakeLists.txt
new file mode 100644
index 000000000..9f6513316
--- /dev/null
+++ b/sources/shiboken6/config.tests/target_qt_mkspec/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.18)
+project(dummy LANGUAGES CXX)
+
+include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/ShibokenHelpers.cmake")
+
+shiboken_internal_detect_if_cross_building()
+shiboken_internal_set_up_extra_dependency_paths()
+find_package(Qt6 REQUIRED COMPONENTS Core)
+
+get_target_property(darwin_target Qt6::Core QT_DARWIN_MIN_DEPLOYMENT_TARGET)
+
+# Get macOS minimum deployment target
+message(STATUS "qfp:qt_info:QMAKE_MACOSX_DEPLOYMENT_TARGET: ${darwin_target}")
+
+# Get Qt build type
+if(QT_FEATURE_debug_and_release)
+ message(STATUS "qfp:qt_info:BUILD_TYPE: debug_and_release")
+elseif(QT_FEATURE_debug)
+ message(STATUS "qfp:qt_info:BUILD_TYPE: debug")
+else()
+ message(STATUS "qfp:qt_info:BUILD_TYPE: release")
+endif()
diff --git a/sources/shiboken6/data/CMakeLists.txt b/sources/shiboken6/data/CMakeLists.txt
new file mode 100644
index 000000000..679eefe6a
--- /dev/null
+++ b/sources/shiboken6/data/CMakeLists.txt
@@ -0,0 +1,60 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(LIBRARY_OUTPUT_SUFFIX ${CMAKE_DEBUG_POSTFIX})
+else()
+ set(LIBRARY_OUTPUT_SUFFIX ${CMAKE_RELEASE_POSTFIX})
+endif()
+
+include(CMakePackageConfigHelpers)
+
+# Build-tree / super project package config file.
+set(SHIBOKEN_PYTHON_MODULE_DIR "${shiboken6_BINARY_DIR}/shibokenmodule")
+set(SHIBOKEN_SHARED_LIBRARY_DIR "${shiboken6_BINARY_DIR}/libshiboken")
+
+configure_package_config_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/Shiboken6Config-spec.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Shiboken6Config${PYTHON_CONFIG_SUFFIX}.cmake"
+ INSTALL_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}"
+ PATH_VARS SHIBOKEN_PYTHON_MODULE_DIR SHIBOKEN_SHARED_LIBRARY_DIR
+ INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}"
+)
+
+# Install-tree / relocatable package config file.
+set(SHIBOKEN_PYTHON_MODULE_DIR "${PYTHON_SITE_PACKAGES}/shiboken6")
+if (WIN32)
+ set(SHIBOKEN_SHARED_LIBRARY_DIR "${BIN_INSTALL_DIR}")
+else()
+ set(SHIBOKEN_SHARED_LIBRARY_DIR "${LIB_INSTALL_DIR}")
+endif()
+
+configure_package_config_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/Shiboken6Config-spec.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/install/Shiboken6Config${PYTHON_CONFIG_SUFFIX}.cmake"
+ INSTALL_DESTINATION "${LIB_INSTALL_DIR}/cmake/Shiboken6"
+ PATH_VARS SHIBOKEN_PYTHON_MODULE_DIR SHIBOKEN_SHARED_LIBRARY_DIR
+)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Shiboken6Config.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Shiboken6Config.cmake" @ONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Shiboken6ConfigVersion.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Shiboken6ConfigVersion.cmake" @ONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/shiboken6.pc.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/shiboken6${shiboken6_SUFFIX}.pc" @ONLY)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Shiboken6Config.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/Shiboken6")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/Shiboken6Config${PYTHON_CONFIG_SUFFIX}.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/Shiboken6")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Shiboken6ConfigVersion.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/Shiboken6")
+
+install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ShibokenHelpers.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/Shiboken6")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/shiboken6${shiboken6_SUFFIX}.pc"
+ DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
+
diff --git a/sources/shiboken6/data/GeneratorRunnerConfig.cmake.in b/sources/shiboken6/data/GeneratorRunnerConfig.cmake.in
new file mode 100644
index 000000000..cf973e2a6
--- /dev/null
+++ b/sources/shiboken6/data/GeneratorRunnerConfig.cmake.in
@@ -0,0 +1,17 @@
+# GENERATORRUNNER_INCLUDE_DIR - Directories to include to use GENERATORRUNNER
+# GENERATORRUNNER_LIBRARIES - Files to link against to use GENERATORRUNNER
+# GENERATORRUNNER_PLUGIN_DIR - Where to find/put plugins for generator runner
+# GENERATORRUNNER_BINARY - Executable name
+
+SET(GENERATORRUNNER_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include/generatorrunner@generator_SUFFIX@")
+if(MSVC)
+ SET(GENERATORRUNNER_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@genrunner@generator_SUFFIX@.lib")
+elseif(CYGWIN)
+ SET(GENERATORRUNNER_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_IMPORT_LIBRARY_PREFIX@genrunner@generator_SUFFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
+elseif(WIN32)
+ SET(GENERATORRUNNER_LIBRARY "@CMAKE_INSTALL_PREFIX@/bin/@CMAKE_SHARED_LIBRARY_PREFIX@genrunner@generator_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
+else()
+ SET(GENERATORRUNNER_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@genrunner@generator_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
+endif()
+SET(GENERATORRUNNER_PLUGIN_DIR "@generator_plugin_DIR@")
+SET(GENERATORRUNNER_BINARY "@CMAKE_INSTALL_PREFIX@/bin/generatorrunner@generator_SUFFIX@")
diff --git a/sources/shiboken6/data/GeneratorRunnerConfigVersion.cmake.in b/sources/shiboken6/data/GeneratorRunnerConfigVersion.cmake.in
new file mode 100644
index 000000000..8eb5ba479
--- /dev/null
+++ b/sources/shiboken6/data/GeneratorRunnerConfigVersion.cmake.in
@@ -0,0 +1,10 @@
+set(PACKAGE_VERSION @generator_VERSION@)
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+endif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
diff --git a/sources/shiboken6/data/Shiboken6Config-spec.cmake.in b/sources/shiboken6/data/Shiboken6Config-spec.cmake.in
new file mode 100644
index 000000000..233404bc6
--- /dev/null
+++ b/sources/shiboken6/data/Shiboken6Config-spec.cmake.in
@@ -0,0 +1,41 @@
+# SHIBOKEN_BUILD_TYPE - Tells if Shiboken was compiled in Release or Debug mode.
+# SHIBOKEN_PYTHON_INTERPRETER - Python interpreter (regular or debug) to be used with the bindings.
+
+@PACKAGE_INIT@
+
+# This is the version of Python against which Shiboken was built. Not necessarily the version
+# against which a downstream project is built (e.g. PySide6).
+set(SHIBOKEN_PYTHON_VERSION_MAJOR "@Python_VERSION_MAJOR@")
+set(SHIBOKEN_PYTHON_VERSION_MINOR "@Python_VERSION_MINOR@")
+set(SHIBOKEN_PYTHON_VERSION_PATCH "@Python_VERSION_PATCH@")
+set(SHIBOKEN_PYTHON_LIMITED_API "@PYTHON_LIMITED_API@")
+
+# Import targets and call variable set up functions only when using an installed shiboken config
+# file (so not during a regular shiboken build, or during a super project build).
+if (NOT TARGET Shiboken6::libshiboken)
+ include("${CMAKE_CURRENT_LIST_DIR}/Shiboken6Targets.cmake")
+ include("${CMAKE_CURRENT_LIST_DIR}/ShibokenHelpers.cmake")
+
+ # Compute the python include and libraries path if needed (aka not part of super project build).
+ shiboken_find_required_python(@Python_VERSION_MAJOR@)
+ shiboken_check_if_built_and_target_python_are_compatible()
+ shiboken_check_if_limited_api()
+ shiboken_compute_python_includes(IS_CALLED_FROM_EXPORT)
+ shiboken_compute_python_libraries(IS_CALLED_FROM_EXPORT)
+endif()
+
+# Get the "python interpreter" dynamic global property as a variable instead. It brings it into
+# scope for super project builds.
+get_property(SHIBOKEN_PYTHON_INTERPRETER GLOBAL PROPERTY SHIBOKEN_PYTHON_INTERPRETER)
+
+# Set static variables.
+set(SHIBOKEN_PYTHON_EXTENSION_SUFFIX "@PYTHON_EXTENSION_SUFFIX@")
+set(SHIBOKEN_PYTHON_SHARED_LIBRARY_SUFFIX "@PYTHON_SHARED_LIBRARY_SUFFIX@")
+set(SHIBOKEN_PYTHON_CONFIG_SUFFIX "@PYTHON_CONFIG_SUFFIX@")
+set(SHIBOKEN_SO_VERSION "@shiboken6_library_so_version@")
+set(SHIBOKEN_BUILD_TYPE "@SHIBOKEN_BUILD_TYPE@")
+
+set_and_check(SHIBOKEN_PYTHON_MODULE_DIR "@PACKAGE_SHIBOKEN_PYTHON_MODULE_DIR@")
+set_and_check(SHIBOKEN_SHARED_LIBRARY_DIR "@PACKAGE_SHIBOKEN_SHARED_LIBRARY_DIR@")
+
+message(STATUS "libshiboken built for @SHIBOKEN_BUILD_TYPE@")
diff --git a/sources/shiboken6/data/Shiboken6Config.cmake.in b/sources/shiboken6/data/Shiboken6Config.cmake.in
new file mode 100644
index 000000000..d818eb4c9
--- /dev/null
+++ b/sources/shiboken6/data/Shiboken6Config.cmake.in
@@ -0,0 +1,5 @@
+if (NOT PYTHON_CONFIG_SUFFIX)
+ message(STATUS "Shiboken6Config: Using default python: @PYTHON_CONFIG_SUFFIX@")
+ SET(PYTHON_CONFIG_SUFFIX @PYTHON_CONFIG_SUFFIX@)
+endif()
+include("${CMAKE_CURRENT_LIST_DIR}/Shiboken6Config${PYTHON_CONFIG_SUFFIX}.cmake")
diff --git a/sources/shiboken6/data/Shiboken6ConfigVersion.cmake.in b/sources/shiboken6/data/Shiboken6ConfigVersion.cmake.in
new file mode 100644
index 000000000..3990e9dad
--- /dev/null
+++ b/sources/shiboken6/data/Shiboken6ConfigVersion.cmake.in
@@ -0,0 +1,10 @@
+set(PACKAGE_VERSION @shiboken6_VERSION@)
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+endif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
diff --git a/sources/shiboken6/data/Shiboken6ToolsConfig.cmake.in b/sources/shiboken6/data/Shiboken6ToolsConfig.cmake.in
new file mode 100644
index 000000000..438b5c651
--- /dev/null
+++ b/sources/shiboken6/data/Shiboken6ToolsConfig.cmake.in
@@ -0,0 +1,7 @@
+@PACKAGE_INIT@
+
+cmake_minimum_required(VERSION 3.18)
+
+if(NOT TARGET Shiboken6::shiboken6)
+ include("${CMAKE_CURRENT_LIST_DIR}/Shiboken6ToolsTargets.cmake")
+endif()
diff --git a/sources/shiboken6/data/docgenerator.1 b/sources/shiboken6/data/docgenerator.1
new file mode 120000
index 000000000..c65282f98
--- /dev/null
+++ b/sources/shiboken6/data/docgenerator.1
@@ -0,0 +1 @@
+generatorrunner.1 \ No newline at end of file
diff --git a/sources/shiboken6/data/generatorrunner.1 b/sources/shiboken6/data/generatorrunner.1
new file mode 100644
index 000000000..f5a61f139
--- /dev/null
+++ b/sources/shiboken6/data/generatorrunner.1
@@ -0,0 +1,76 @@
+.TH GENERATORRUNNER 1 "SEPTEMBER 2009" Linux "User Manuals"
+.SH NAME
+generatorrunner - plugin-based binding source code generator
+.SH SYNOPSIS
+.B generatorrunner \-\-generator-set=<plugin name> [options] header-file typesystem-file
+.SH DESCRIPTION
+.B generatorrunner
+is a utility that uses the information taken from APIExtractor
+related to the provided C++ headers and typesystem files and execute
+generators using this information. Generators are plugins and you need
+to specify one using the \-\-generator-set parameter. At the moment there
+are two generators available:
+
+.B qtdoc
+\- Generates Sphinx-based documentation for C++ libraries documented using
+.B qdoc
+documentation syntax, using the XML files created by the documentation tool
+.B (qdoc).
+Can be called supplying
+.B \-\-generator-set=qtdoc
+to
+.B generatorrunner
+or by calling the convenience executable
+.B docgenerator.
+
+Other plugins can be used with
+.B generatorrunner,
+provided that they follow the generator front-end specifications,
+and can be written to generate code or documentation for any target
+languague you desire. For more information about the generator front-end
+architecture and current limitations, refer to http://www.pyside.org/home-binding.
+
+.SH OPTIONS
+.SS "General options"
+.IP \-\-api-version=<version>
+Specify the supported api version used to generate the bindings.
+.IP \-\-debug-level=[sparse|medium|full]
+The amount of messages displayed.
+.IP \-\-documentation-only
+Only generates the documentation.
+.IP \-\-drop-type-entries="<TypeEntry0>[;TypeEntry1;...]"
+Semicolon separated list of type system entries (classes, namespaces, global functions and enums) to be dropped from generation.
+.IP \-\-help \fR,\fP \-h \fR,\fP -?
+Prints the usage message.
+.IP \-\-project-file=<file>
+Text file containing a description of the binding project. Replaces and overrides command line arguments.
+.IP \-\-include\-paths=\fI<path>[:path:..]\fR
+The directories where the generator will search for the
+headers. Works like gcc's \-I flag.
+.IP \-\-license\-file=\fI[licensefile]\fR
+Template for copyright headers of generated files.
+.IP \-\-no\-supress\-warnings
+Show all warnings.
+.IP \-\-output\-directory=\fI[dir]\fR
+The directory where the generated files will be written.
+.IP \-\-silent
+Avoid printing any messages.
+.IP \-\-typesytem\-paths=\fI<path>[:path:..]\fR
+The directories where the generator will search for the
+external typesystems referred by the main one.
+.IP \-\-version
+Displays the current version.
+Drops support for named args.
+.SS "Specific to qtdoc plugin"
+.IP \-\-documentation\-code\-snippets\-dir
+Directory used to search code snippets used by the documentation
+.IP \-\-documentation\-data\-dir
+Directory with XML files generated by documentation tool (qdoc or Doxygen)
+.IP \-\-documentation\-out\-dir
+The directory where the generated documentation files will be written
+.IP \-\-library\-source\-dir
+Directory where library source code is located
+
+.SH AUTHORS
+Lauro Moura <lauro.neto at openbossa dot org>, Bruno Araujo <bruno.araujo at openbossa dot org>, Hugo Lima <hugo.lima at openbossa dot org>
+
diff --git a/sources/shiboken6/data/generatorrunner.pc.in b/sources/shiboken6/data/generatorrunner.pc.in
new file mode 100644
index 000000000..a566f4356
--- /dev/null
+++ b/sources/shiboken6/data/generatorrunner.pc.in
@@ -0,0 +1,13 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@LIB_INSTALL_DIR@
+includedir=@CMAKE_INSTALL_PREFIX@/include
+
+
+Name: generatorrunner@generator_SUFFIX@
+Description: Generator Runner loads and calls binding generator front-ends.
+Requires: apiextractor
+Version: @generatorrunner_VERSION@
+Libs: -L${libdir} -lgenrunner@generator_SUFFIX@
+Cflags: -I${includedir}@generator_SUFFIX@
+
diff --git a/sources/shiboken6/data/shiboken6.pc.in b/sources/shiboken6/data/shiboken6.pc.in
new file mode 100644
index 000000000..a82d23168
--- /dev/null
+++ b/sources/shiboken6/data/shiboken6.pc.in
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_PREFIX@/@LIB_INSTALL_DIR@
+includedir=@CMAKE_INSTALL_PREFIX@/include/shiboken6
+python_interpreter=@Python_EXECUTABLE@
+python_include_dir=@Python_INCLUDE_DIRS@
+
+Name: shiboken6
+Description: Support library for Python bindings created with the Shiboken6 generator.
+Version: @shiboken6_VERSION@
+Libs: @SHIBOKEN_PYTHON_LIBRARIES@ -L${libdir} -lshiboken6@shiboken6_SUFFIX@@PYTHON_SHARED_LIBRARY_SUFFIX@@LIBRARY_OUTPUT_SUFFIX@
+Cflags: -I@Python_INCLUDE_DIRS@ -I${includedir}/@shiboken6_SUFFIX@@SBK_PKG_CONFIG_PY_DEBUG_DEFINITION@
diff --git a/sources/shiboken6/doc/CMakeLists.txt b/sources/shiboken6/doc/CMakeLists.txt
new file mode 100644
index 000000000..eaef4ff29
--- /dev/null
+++ b/sources/shiboken6/doc/CMakeLists.txt
@@ -0,0 +1,73 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.18)
+
+if(FULLDOCSBUILD EQUAL 0)
+ project(shiboken6_doc)
+endif()
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake")
+include(FindDocTools)
+
+# Generate html by default.
+if(NOT DOC_OUTPUT_FORMAT)
+ set(DOC_OUTPUT_FORMAT "html")
+endif()
+
+if(SPHINX_BUILD)
+ message(STATUS "sphinx-build - found")
+ configure_file(conf.py.in conf.py @ONLY)
+ # conditional tag for sphinx build
+ #string(JOIN "_" SPHINX_TAG ${DOC_OUTPUT_FORMAT} "format")
+ add_custom_target(doc
+ COMMAND ${SPHINX_BUILD} -b ${DOC_OUTPUT_FORMAT} -j auto -c . ${CMAKE_CURRENT_SOURCE_DIR} html
+ COMMENT "Generating shiboken documentation HTML files"
+ VERBATIM)
+
+ # Attach a POST_BUILD step to the 'doc' custom target to generate a QCH file.
+ if(DOC_OUTPUT_FORMAT STREQUAL "qthelp")
+ if(qhelpgenerator_binary)
+ message(STATUS "qhelpgenerator - found")
+
+ # Python script that will be called to update the QHP
+ set(PATCH_QHP_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/../../shiboken6/doc/scripts/patch_qhp.py")
+ file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/html/Shiboken.qhp QHP_FILE)
+
+ if(SHIBOKEN_IS_CROSS_BUILD)
+ set(python_executable "${QFP_PYTHON_HOST_PATH}")
+ else()
+ set(python_executable "${Python_EXECUTABLE}")
+ endif()
+ if(NOT python_executable OR NOT EXISTS "${python_executable}")
+ message(FATAL_ERROR "No python executable found to build documentation.")
+ endif()
+
+ add_custom_command(TARGET doc POST_BUILD
+ COMMAND "${python_executable}" ${PATCH_QHP_SCRIPT} -v shiboken6 ${QHP_FILE}
+ COMMAND "${qhelpgenerator_binary}" ${QHP_FILE}
+ COMMENT "Generating shiboken documentation QCH files based on the QHP files"
+ VERBATIM)
+ else()
+ message(WARNING "qhelpgenerator - not found! qch generation disabled")
+ endif()
+ endif()
+else()
+ if(NOT SPHINX_BUILD)
+ message(WARNING "sphinx-build - not found! doc target disabled")
+ endif()
+ if (WIN32)
+ # if jom is used and we have no sphinx, then jom will crash.
+ # so for windows, we always create a doc target (until jom gets fixed...)
+ add_custom_target(doc echo.
+ COMMAND echo +++ This is a fake build, to make 'jom' happy.
+ COMMAND echo +++ The documentation was _not_ built!
+ COMMAND echo.
+ )
+ endif()
+endif()
+
+if (NOT WIN32)
+ file(GLOB manpages "${CMAKE_CURRENT_SOURCE_DIR}/*.1")
+ install(FILES ${manpages} DESTINATION share/man/man1)
+endif()
diff --git a/sources/shiboken6/doc/README.md b/sources/shiboken6/doc/README.md
new file mode 100644
index 000000000..2575eafd2
--- /dev/null
+++ b/sources/shiboken6/doc/README.md
@@ -0,0 +1,12 @@
+# Shiboken Documentation
+
+The documentation was written and needs to be generated
+with [python-sphinx](http://www.sphinx-doc.org/en/master/)
+
+### Images
+
+The SVG diagrams use the Qt color scheme.
+The font also follows Qt styling, and it is called `Titillium`.
+It can be download from:
+* https://fonts.google.com/specimen/Titillium+Web
+* https://www.fontsquirrel.com/fonts/Titillium
diff --git a/sources/shiboken6/doc/_static/css/qt_font.css b/sources/shiboken6/doc/_static/css/qt_font.css
new file mode 100644
index 000000000..ce39943ef
--- /dev/null
+++ b/sources/shiboken6/doc/_static/css/qt_font.css
@@ -0,0 +1,15 @@
+@font-face {
+ font-family: 'Titillium Web';
+ font-style: normal;
+ font-weight: 400;
+ src: url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.eot");
+ /* IE9 Compat Modes */
+ src: local("Titillium Web"),
+ local("TitilliumWeb-Regular"),
+ url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.eot?#iefix") format("embedded-opentype"),
+ url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.woff2") format("woff2"),
+ url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.woff") format("woff"),
+ url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.ttf") format("truetype"),
+ url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.svg#TitilliumWeb") format("svg");
+ /* Legacy iOS */
+}
diff --git a/sources/shiboken6/doc/_static/css/qt_style.css b/sources/shiboken6/doc/_static/css/qt_style.css
new file mode 100644
index 000000000..08c4646c6
--- /dev/null
+++ b/sources/shiboken6/doc/_static/css/qt_style.css
@@ -0,0 +1,100 @@
+.text-center {
+ text-align: center !important;
+}
+
+.text-center img {
+ padding-top: 10px;
+ height: 70px !important;
+}
+
+.cover-img img {
+ object-fit: cover;
+ height: 50%;
+}
+
+/* Tables */
+.section .docutils.container td {
+ float:left;
+}
+
+table.docutils {
+ margin-right: auto;
+ margin-bottom: 10px;
+ border: none;
+ width: initial;
+ font-size: 0.8em;
+}
+
+table.docutils.colwidths-given td {
+ float: none;
+}
+
+table.docutils th,
+table.docutils td {
+ padding-left:0;
+ border: none;
+}
+
+table.docutils td ul {
+ margin:0
+}
+
+table.docutils td ul > li {
+ margin: 0 0 0.5em;
+}
+
+.hide {
+ display: none;
+}
+
+.fixed .container {
+ max-width:1280px;
+ margin:0 auto;
+ padding:0 3.9%; /* 0? */
+ position:relative;
+ overflow:visible
+}
+
+/* We cannot put a :download:`....` command inside
+ * a sphinx-design button, so we add some properties from the button
+ * to the download class to mimic it */
+code.download {
+ text-align: center;
+ color: var(--color-brand-primary);
+ display: block;
+ border-color: transparent;
+ background-color: transparent;
+ border: 1px solid var(--color-brand-primary) !important;
+ border-radius: 0.25rem;
+ font-size: 1rem;
+ font-weight: 400;
+ vertical-align: middle;
+ padding: .375rem .75rem;
+ user-select: none;
+ line-height: 1.5;
+ transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
+}
+
+code.download:hover {
+ color: white;
+ background-color: var(--color-brand-primary);
+ border-color: var(--color-brand-primary);
+ text-decoration: none;
+ padding: .375rem .75rem;
+}
+
+dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple):first-child > dt {
+ font-size: +2.25rem;
+ font-weight: 700;
+ color: #ff00dd;
+}
+
+.theme-toggle svg{
+ width: +1.25rem;
+ height: +2.25rem;
+}
+
+.sd-card-title code span {
+ font-size: +1rem;
+ color: var(--color-brand-primary);
+}
diff --git a/sources/shiboken6/doc/_static/qtforpython.png b/sources/shiboken6/doc/_static/qtforpython.png
new file mode 100644
index 000000000..3a2f2bd17
--- /dev/null
+++ b/sources/shiboken6/doc/_static/qtforpython.png
Binary files differ
diff --git a/sources/shiboken6/doc/_static/shiboken.png b/sources/shiboken6/doc/_static/shiboken.png
new file mode 100644
index 000000000..587d33329
--- /dev/null
+++ b/sources/shiboken6/doc/_static/shiboken.png
Binary files differ
diff --git a/sources/shiboken6/doc/_static/shiboken.svg b/sources/shiboken6/doc/_static/shiboken.svg
new file mode 100644
index 000000000..a13f3e9fb
--- /dev/null
+++ b/sources/shiboken6/doc/_static/shiboken.svg
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="1080"
+ zoomAndPan="magnify"
+ viewBox="0 0 810 809.999993"
+ height="1080"
+ preserveAspectRatio="xMidYMid meet"
+ version="1.0"
+ id="svg47"
+ sodipodi:docname="shiboken.svg"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview49"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ showgrid="false"
+ inkscape:zoom="0.80648148"
+ inkscape:cx="505.28129"
+ inkscape:cy="540"
+ inkscape:window-width="2552"
+ inkscape:window-height="1432"
+ inkscape:window-x="1924"
+ inkscape:window-y="4"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg47" />
+ <defs
+ id="defs17">
+ <clipPath
+ id="25c649227a">
+ <path
+ d="M 187.234375 180.804688 L 622.011719 180.804688 L 622.011719 615.582031 L 187.234375 615.582031 Z M 187.234375 180.804688 "
+ clip-rule="nonzero"
+ id="path2" />
+ </clipPath>
+ <clipPath
+ id="a7a24c818d">
+ <path
+ d="M 475.953125 479.28125 L 728.5625 479.28125 L 728.5625 731.886719 L 475.953125 731.886719 Z M 475.953125 479.28125 "
+ clip-rule="nonzero"
+ id="path5" />
+ </clipPath>
+ <clipPath
+ id="9e94c67ce5">
+ <path
+ d="M 80.601562 479.28125 L 332.789062 479.28125 L 332.789062 731.886719 L 80.601562 731.886719 Z M 80.601562 479.28125 "
+ clip-rule="nonzero"
+ id="path8" />
+ </clipPath>
+ <clipPath
+ id="f807adb387">
+ <path
+ d="M 475.953125 81.417969 L 728.5625 81.417969 L 728.5625 333.609375 L 475.953125 333.609375 Z M 475.953125 81.417969 "
+ clip-rule="nonzero"
+ id="path11" />
+ </clipPath>
+ <clipPath
+ id="a7b91dab09">
+ <path
+ d="M 80.601562 81.417969 L 332.789062 81.417969 L 332.789062 333.609375 L 80.601562 333.609375 Z M 80.601562 81.417969 "
+ clip-rule="nonzero"
+ id="path14" />
+ </clipPath>
+ </defs>
+ <path
+ fill="#41cb51"
+ d="M 404.621094 459.0625 C 371.058594 459.0625 343.753906 431.75 343.753906 398.195312 C 343.753906 364.628906 371.058594 337.324219 404.621094 337.324219 C 438.179688 337.324219 465.492188 364.628906 465.492188 398.195312 C 465.492188 431.75 438.179688 459.0625 404.621094 459.0625 Z M 404.621094 459.0625 "
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path25" />
+ <g
+ clip-path="url(#25c649227a)"
+ id="g29">
+ <path
+ fill="#41cb51"
+ d="M 614.714844 363.132812 L 568.308594 355.550781 C 564.375 340.4375 558.351562 325.984375 550.351562 312.4375 L 577.464844 273.804688 C 579.890625 270.34375 579.480469 265.648438 576.5 262.65625 L 539.613281 225.769531 C 536.59375 222.742188 531.828125 222.371094 528.386719 224.855469 L 490.152344 252.335938 C 476.578125 244.351562 462.109375 238.34375 447.003906 234.4375 L 438.867188 187.996094 C 438.136719 183.839844 434.519531 180.804688 430.292969 180.804688 L 378.117188 180.804688 C 373.859375 180.804688 370.222656 183.890625 369.535156 188.101562 L 361.953125 234.535156 C 347.023438 238.421875 332.691406 244.371094 319.222656 252.273438 L 280.808594 224.820312 C 277.335938 222.351562 272.617188 222.742188 269.597656 225.742188 L 232.703125 262.628906 C 229.71875 265.613281 229.304688 270.308594 231.730469 273.761719 L 258.851562 312.5 C 250.886719 325.996094 244.902344 340.386719 240.980469 355.402344 L 194.511719 363.140625 C 190.3125 363.835938 187.234375 367.464844 187.234375 371.714844 L 187.234375 423.890625 C 187.234375 428.105469 190.261719 431.714844 194.40625 432.445312 L 240.894531 440.6875 C 244.78125 455.6875 250.746094 470.0625 258.675781 483.582031 L 231.214844 521.964844 C 228.746094 525.425781 229.136719 530.164062 232.136719 533.175781 L 269.023438 570.0625 C 272 573.035156 276.695312 573.453125 280.15625 571.035156 L 318.875 543.9375 C 332.320312 551.878906 346.703125 557.871094 361.78125 561.808594 L 369.535156 608.3125 C 370.242188 612.503906 373.867188 615.582031 378.117188 615.582031 L 430.292969 615.582031 C 434.5 615.582031 438.109375 612.554688 438.847656 608.40625 L 447.101562 561.914062 C 462.292969 557.984375 476.804688 551.949219 490.394531 543.921875 L 529.074219 571.035156 C 532.535156 573.460938 537.230469 573.050781 540.210938 570.070312 L 577.082031 533.183594 C 580.097656 530.164062 580.480469 525.410156 577.984375 521.957031 L 550.480469 483.730469 C 558.464844 470.175781 564.453125 455.714844 568.359375 440.609375 L 614.8125 432.460938 C 618.976562 431.722656 622.011719 428.105469 622.011719 423.890625 L 622.011719 371.714844 C 622.011719 367.453125 618.921875 363.820312 614.714844 363.132812 Z M 404.621094 502.539062 C 347.085938 502.539062 300.277344 455.722656 300.277344 398.183594 C 300.277344 340.65625 347.085938 293.847656 404.621094 293.847656 C 462.160156 293.847656 508.96875 340.65625 508.96875 398.183594 C 508.96875 455.722656 462.160156 502.539062 404.621094 502.539062 Z M 404.621094 502.539062 "
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path27" />
+ </g>
+ <g
+ clip-path="url(#a7a24c818d)"
+ id="g33">
+ <path
+ fill="#ffd43b"
+ d="M 653.035156 479.28125 C 653.035156 576.996094 573.667969 656.363281 475.953125 656.363281 L 475.953125 731.886719 C 615.484375 731.886719 728.5625 618.8125 728.5625 479.28125 Z M 653.035156 479.28125 "
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path31" />
+ </g>
+ <g
+ clip-path="url(#9e94c67ce5)"
+ id="g37">
+ <path
+ fill="#306998"
+ d="M 156.125 479.28125 C 156.125 576.996094 235.492188 656.363281 333.207031 656.363281 L 333.207031 731.886719 C 193.675781 731.886719 80.601562 618.8125 80.601562 479.28125 Z M 156.125 479.28125 "
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path35" />
+ </g>
+ <g
+ clip-path="url(#f807adb387)"
+ id="g41">
+ <path
+ fill="#306998"
+ d="M 653.035156 334.023438 C 653.035156 236.308594 573.667969 156.945312 475.953125 156.945312 L 475.953125 81.417969 C 615.484375 81.417969 728.5625 194.492188 728.5625 334.023438 Z M 653.035156 334.023438 "
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path39" />
+ </g>
+ <g
+ clip-path="url(#a7b91dab09)"
+ id="g45">
+ <path
+ fill="#ffd43b"
+ d="M 156.125 334.023438 C 156.125 236.308594 235.492188 156.945312 333.207031 156.945312 L 333.207031 81.417969 C 193.675781 81.417969 80.601562 194.492188 80.601562 334.023438 Z M 156.125 334.023438 "
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path43" />
+ </g>
+</svg>
diff --git a/sources/shiboken6/doc/_templates/index.html b/sources/shiboken6/doc/_templates/index.html
new file mode 100644
index 000000000..00ac64271
--- /dev/null
+++ b/sources/shiboken6/doc/_templates/index.html
@@ -0,0 +1,35 @@
+{% extends "layout.html" %}
+{% set title = 'Overview' %}
+{% block body %}
+<div class="section">
+ <h1>{{ project }} {{ version }}</h1>
+
+ <p>{{ project }} is a plugin (front-end) for Generator Runner. It generates bindings for C++ libraries using CPython source code.</p>
+
+ <h2>Documentation</h2>
+ <table class="contentstable" align="center" style="margin-left: 30px"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Contents</a><br/>
+ <span class="linkdescr">for a complete overview</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("faq") }}">FAQ</a><br/>
+ <span class="linkdescr">answers for frequent asked questions</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("commandlineoptions") }}">Command line options</a><br/>
+ <span class="linkdescr">explains the few flags used to change {{ project }} behaviour</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("typesystemvariables") }}">Type System Variables</a><br/>
+ <span class="linkdescr">describes the type system variables that could be used in user custom code</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("typeconverters") }}">Type Converters</a><br/>
+ <span class="linkdescr">describes how to define type converters</span></p>
+ </td>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("codeinjectionsemantics") }}">Code Injection Semantics</a><br/>
+ <span class="linkdescr">explains how custom code injection is interpreted by {{ project }}</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("sequenceprotocol") }}">Sequence Protocol</a><br/>
+ <span class="linkdescr">support for python sequence protocol</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("ownership") }}">Object Ownership</a><br/>
+ <span class="linkdescr">object ownership features</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("wordsofadvice") }}">Words of Advice</a><br/>
+ <span class="linkdescr">Advice for binding developers and users.</span></p>
+ </td></tr>
+ </table>
+</div>
+{% endblock %}
diff --git a/sources/shiboken6/doc/_templates/layout.html b/sources/shiboken6/doc/_templates/layout.html
new file mode 100644
index 000000000..8f16e1cdf
--- /dev/null
+++ b/sources/shiboken6/doc/_templates/layout.html
@@ -0,0 +1,53 @@
+{% extends "!layout.html" %}
+
+{%- block sidebar1 %}{{ sidebar() }}{%- endblock %}
+{%- block sidebar2 %}{%- endblock %}
+
+{% block sidebarlogo %}
+<div class="logo">
+ <a href="http://www.pyside.org">
+ <img alt="PySide" src="{{ pathto('_static/pysidelogo.png', 1) }}"/>
+ </a>
+</div>
+{% endblock %}
+
+{%- block header %}
+<div id="container">
+ <div class="header">
+ <div class="header_container">
+ <div class="related">
+ <ul>
+ {%- block rootrellink %}
+ <li><a href="{{ pathto( 'index' ) }}">{{ shorttitle|e }}</a></li>
+ {%- endblock %}
+ {%- for parent in parents %}
+ <li>{{ reldelim1 }} <a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a></li>
+ {%- endfor %}
+ {%- block relbaritems %} {% endblock %}
+ </ul>
+ </div>
+ </div>
+ </div>
+{%- endblock -%}
+
+{%- block document %}
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+ {% block body %} {% endblock %}
+ </div>
+ </div>
+ </div>
+{% endblock %}
+
+{%- block footer %}
+ <div class="footer">
+ <a href="https://www.qt.io/"><img src="{{ pathto('_static/logo_qt.png', 1) }}" alt="Qt" border="0" /></a>
+ <a href="http://www.python.org"><img src="{{ pathto('_static/logo_python.jpg', 1) }}" alt="Python" border="0" /></a>
+ <p>{{ copyright }}</p>
+ </div>
+</div>
+{%- endblock %}
+
+{%- block relbar1 %}{%- endblock %}
+{%- block relbar2 %}{%- endblock %}
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/domainindex.html b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/domainindex.html
new file mode 100644
index 000000000..c136cdd1c
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/domainindex.html
@@ -0,0 +1,57 @@
+{#
+ basic/domainindex.html
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+ Template for domain indices (module index, ...).
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{% extends "layout.html" %}
+{% set title = indextitle %}
+{% block extrahead %}
+{{ super() }}
+{% if not embedded and collapse_index %}
+ <script type="text/javascript">
+ DOCUMENTATION_OPTIONS.COLLAPSE_INDEX = true;
+ </script>
+{% endif %}
+{% endblock %}
+{% block body %}
+<div class="section">
+ {%- set curr_group = 0 %}
+
+ <h1>{{ indextitle }}</h1>
+
+ <div class="modindex-jumpbox">
+ {%- for (letter, entries) in content %}
+ <a href="#cap-{{ letter }}"><strong>{{ letter }}</strong></a>
+ {%- if not loop.last %} | {% endif %}
+ {%- endfor %}
+ </div>
+
+ <table class="indextable modindextable" cellspacing="0" cellpadding="2">
+ {%- for letter, entries in content %}
+ <tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-{{ letter }}">
+ <strong>{{ letter }}</strong></a></td><td></td></tr>
+ {%- for (name, grouptype, page, anchor, extra, qualifier, description)
+ in entries %}
+ {%- if grouptype == 1 %}{% set curr_group = curr_group + 1 %}{% endif %}
+ <tr{% if grouptype == 2 %} class="cg-{{ curr_group }}"{% endif %}>
+ <td>{% if grouptype == 1 -%}
+ <img src="{{ pathto('_static/minus.png', 1) }}" id="toggle-{{ curr_group }}"
+ class="toggler" style="display: none" alt="-" />
+ {%- endif %}</td>
+ <td>{% if grouptype == 2 %}&nbsp;&nbsp;&nbsp;{% endif %}
+ {% if page %}<a href="{{ pathto(page) }}#{{ anchor }}">{% endif -%}
+ <tt class="xref">{{ name|e }}</tt>
+ {%- if page %}</a>{% endif %}
+ {%- if extra %} <em>({{ extra|e }})</em>{% endif -%}
+ </td><td>{% if qualifier %}<strong>{{ qualifier|e }}:</strong>{% endif %}
+ <em>{{ description|e }}</em></td></tr>
+ {%- endfor %}
+ {%- endfor %}
+ </table>
+</div>
+{% endblock %}
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/fakebar.png b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/fakebar.png
new file mode 100644
index 000000000..b45830e00
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/fakebar.png
Binary files differ
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/logo_python.jpg b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/logo_python.jpg
new file mode 100644
index 000000000..cd474efba
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/logo_python.jpg
Binary files differ
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/logo_qt.png b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/logo_qt.png
new file mode 100644
index 000000000..3bc03b7c7
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/logo_qt.png
Binary files differ
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/minus.png b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/minus.png
new file mode 100644
index 000000000..da1c5620d
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/minus.png
Binary files differ
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/plus.png b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/plus.png
new file mode 100644
index 000000000..b3cb37425
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/plus.png
Binary files differ
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/pyside.css b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/pyside.css
new file mode 100644
index 000000000..94134cacf
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/pyside.css
@@ -0,0 +1,1943 @@
+@import url('cookie-confirm.css') screen;
+
+/* -- admonitions -- */
+
+div.admonition {
+ margin: 1.5em 0 1.5em;
+ padding: 0;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+div.admonition code {
+ font-family: inherit;
+}
+
+p.admonition-title + p {
+ padding-left: 1em;
+}
+
+div.admonition a:after {
+ content: ', ';
+}
+
+div.admonition a:last-child:after {
+ content: '';
+}
+
+.body {
+ width: 100%
+}
+.bodywrapper .admonition p.admonition-title {
+ margin-bottom:5px
+}
+
+.bodywrapper .admonition p {
+ margin:0
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+div.warning, div.seealso, div.note {
+ padding: 6px 0px 6px 10px;
+ border: none;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+}
+
+div.seealso {
+ background-color: #fff2d6;
+}
+
+div.note {
+ background-color: #f3f3f4;
+}
+
+table.docutils {
+ margin-right: auto;
+ margin-bottom: 10px;
+ border: none;
+ width: initial;
+}
+
+table.docutils.colwidths-given td {
+ float: none;
+}
+
+table.docutils th,
+table.docutils td {
+ padding-left:0;
+ border: none;
+}
+
+table.docutils td ul {
+ margin:0
+}
+
+table.docutils td ul > li {
+ margin: 0 0 0.5em;
+}
+h2 em {
+ float: right;
+ font-size: 10px;
+ position: relative;
+ top: -20px;
+}
+
+.document {
+ padding-bottom: 20px;
+}
+
+.documentwrapper {
+ margin-left: 20px;
+}
+
+.body blockquote {
+ border: none;
+ padding-left: 0;
+ margin-bottom: 1.5em;
+}
+
+.sphinxsidebar {
+ float: left;
+ width: 186px;
+ padding: 25px;
+ text-align: left;
+ background-color: #fff;
+}
+
+.sphinxsidebar ul {
+ padding: 0px;
+ margin: 0px;
+ list-style-position: inside;
+}
+
+.sphinxsidebar > ul {
+ padding: 0px;
+ margin: 0px;
+}
+
+.sphinxsidebar ul li li {
+ margin-left: 10px;
+ padding: 0px;
+ font-size: 0.95em;
+}
+
+.sphinxsidebar ul a,
+.sphinxsidebar p.topless a {
+ word-break: break-word;
+}
+
+.sphinxsidebar h3, .sphinxsidebar h3 a {
+ color: #333;
+}
+
+.sphinxsidebar p.topless {
+ margin: 1em 0 1em;
+}
+
+.pysidetoc ul {
+ list-style: none;
+ padding: 0px;
+ margin: 0px;
+}
+
+.pysidetoc em {
+ font-style: normal;
+}
+
+.pysidetoc strong {
+ display: block;
+ padding: 5px;
+ margin: 0 10px 10px 0;
+ border: none;
+ background-color: #e2e2e2;
+}
+
+.section .docutils.container td {
+ float:left;
+}
+
+.hide {
+ display: none;
+}
+
+/* copy-notice */
+.document + p {
+ margin-left: 255px;
+ width: 70%;
+ font-size: 0.75em;
+ margin: 0 35px 15px 280px;
+}
+
+#searchbox {
+ border-top: 1px solid #989898;
+ padding-top: 10px;
+ margin-left: -10px;
+ margin-right: -10px;
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+#search_button {
+ border: 1px solid #3A393A;
+ background-color: #3A393A;
+ color: white;
+ cursor: pointer;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -khtml-border-radius: 5px;
+
+}
+
+form {
+ margin: 0px;
+ padding: 0px;
+}
+
+#searchbox h3 {
+ padding: 10px 0 0 0;
+ margin-bottom: 5px;
+}
+
+/* search field */
+form #q {
+ width: 136px;
+ /* height: 22px; */
+ /* border: none; */
+ margin: 0px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -khtml-border-radius: 5px;
+ margin-top: 2px;
+ padding: 4px;
+ line-height: 22px;
+}
+
+#search-results h2 {
+ display: none;
+}
+
+#search-results h2 {
+ display: none;
+}
+
+#search-results ul.search {
+ margin: 0px;
+ padding: 0px;
+}
+
+ul.search div.context {
+ padding-left: 40px;
+}
+
+#installation td {
+ text-align: center;
+ font-weight: bold;
+}
+
+em {
+ color: inherit;
+ font-style:italic;
+}
+
+/******** REL bar *********/
+
+.related {
+ display: inline;
+}
+
+.related h3 {
+ display: none;
+}
+
+.align-center {
+ text-align: center;
+}
+
+.contentstable {
+ width: 100%;
+}
+
+.contentstable td {
+ padding-left: 30px;
+ vertical-align: top;
+}
+
+p.biglink a {
+ font-size: 20px;
+}
+
+dt:target, .highlight {
+ background-color: #fbe54e;
+}
+
+p.highlight-link {
+ margin-top: 10px;
+ font-size: 0.8em;
+}
+
+#synopsis table, table.field-list {
+ margin: 1em 0 1em 0;
+}
+
+table.field-list tr {
+ text-align: left;
+}
+
+tt.descname {
+ font-size: 120%;
+ font-weight: bold;
+}
+
+#functions ul, #virtual-functions ul, #slots ul, #signals ul, #static-functions ul {
+ margin: 0;
+ padding: 6px;
+ border: 1px solid #ddd;
+ border-radius: 0;
+ background-color: #e2e2e2;
+}
+
+#functions p, #virtual-functions p, #slots p, #signals p, #static-functions p {
+ margin: 0;
+ padding: 0;
+}
+
+#functions li, #virtual-functions li, #slots li, #signals li, #static-functions li {
+ list-style: none;
+ margin: 5px;
+ padding: 0;
+ font-size: 90%;
+}
+
+#synopsis span.pre {
+ color: #009491;
+ font-weight: bolder;
+}
+
+#detailed-description .class dt,
+#detailed-description .method dt,
+#detailed-description .staticmethod dt,
+#detailed-description .attribute dt {
+ margin: 0px;
+ margin-bottom: 10px;
+ padding: 10px;
+ font-weight: bold;
+ background-color: #e2e2e2;
+ border: none;
+ border-radius: 0;
+}
+
+#detailed-description dd > blockquote,
+#detailed-description dd > .field-list {
+ font-family: monospace;
+ font-size: small;
+ border-left: 10px solid #e2e2e2;
+ padding-left: 10px;
+ margin-bottom: 1.5em;
+}
+
+#detailed-description dd > blockquote blockquote {
+ border: none;
+ padding: 0;
+}
+
+#detailed-description .class .field-odd,
+#detailed-description .method .field-odd,
+#detailed-description .staticmethod .field-odd,
+#detailed-description .attribute .field-odd {
+ margin: 0;
+ padding: 1px 0 0 0;
+ background-color: #ffffff;
+
+}
+
+#detailed-description .class .field-even,
+#detailed-description .method .field-even,
+#detailed-description .staticmethod .field-even,
+#detailed-description .attribute .field-even {
+ margin: 0;
+ padding: 1px 0 0 0;
+ background-color: #ffffff;
+}
+
+#detailed-description .class .field-odd li,
+#detailed-description .method .field-odd li,
+#detailed-description .staticmethod .field-odd li,
+#detailed-description .attribute .field-odd li {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+
+}
+
+#detailed-description .class .field-even li,
+#detailed-description .method .field-even li,
+#detailed-description .staticmethod .field-even li,
+#detailed-description .attribute .field-even li {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+#detailed-description .class .field-odd p,
+#detailed-description .method .field-odd p,
+#detailed-description .staticmethod .field-odd p,
+#detailed-description .attribute .field-odd p{
+ margin: 0;
+ margin-left: 20px;
+
+}
+
+#detailed-description .class .field-even p,
+#detailed-description .method .field-even p,
+#detailed-description .staticmethod .field-even p,
+#detailed-description .attribute .field-even p{
+ margin: 0;
+ margin-left: 20px;
+}
+
+#detailed-description .class .field-odd p:last-child,
+#detailed-description .method .field-odd p:last-child,
+#detailed-description .staticmethod .field-odd p:last-child,
+#detailed-description .attribute .field-odd p:last-child {
+ margin-bottom: 10px;
+
+}
+
+#detailed-description .class .field-even p:last-child,
+#detailed-description .method .field-even p:last-child,
+#detailed-description .staticmethod .field-even p:last-child,
+#detailed-description .attribute .field-even p:last-child{
+ margin-bottom: 10px;
+}
+
+.document dl.attribute,
+.document dl.class,
+.document dl.method,
+.document dl.staticmethod {
+ margin-top: 2em;
+}
+
+.document dl.attribute dd,
+.document dl.class dd,
+.document dl.method dd,
+.document dl.staticmethod dd {
+ padding-left: 1em;
+}
+
+#detailed-description .attribute td:nth-child(1) {
+ font-family: monospace;
+}
+
+/* Qt theme */
+#navbar {
+ position:fixed;
+ top:0;
+ left:0;
+ z-index:100;
+ background:#fff;
+ width:100%
+}
+#navbar .container, .fixed .container {
+ max-width:1280px;
+ margin:0 auto;
+ padding:0 3.9%; /* 0? */
+ position:relative;
+ overflow:visible
+}
+#navbar .navbar-header {
+ position:relative
+}
+#menuextras li a:hover span {
+ color: #2cde85;
+}
+/* new header */
+#mm-wrap, #mm-wrap #mm-helper,
+#mm-wrap #mm-helper li.mm-item,
+#mm-wrap #mm-helper a.mm-link {
+ -moz-transition: none;
+ -o-transition: none;
+ -webkit-transition: none;
+ transition: none;
+ -webkit-border-radius: 0 0 0 0;
+ -moz-border-radius: 0 0 0 0;
+ -ms-border-radius: 0 0 0 0;
+ -o-border-radius: 0 0 0 0;
+ border-radius: 0 0 0 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ -ms-box-shadow: none;
+ -o-box-shadow: none;
+ box-shadow: none;
+ background: none;
+ border: 0;
+ bottom: auto;
+ box-sizing: border-box;
+ clip: auto;
+ color: #090e21;
+ display: block;
+ float: none;
+ font-family: inherit;
+ font-size: 14px;
+ height: auto;
+ left: auto;
+ line-height: 1.7;
+ list-style-type: none;
+ margin: 0;
+ min-height: 0;
+ opacity: 1;
+ outline: none;
+ overflow: visible;
+ padding: 0;
+ position: relative;
+ right: auto;
+ text-align: left;
+ text-decoration: none;
+ text-transform: none;
+ top: auto;
+ vertical-align: baseline;
+ visibility: inherit;
+ width: auto;
+}
+#mm-wrap #mm-helper {
+ visibility:visible;
+ text-align:right;
+ padding:0 0px 0 0px
+}
+#navbar #mm-wrap #mm-helper li.mm-item {
+ border-right:solid #f3f3f4 1px;
+ padding-right:30px;
+ padding-left:30px
+}
+#navbar #mm-wrap #mm-helper li.mm-item > a:hover {
+ opacity: .5
+}
+#mm-wrap #mm-helper > li.mm-item {
+ margin:0 0 0 0;
+ display:inline-block;
+ height:auto;
+ vertical-align:middle
+}
+#navbar #mm-wrap #mm-helper li.mm-item:nth-child(3) {
+ border-right:0
+}
+#mm-wrap #mm-helper a.mm-link {
+ cursor: pointer
+}
+@media (max-width: 1279px) {
+ #navbar {
+ padding:0;
+ position:relative;
+ }
+ #navbar .container {
+ max-width:100%
+ }
+ .container {
+ padding:0 2%
+ }
+}
+#navbar .navbar-oneQt {
+ display:inline;
+ float:left;
+ width:31px;
+ color:#2cde85
+}
+#navbar .navbar-oneQt:before {
+ content:attr(data-icon);
+ position:absolute;
+ top:14px;
+ left:0;
+ color:#2cde85;
+ font-family:'Qt Icons';
+ line-height:1;
+ font-size:40px;
+ transition:all 0.3s ease-in-out;
+}
+#mm-wrap {
+ clear:both;
+ background:rgba(255, 255, 255, 0.1);
+ -webkit-border-radius:0px 0px 0px 0px;
+ -moz-border-radius:0px 0px 0px 0px;
+ -ms-border-radius:0px 0px 0px 0px;
+ -o-border-radius:0px 0px 0px 0px;
+ border-radius:0px 0px 0px 0px
+}
+#mm-wrap #mm-helper li.mm-item:last-child a {
+ background:transparent url("icon_avatar.png") 50% 50% no-repeat !important;
+ background-size:24px !important;
+ width:24px !important;
+ height:24px !important;
+}
+#navbar #mm-wrap #mm-helper li.mm-item > a {
+ opacity:1;
+ -webkit-transition:all 0.3s ease-in-out;
+ -moz-transition:all 0.3s ease-in-out;
+ -ms-transition:all 0.3s ease-in-out;
+ -o-transition:all 0.3s ease-in-out;
+ transition:all 0.3s ease-in-out;
+}
+#mm-wrap #mm-helper > li.mm-item > a.mm-link {
+ border-top:0px solid #fff;
+ border-left:0px solid #fff;
+ border-right:0px solid #fff;
+ border-bottom:0px solid #fff;
+ outline:none;
+ text-decoration:none;
+ padding:0 0 0 0;
+ line-height:70px;
+ font-weight:normal;
+ height:70px;
+ vertical-align:baseline;
+ text-align:left;
+ width:auto;
+ display:block;
+ color:#090e21;
+ text-transform:none;
+ text-decoration:none;
+ background:rgba(0, 0, 0, 0);
+ -webkit-border-radius:0px 0px 0px 0px;
+ -moz-border-radius:0px 0px 0px 0px;
+ -ms-border-radius:0px 0px 0px 0px;
+ -o-border-radius:0px 0px 0px 0px;
+ border-radius:0px 0px 0px 0px;
+ font-family:inherit;
+ font-size:14px;
+}
+/* end new header */
+@media (min-width: 1320px) {
+ .body .flowListDiv dl.flowList {
+ -webkit-column-count:3;
+ -moz-column-count:3;
+ column-count:3
+ }
+}
+@media (min-width: 1120px) {
+ #navbar.fixed {
+ -moz-box-shadow:0px 0px 8px rgba(0,0,0,0.23);
+ -webkit-box-shadow:0px 0px 8px rgba(0,0,0,0.23);
+ box-shadow:0px 0px 8px rgba(0,0,0,0.23)
+ }
+ #navbar.fixed #mm-wrap #mm-helper > li.mm-item > a.mm-link {
+ height:50px;
+ line-height:50px
+ }
+ #navbar.fixed .navbar-oneQt:before {
+ font-size:35px;
+ top:7px
+ }
+
+ .flowListDiv dl.flowList {
+ -webkit-column-count:2;
+ -moz-column-count:2;
+ column-count:2
+ }
+}
+@media (max-width: 1120px) {
+ #navbar {
+ padding:0;
+ position:relative
+ }
+ #navbar .navbar-oneQt:before {
+ left:10px
+ }
+ #navbar .container {
+ max-width:100%;
+ padding:0
+ }
+ #footerbar .container {
+ padding:0
+ }
+ body .main {
+ margin-top:0px
+ }
+ #footerbar .footer-main .footer-nav {
+ padding:3.9% 0 3.9% 3%;
+ border-bottom:1px solid #413d3b;
+ float:none;
+ display:block;
+ width:auto
+ }
+ #footerbar .footer-main .theqtcompany {
+ clear:both;
+ float:left;
+ margin:30px 0 8px 3%
+ }
+ #footerbar .footer-main .footer-social {
+ float:left;
+ padding:50px 0px 0px 3%
+ }
+ #footerbar #menu-footer-submenu {
+ clear:both;
+ float:none;
+ display:block;
+ padding:0px 0px 3.9% 3%
+ }
+ ul#menu-footer-submenu {
+ margin-left: 0
+ }
+}
+.cookies_yum {
+ background-color:#cecfd5;
+ display:none;
+ width:100%
+}
+.cookies_yum img {
+ width:25px;
+ top:6px;
+ display:inline-block;
+ position:absolute;
+ left:13px
+}
+.cookies_yum div {
+ margin:0 auto;
+ max-width:1280px;
+ min-height:30px;
+ padding:6px 0px 6px 0px;
+ position:relative
+}
+.cookies_yum p {
+ color:#09102b;
+ margin:0px;
+ font-size:0.79em;
+ display:inline-block;
+ line-height:1.2;
+ padding:0 30px 0 50px
+}
+.cookies_yum p a {
+ white-space:nowrap
+}
+.cookies_yum a:hover {
+ color:#46a2da
+}
+.cookies_yum .close {
+ width:15px;
+ height:15px;
+ background-image:url("cookiebar-x.png");
+ background-size:15px 30px;
+ background-position:top left;
+ cursor:pointer;
+ top:13px;
+ right:13px;
+ position:absolute;
+ transition:none
+}
+.cookies_yum .close:hover {
+ background-position:bottom left
+}
+#sidebar-toggle,#toc-toggle {
+ width:24px;
+ height:14px;
+ background-size:24px 28px;
+ cursor:pointer;
+ background-image:url("list_expand.png");
+ float:right
+}
+#sidebar-toggle.collapsed,
+#toc-toggle.collapsed {
+ background-position:bottom left
+}
+#sidebar-content > h2 {
+ display:none
+}
+#footerbar {
+ background:#222840;
+ color:#fff;
+ font-size: 0.9em;
+}
+#footerbar.fixed {
+ bottom:0;
+ left:0;
+ width:100%
+}
+#footerbar .footer-nav {
+ display:inline;
+ float:left
+}
+#footerbar .footer-main .footer-nav li {
+ float:left;
+ margin-right:1em
+}
+#footerbar .footer-main .footer-nav li a {
+ display:block;
+ padding:30px 0 10px 0;
+ line-height:20px;
+ height:20px;
+ color:#fff;
+ font-weight: 600;
+}
+#footerbar .footer-main .footer-nav li a:hover,#footerbar .footer-main .footer-nav li.current-menu-item a {
+ color:#eee
+}
+#footerbar .footer-main .footer-nav .sub-menu {
+ margin-left:0;
+ margin-bottom:0
+}
+#footerbar .footer-main .footer-nav .sub-menu li {
+ float:none;
+ width: 100%;
+}
+#footerbar .footer-main .footer-nav .sub-menu ul {
+ padding:1px 1em;
+ font-size:0.786em;
+ line-height:8px;
+ float:none;
+ color:#5d5b59;
+ margin-bottom:0
+}
+#footerbar .footer-main .footer-nav .sub-menu li a {
+ padding:2px 0;
+ font-size:1em;
+ float:none;
+ color:#cecfd5;
+ font-weight: 400;
+}
+#footerbar .footer-main .footer-nav .sub-menu li a:hover,#footerbar .footer-main .footer-nav .sub-menu li.current-menu-item a {
+ color:#eee
+}
+#footerbar .theqtcompany {
+ background:url("theqtcompany.png") no-repeat;
+ background-size:100%;
+ width:215px;
+ height:68px;
+ display:inline;
+ float:right;
+ margin:29px 0 28px 30px
+}
+#footerbar .footer-social {
+ display:inline;
+ float:right;
+ width:164px
+}
+#footerbar .footer-main .footer-social>div {
+ margin-left:0.1em;
+ margin-bottom:10px
+}
+#footerbar .disclaimer {
+ font-size:0.786em;
+ line-height:2.73;
+ color:#868584;
+ padding-top:20px;
+ padding-bottom:0.5%
+}
+#footerbar .disclaimer a {
+ color:#bdbebf
+}
+#footerbar .disclaimer a:hover {
+ color:#d6d6d6
+}
+#footerbar .disclaimer ul li {
+ float:left;
+ vertical-align:middle;
+ margin-left:1.18em
+}
+#footerbar .disclaimer ul li:first-child {
+ margin-left:0
+}
+#footerbar .disclaimer ul.lang-selector a {
+ color:#506a34;
+ color:rgba(128,195,66,0.3)
+}
+#footerbar .disclaimer ul.lang-selector a:hover {
+ color:#80c342;
+ color:rgba(128,195,66,0.7)
+}
+#menu-footer-menu, #menu-footer-menu ul {
+ margin-left:0;
+ margin-bottom:0
+}
+@font-face {
+ font-family: 'Titillium Web';
+ font-style: normal;
+ font-weight: 400;
+ src: url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.eot");
+ /* IE9 Compat Modes */
+ src: local("Titillium Web"), local("TitilliumWeb-Regular"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.eot?#iefix") format("embedded-opentype"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.woff2") format("woff2"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.woff") format("woff"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.ttf") format("truetype"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-regular.svg#TitilliumWeb") format("svg");
+ /* Legacy iOS */
+}
+/* titillium-web-italic - latin_latin-ext */
+@font-face {
+ font-family: 'Titillium Web';
+ font-style: italic;
+ font-weight: 400;
+ src: url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-italic.eot");
+ /* IE9 Compat Modes */
+ src: local("Titillium WebItalic"), local("TitilliumWeb-Italic"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-italic.eot?#iefix") format("embedded-opentype"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-italic.woff2") format("woff2"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-italic.woff") format("woff"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-italic.ttf") format("truetype"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-italic.svg#TitilliumWeb") format("svg");
+ /* Legacy iOS */
+}
+/* titillium-web-600 - latin_latin-ext */
+@font-face {
+ font-family: 'Titillium Web';
+ font-style: normal;
+ font-weight: 600;
+ src: url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-600.eot");
+ /* IE9 Compat Modes */
+ src: local("Titillium WebSemiBold"), local("TitilliumWeb-SemiBold"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-600.eot?#iefix") format("embedded-opentype"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-600.woff2") format("woff2"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-600.woff") format("woff"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-600.ttf") format("truetype"), url("//d33sqmjvzgs8hq.cloudfront.net/wp-content/themes/oneqt/assets/fonts/titillium-web-v4-latin_latin-ext-600.svg#TitilliumWeb") format("svg");
+ /* Legacy iOS */
+}
+@font-face {
+ font-family:monospace;
+ font-style:normal;
+ font-weight:400;
+ src:local("Droid Sans Mono"),local("DroidSansMono"),url(//fonts.gstatic.com/s/droidsansmono/v7/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff) format("woff")
+}
+@font-face {
+ font-family:'Qt Icons';
+ src:url("../style/icomoon.eot?-tgjuoj");
+ src:url("../style/icomoon.eot?#iefix-tgjuoj") format("embedded-opentype"),url("../style/icomoon.woff?-tgjuoj") format("woff"),url("../style/icomoon.ttf?-tgjuoj") format("truetype"),url("../style/icomoon.svg?-tgjuoj#icomoon") format("svg");
+ font-weight:normal;
+ font-style:normal
+}
+@font-face {
+ font-family:'social-icons';
+ src:url("../style/social-icons.eot?54625607");
+ src:url("../style/social-icons.eot?54625607#iefix") format("embedded-opentype"),
+ url("../style/social-icons.woff?54625607") format("woff");
+ font-weight:normal;
+ font-style:normal
+}
+.clearfix:before,.clearfix:after {
+ content:" ";
+ display:table
+}
+.clearfix:after {
+ clear:both
+}
+.clearfix {
+ *zoom:1
+}
+.clearfix .right {
+ float:right
+}
+html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video {
+ margin:0;
+ padding:0;
+ border:0;
+ font-size:100%;
+ line-height: 1.4;
+}
+html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,caption,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video {
+ vertical-align:baseline
+}
+h1,h2,h3,h4,h5,h6 {
+ font-weight:300
+}
+.body h2,.body h3,.body h4,.body h5,.body h6 {
+ margin:1.5em 0 0.75em
+}
+.body h1 {
+ margin-bottom:0.75em;
+ font-size:2.25em;
+}
+.body h3.fn,.body h3.flags {
+ color:#26282a;
+ font-size:1.46em;
+ padding:15px 0 15px 0;
+ border-bottom:2px #eee solid;
+ word-wrap:break-word
+}
+.body .fngroup {
+ border-bottom:2px #eee solid;
+ padding-bottom:15px;
+ margin-bottom:1.5em
+}
+.body .fngroup h3.fngroupitem {
+ margin:0;
+ padding-bottom:0;
+ border:none
+}
+.body h3.fn .name,
+.body h3 span.type,
+.qmlname span.name {
+ font-weight: 400
+}
+.qmlname {
+ font-size:1.46em
+}
+.qmlproto table {
+ border:none;
+ border-bottom:2px #eee solid
+}
+.qmlproto table p {
+ max-width:100%
+}
+.qmlproto table tr {
+ background-color:#fff
+}
+.qmlname td, .qmlname th {
+ border:none;
+ text-align:left;
+ padding:5px 0 0 0
+}
+.qmlreadonly,.qmldefault {
+ padding:0 5px 0 5px;
+ font-size:0.75em;
+ background-color:#eee;
+ float:right
+}
+.qmlreadonly {
+ color:#414141
+}
+.qmldefault {
+ color:#D14141
+}
+.rightAlign {
+ padding:3px 5px 3px 10px;
+ text-align:right
+}
+.centerAlign.functionIndex {
+ text-align:center;
+ font-size:150%;
+ margin-bottom: 1em
+}
+article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section {
+ display:block
+}
+body {
+ line-height:1.25em;
+ font-family: Arial, Helvitica;
+ font-weight:400;
+ transition-duration:1s;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font-size: 16px;
+ background-color:#f3f3f4;
+ color:#404244;
+}
+ol,ul {
+ list-style-type: square;
+ #color: #17a81a;
+}
+.body ol,.body ul {
+ margin-top:0.75em;
+ margin-left:20px
+}
+.bodywrapper ol>li {
+ list-style-type:decimal;
+ margin-left:15px
+}
+.bodywrapper ol.a >li {
+ list-style-type:lower-alpha;
+}
+.bodywrapper ol.A >li {
+ list-style-type:upper-alpha;
+}
+.bodywrapper ol.i >li {
+ list-style-type:lower-roman;
+}
+.bodywrapper ol.I >li {
+ list-style-type:upper-roman;
+}
+.body li p {
+ margin-top:1em
+}
+blockquote,q {
+ quotes:none;
+ border-left:10px solid #ddd;
+ padding-left:10px
+}
+blockquote:before,blockquote:after,q:before,q:after {
+ content:'';
+ content:none;
+ width:100%
+}
+table {
+ border-collapse:collapse;
+ border-spacing:0;
+ margin-bottom:5px;
+ width:100%
+}
+a {
+ color:#17a81a;
+ text-decoration:none;
+ transition-duration:0.3s
+}
+a:hover {
+ color:#17a81a
+}
+.main,#footerbar>div {
+ max-width:1280px;
+ width:95%;
+ margin:0 auto
+}
+.main {
+ margin-top:80px
+}
+@media (max-width: 1120px) {
+ .main,.navbar-header,#footerbar>div {
+ width: 100%;
+ margin: 0;
+ }
+ .main .main-rounded {
+ padding: 0 15px;
+ }
+}
+.main_index {
+ background-color:#fff
+}
+.sectionlist {
+ margin-bottom:2em
+}
+[class*="col-"] {
+ letter-spacing:normal
+}
+.landing,.main_index .row {
+ letter-spacing:-0.31em
+}
+.main_index .row>div {
+ letter-spacing:normal
+}
+.col-1,.body {
+ display:inline-block;
+ background-color:#fff;
+ padding: 25px 35px 20px 30px;
+ -webkit-box-sizing:border-box;
+ -moz-box-sizing:border-box;
+ -ms-box-sizing:border-box;
+ box-sizing:border-box;
+}
+.col-1 h2 {
+ font-size:1.8em;
+ font-weight:300;
+ line-height:1.1;
+ margin-bottom:0.83em;
+ margin-top:1em
+}
+.icons1of3 img {
+ display:inline-block;
+ float:left;
+ margin-right:0.75em;
+ margin-top:-5px;
+ width:2.75em
+}
+div.multi-column {
+ position:relative
+}
+div.multi-column div {
+ display:-moz-inline-box;
+ display:inline-block;
+ vertical-align:top;
+ margin-top:1em;
+ margin-right:2em;
+ width:16em
+}
+.sidebar {
+ display:block;
+ position:relative;
+ position:sticky;
+ float:left;
+ -webkit-box-sizing:border-box;
+ -moz-box-sizing:border-box;
+ -ms-box-sizing:border-box;
+ box-sizing:border-box;
+ width:20%;
+ padding-right:20px
+}
+.sidebar li {
+ text-overflow:ellipsis;
+ overflow:hidden
+}
+.toc,.sectionlist {
+ padding:25px;
+ background-color:#fff;
+ margin-bottom:1.25em
+}
+.sidebar .sectionlist p {
+ margin-bottom:0
+}
+.sectionlist.promo {
+ padding:0;
+ background-color:#f3f3f4
+}
+.sidebar-content:empty {
+ display:none;
+ visibility:hidden
+}
+.col-2 h2,.toc h3,.sidebar-content h2,
+.sidebar-content h3,.sectionlist h2,
+.sphinxsidebar {
+ position: fixed;
+ overflow: scroll;
+ overflow-x: hidden;
+ overflow-y: hidden;
+}
+.sphinxsidebar h3 {
+ font-weight: bold;
+ margin-bottom:1em;
+}
+.toc h3 a {
+ color:#404244
+}
+.title {
+ font-size:2.25em;
+ font-weight:300;
+ letter-spacing:-1px;
+ line-height:1.15em;
+ margin-bottom:0.5em;
+ word-wrap:break-word
+}
+.navigationbar,col-1 h2 {
+ font-size:0.85em
+}
+.navigationbar h1 {
+ font-size:2.5em;
+ margin-bottom:0.85em;
+ margin-top:0.85em
+}
+.navigationbar li {
+ display:inline-block;
+ margin-right:5px;
+ position:relative;
+ padding-right:10px;
+ color:#585a5c
+}
+.navigationbar ul:last-of-type li a {
+ color:#404244
+}
+.sectionlist li, .sphinxsidebar li {
+ padding-bottom: 10px;
+ line-height: 1.75em;
+}
+.col-1 ul {
+ margin-bottom:1.56em
+}
+.bodywrapper li {
+ margin-top:0.5em;
+ line-height:1.25em
+}
+.bodywrapper li.level2 {
+ margin-left:10px;
+ margin-top:0.4em;
+ font-size:0.9375em;
+}
+.bodywrapper p,
+.bodywrapper dd {
+ line-height:1.25em;
+ margin:1em 0 1em;
+ color:#404244
+}
+.bodywrapper b {
+ font-weight:600
+}
+.body ul,.body ol {
+ /* margin-bottom:1.5em */
+}
+.bodywrapper ul ul {
+ margin-top:0.5em
+}
+.bodywrapper .naviNextPrevious {
+ margin-top:25px;
+ max-width:100%
+}
+.naviNextPrevious.headerNavi,
+p.naviNextPrevious + p {
+ display:none
+}
+.nextPage {
+ float:right
+}
+.prevPage:before {
+ content:"< "
+}
+.nextPage:after {
+ content:" >"
+}
+.navigationbar li a {
+ color:#404244
+}
+.navigationbar li:after {
+ color:#404244;
+ content:"›";
+ display:inline-block;
+ font-size:1.5em;
+ line-height:1;
+ position:absolute;
+ right:-2px;
+ top:-4px
+}
+.sub-navigation {
+ margin-top:10px
+}
+.navigationbar li:last-child:after,.sub-navigation li:after {
+ content:none
+}
+.navigationbar {
+ margin-bottom:10px;
+ line-height:1em
+}
+#buildversion {
+ margin-bottom:10px;
+ font-style:italic;
+ font-size:small;
+ float:right
+}
+.copy-notice {
+ width:75%;
+ font-size:0.75em;
+ margin:20px 35px 0 10px;
+ line-height:1.75em;
+ float:right;
+ color:#585a5c
+}
+.copy-notice.index {
+ margin-top:10px;
+ float:none
+}
+li a.active {
+ color:#585a5c
+}
+.flowList {
+ padding:25px
+}
+.flowListDiv dl {
+ -webkit-column-count:1;
+ -moz-column-count:1;
+ column-count:1
+}
+.flowList dd {
+ display:inline-block;
+ margin-left:10px;
+ width:90%;
+ line-height:1.15em;
+ overflow-x:hidden;
+ text-overflow:ellipsis
+}
+.alphaChar {
+ font-size:2em;
+ position:absolute
+}
+.flowList.odd {
+ background-color:#f9f9f9
+}
+.body ul>li,.doc-column ul>li {
+ list-style-image:url("list_arrow.png");
+ margin-left:15px;
+ color:#404244;
+ margin-top:0.65em;
+ line-height:1em
+}
+.bodywrapper table p {
+ margin:0px;
+ padding:0px
+}
+.bodywrapper table p {
+ margin:0px;
+ padding:0px;
+ min-height:1.25em
+}
+.bodywrapper .qmldoc {
+ margin-top:0.75em
+}
+.body h2 {
+ margin-top: 1.5em;
+ font-size:1.75em
+}
+.body h3 {
+ font-size:1.35em
+}
+.body h4 {
+ font-size:1.15em
+}
+.body p img {
+ margin-top:0.75em;
+ max-width:100%
+}
+.body .border img {
+ box-shadow:3px 3px 8px 3px rgba(200,200,200,0.5)
+}
+.body .border .player {
+ box-shadow:3px 3px 8px 3px rgba(200,200,200,0.5)
+}
+.body p.figCaption {
+ transform:translateY(-30px);
+ color:#606366;
+ font-size:95%;
+ margin-left:3px;
+ font-style:italic
+}
+.body table {
+ width:initial;
+ vertical-align:initial
+}
+table .odd {
+ background-color:#f9f9f9
+}
+table thead {
+ text-align:left;
+ padding-left:20px
+}
+table,table td,table th {
+ border:1px solid #eee
+}
+table td,table th {
+ padding:5px 20px;
+ line-height:1.3
+}
+.body .fixed table td {
+ min-width:50%;
+ width:50%
+}
+table.alignedsummary,table.propsummary {
+ width:initial
+}
+table.valuelist td.tblval {
+ font-size:0.75em
+}
+div.main_index .row {
+ border-bottom:10px solid #f3f3f4
+}
+div.main_index .row {
+ position:relative
+}
+div.main_index .row>div {
+ display:inline-block;
+ width:50%;
+ vertical-align:top;
+ padding:2em 3em;
+ -webkit-box-sizing:border-box;
+ -moz-box-sizing:border-box;
+ -ms-box-sizing:border-box;
+ box-sizing:border-box
+}
+div.main_index h2 {
+ font-size:2.1875em;
+ margin-bottom:1em
+}
+#search_bar {
+ width:40%;
+ float:right
+}
+div.main_index .row:after {
+ content:"";
+ position:absolute;
+ top:0;
+ right:50%;
+ height:100%;
+ width:10px;
+ background-color:#f3f3f4
+}
+div.table {
+ overflow-x:auto
+}
+.body tr > td > pre {
+ font-size:0.75em
+}
+p.qt_commercial {
+ border:3px solid #5caa15;
+ margin:0 auto;
+ padding:15px;
+ width:28%;
+ text-align:center;
+ clear:both
+}
+h1.qt_commercial {
+ padding:20px;
+ background-color:#5caa15;
+ display:inline;
+ float:right;
+ font-size:1.25em;
+ line-height:1.25em;
+ height:1.25em;
+ color:#fff
+}
+div.qt_commercial {
+ border-top:5px solid #5caa15;
+ margin-bottom:50px
+}
+div.pre {
+ position:relative;
+ height:auto
+}
+pre, .LegaleseLeft {
+ background-color:#222840;
+ color:#fff;
+ display:block;
+ font-family:monospace;
+ line-height:1.5;
+ overflow-x:auto;
+ margin-bottom:25px;
+ padding:25px;
+ margin-top:0.75em;
+ font-size: .8em;
+}
+.bodywrapper .LegaleseLeft p {
+ color:#fff;
+ white-space: pre-wrap
+}
+pre .str,code .str {
+ color:#aaaaaa
+}
+pre .kwd,code .kwd {
+ color:#ffff55
+}
+pre .com,code .com {
+ color:#55ffff
+}
+pre .typ,code .typ {
+ color:#4f9d08
+}
+pre a .typ,code a .typ {
+ color:#21be2b
+}
+pre .lit,code .lit {
+ color:#ff55ff
+}
+pre .pun,code .pun {
+ color:#fff
+}
+pre .pln,code .pln {
+ color:#fff
+}
+@media print {
+ pre {
+ background-color:#eee !important
+ }
+ pre .str,code .str {
+ color:#060
+ }
+ pre .kwd,code .kwd{
+ color:#006;
+ font-weight:bold
+ }
+ pre .com,code .com {
+ color:#600
+ }
+ pre .typ,code .typ {
+ color:#404;
+ font-weight:bold
+ }
+ pre .lit,code .lit {
+ color:#044
+ }
+ pre .pun,code .pun {
+ color:#440
+ }
+ pre .pln,code .pln {
+ color:#000
+ }
+}
+pre.wrap {
+ white-space:pre-wrap
+}
+pre span.wrap {
+ display:none;
+ background:url("wrap.png") no-repeat;
+ right:0;
+ top:2px;
+ position:absolute;
+ width:20px;
+ height:14px;
+ margin:4px;
+ opacity:0.65
+}
+
+span.pre {
+ color: #09102d;
+}
+
+span.wrap:hover {
+ opacity:1
+}
+span.wrap:active {
+ opacity:0.75
+}
+.copy_text {
+ background-color:#46a2da;
+ color:#fff;
+ border:2px solid #46a2da;
+ padding:10px 16px;
+ margin-left:-10px;
+ margin-top:-50px;
+ position:absolute;
+ opacity:0;
+ cursor:pointer;
+ float:right
+}
+.copy_text:hover {
+ background-color:#fff;
+ color:#46a2da
+}
+code,.codelike {
+ font-family:monospace;
+}
+#detailed-description .function dt > code,
+#detailed-description .function dt > em {
+ font-weight:bold
+}
+h3.fn code {
+ font-size:0.75em;
+ float:right;
+ background-color:#eee;
+ padding:3px;
+ margin: 3px 0 0 20px
+}
+pre:hover>.copy_text {
+ display:inline-block;
+ opacity:1;
+ transition:0.5s ease
+}
+#main_title_bar {
+ background:url("pyside-logo.png") no-repeat;
+ background-size:100%;
+ width:366px;
+ height:86px;
+ margin:15px 0 15px 0
+}
+#main_title_bar h1 {
+ visibility:hidden
+}
+#main_title_bar .search_bar {
+ letter-spacing:normal;
+ width:50%;
+ display:inline-block;
+ -webkit-box-sizing:border-box;
+ -moz-box-sizing:border-box;
+ -ms-box-sizing:border-box;
+ box-sizing:border-box;
+ vertical-align:middle
+}
+#main_title_bar h1 {
+ letter-spacing:normal;
+ display:inline-block;
+ -webkit-box-sizing:border-box;
+ -moz-box-sizing:border-box;
+ -ms-box-sizing:border-box;
+ box-sizing:border-box;
+ vertical-align:middle
+}
+#main_title_bar .search_bar * {
+ letter-spacing:normal;
+ padding:0;
+ margin:0;
+ border:none
+}
+#sidebar-toggle,#toc-toggle {
+ display:none
+}
+@media (max-width: 980px) {
+ body {
+ font-size:calc-em(14px)
+ }
+ #main_title_bar>h1,#main_title_bar .search_bar {
+ width:100%
+ }
+ #main_title_bar .search_bar {
+ margin-bottom:15px
+ }
+ .main {
+ margin-top:0px
+ }
+ .main_index .row {
+ border:none !important
+ }
+ .title {
+ font-size:1.5em;
+ font-weight:400;
+ word-wrap:break-word
+ }
+ .col-1,.body,.naviNextPrevious,.sidebar {
+ padding:10px
+ }
+ .sidebar {
+ position:relative;
+ padding-top:0
+ }
+ .search .sidebar {
+ display:none;
+ visibility:hidden
+ }
+ .col-2 h2,.toc h3,.sidebar-content h2,.sidebar-content h3,.sectionlist h2 {
+ text-align:center;
+ margin-bottom:5px
+ }
+ div.main_index .row:after {
+ content:none
+ }
+ div.main_index .row>div {
+ display:block !important;
+ width:100%;
+ padding:15px;
+ margin:0
+ }
+ .body,.sidebar,.col-1 {
+ width:100%
+ }
+ .sidebar-content,.col-2,.toc {
+ background-color:#fff;
+ margin-bottom:1em;
+ padding:20px
+ }
+ #sidebar-toggle,#toc-toggle {
+ display:block
+ }
+ #sidebar-toggle.collapsed + h2 {
+ display:block
+ }
+ .bodywrapper p {
+ margin-bottom:1em;
+ max-width:100%
+ }
+ table td,table th {
+ padding:5px 5px
+ }
+ .sectionlist {
+ padding:0
+ }
+ .sidebar > .sectionlist {
+ padding:20px
+ }
+ .sectionlist.promo {
+ max-width:46%;
+ margin:0 auto 1em auto;
+ float:left;
+ padding:0 2%
+ }
+ .sidebar .sidebar-content {
+ clear:both
+ }
+ .copy-notice {
+ float:none;
+ width:initial
+ }
+}
+[id]:target > *:first-child,
+dt[id]:target {
+ -webkit-animation:highlighter 3s;
+ animation:highlighter 3s
+}
+@-webkit-keyframes highlighter {
+ 25% {
+ background-color:#d1e8f6;
+ color:#444
+ }
+ 75% {
+ background-color:#d1e8f6;
+ color:#444
+ }
+}
+@keyframes highlighter {
+ 25% {
+ background-color:#d1e8f6;
+ color:#444
+ }
+ 75% {
+ background-color:#d1e8f6;
+ color:#444
+ }
+}
+@-webkit-keyframes copypaste {
+ 25% {
+ opacity:1
+ }
+ 100% {
+ border-radius:10px;
+ margin-top:-50px;
+ opacity:1
+ }
+}
+@keyframes copypaste {
+ 25% {
+ opacity:1
+ }
+ 100% {
+ border-radius:10px;
+ margin-top:-50px;
+ opacity:1
+ }
+}
+#footer {
+ clear:both
+}
+.footer-social i {
+ font-family: "social-icons";
+ font-style: normal;
+ font-size:150%;
+ margin: .55em;
+ color: #cecfd5
+}
+.footer-social i:hover {
+ color: #eee
+}
+.footer-social .icon-twitter:before {
+ content: '\f099'
+}
+.footer-social .icon-facebook:before {
+ content: '\f09a'
+}
+.footer-social .icon-youtube:before {
+ content: '\f16a'
+}
+.menuextraslanguages {
+ display:none;
+ visibility:hidden
+}
+
+input:focus {
+ border-color: #46a2da;
+ box-shadow: 0 0 5px #46a2da;
+ color: #000;
+}
+
+.animation {
+ width: 100%;
+ border-style: none;
+ border-width: 0
+}
+
+.player {
+ width: auto;
+ position: relative;
+ display: table;
+ margin-bottom:1.5em;
+}
+
+.playcontrol {
+ display: none;
+ background: url("play_icon.svg") no-repeat center,
+ linear-gradient(
+ rgba(0,0,0,0.15), rgba(0,0,0,0.15)
+ );
+ background-size: 25%;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 0%;
+ right: 0%;
+ top: 0%;
+ bottom: 0%;
+ margin: auto
+}
+
+/* expand/collapse code sections */
+pre input {
+ display:none;
+ visibility:hidden
+}
+pre label {
+ display:block;
+ margin:-3px 3px 0 -16px;
+ text-align:center;
+ color:#21be2b;
+ float:left;
+}
+pre label:hover {
+ color:#fff
+}
+pre label::before {
+ font-weight:600;
+ font-size:16px;
+ content:"+";
+ display:inline-block;
+ width:16px;
+ height:16px
+}
+#ec_expand {
+ height:16px;
+ overflow:hidden;
+ transition:height 0.35s;
+}
+#ec_expand::before {
+ content:"...*/";
+ color:#aaa;
+ background-color:#3a4055;
+ z-index:99 !important;
+ right:25px;
+ position:absolute
+}
+#ec_toggle:checked ~ #ec_expand {
+ height:initial
+}
+#ec_toggle:checked ~ #ec_expand::before {
+ content:""
+}
+#ec_toggle:checked ~ label::before {
+ content:"-"
+}
+
+/* permalinks */
+h1:hover > .headerlink,
+h2:hover > .plink,
+h2:hover > .headerlink,
+h3:hover > .plink,
+h3:hover > .headerlink,
+h4:hover > .plink,
+h4:hover > .headerlink,
+h5:hover > .plink,
+h5:hover > .headerlink {
+ opacity:1
+}
+a.plink, a.headerlink {
+ opacity: 0;
+ padding-left: 8px;
+ font-size: 0.8em;
+ font-weight: 600;
+ transition: opacity 180ms ease-in-out
+}
+a.plink::before {
+ content:'\00B6'
+}
+
+table.special {
+ border: 3px;
+ padding: 0px;
+ border-collapse: separate;
+ border-spacing: 20px;
+ line-height: 1.5em;
+}
+
+.special p {
+ text-align: center;
+ color: #3a4055;
+}
+
+.special a {
+ display: block;
+ border-bottom: 0;
+ text-decoration: none;
+}
+
+.special a:hover {
+ border-bottom: 0;
+ text-decoration: none;
+}
+
+.special strong {
+ color: #17a81a;
+ font-size: 110%;
+ font-weight: normal;
+}
+
+table.special th,
+table.special td {
+ border: 1px solid #888;
+ padding-top: 14px;
+ padding-bottom: 14px;
+ padding-left: 6px;
+ padding-right: 5px;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -khtml-border-radius: 5px;
+}
+
+.special td:hover {
+ padding-top: 2px;
+ padding-bottom: 2px;
+ border-bottom: 4px solid #2cde85;
+}
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/pysidelogo.png b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/pysidelogo.png
new file mode 100644
index 000000000..3a2f2bd17
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/pysidelogo.png
Binary files differ
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/relbar_bg.png b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/relbar_bg.png
new file mode 100644
index 000000000..4036733a7
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/static/relbar_bg.png
Binary files differ
diff --git a/sources/shiboken6/doc/_themes/pysidedocs_qthelp/theme.conf b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/theme.conf
new file mode 100644
index 000000000..4384b459c
--- /dev/null
+++ b/sources/shiboken6/doc/_themes/pysidedocs_qthelp/theme.conf
@@ -0,0 +1,7 @@
+[theme]
+inherit = default
+stylesheet = pyside.css
+pygments_style = none
+
+[options]
+nosidebar = true
diff --git a/sources/shiboken6/doc/conf.py.in b/sources/shiboken6/doc/conf.py.in
new file mode 100644
index 000000000..b10f33b2a
--- /dev/null
+++ b/sources/shiboken6/doc/conf.py.in
@@ -0,0 +1,211 @@
+# -*- coding: utf-8 -*-
+#
+# Shiboken documentation build configuration file, created by
+# sphinx-quickstart on Wed Apr 22 15:04:20 2009.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use Path(path).resolve() to make it absolute, like shown here.
+sys.path.append('@CMAKE_CURRENT_SOURCE_DIR@')
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig',
+ 'sphinx.ext.coverage', 'sphinx.ext.intersphinx', 'sphinx.ext.todo',
+ 'sphinx.ext.graphviz',
+ 'sphinx.ext.viewcode',
+ 'sphinx_design', 'sphinx_copybutton',
+ 'myst_parser']
+
+myst_enable_extensions = [
+ "amsmath",
+ "colon_fence",
+ "deflist",
+ "dollarmath",
+ "fieldlist",
+ "html_admonition",
+ "html_image",
+ "replacements",
+ "smartquotes",
+ "strikethrough",
+ "substitution",
+ "tasklist",
+]
+myst_heading_anchors = 6
+
+output_format='@DOC_OUTPUT_FORMAT@'
+
+def setup(app):
+ app.add_config_value('output_format','qthelp','env')
+
+rst_epilog = """
+.. |project| replace:: Qt for Python
+.. |pymodname| replace:: Shiboken6
+"""
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_templates']
+
+# The suffix of source filenames.
+source_suffix = {
+ '.rst': 'restructuredtext',
+ '.md': 'markdown',
+}
+
+# The encoding of source files.
+source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Shiboken'
+copyright = u'2024 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 (https://www.gnu.org/licenses/fdl.html) as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.'
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '@BINDING_API_VERSION@'
+# The full version, including alpha/beta/rc tags.
+release = '@BINDING_API_VERSION_FULL@'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_patterns = ['_build',
+ '**README.md']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+pygments_dark_style = "monokai"
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'furo'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+html_theme_options = {
+ "dark_css_variables": {
+ "color-brand-primary": "#2cde85",
+ "color-brand-content": "#2cde85",
+ "color-admonition-title--important": "#2cde85",
+ "color-admonition-title-background--important": "#474b53",
+ "font-stack": "'Titillium Web', sans-serif",
+ },
+ "light_css_variables": {
+ "color-brand-primary": "#27138b",
+ "color-brand-content": "#27138b",
+ "color-admonition-title--important": "#27138b",
+ "font-stack": "'Titillium Web', sans-serif",
+ },
+}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_themes']
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+html_title = "Shiboken"
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = "@CMAKE_CURRENT_SOURCE_DIR@/_static/shiboken.png"
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_static']
+
+html_css_files = [
+ 'css/qt_font.css',
+ 'css/qt_style.css',
+]
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = { '' : ''}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = { 'index' : 'index.html'}
+
+# If false, no module index is generated.
+html_use_modindex = False
+
+# If false, no index is generated.
+html_use_index = False
+
+# If true, the index is split into individual pages for each letter.
+html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = False
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# -- Options for qthelp output --------------------------------------------------
+qthelp_theme = 'pysidedocs_qthelp'
diff --git a/sources/shiboken6/doc/considerations.rst b/sources/shiboken6/doc/considerations.rst
new file mode 100644
index 000000000..ad913e7a6
--- /dev/null
+++ b/sources/shiboken6/doc/considerations.rst
@@ -0,0 +1,196 @@
+.. _words-of-advice:
+
+***************
+Words of Advice
+***************
+
+When writing or using Python bindings there is some things you must keep in mind.
+
+.. _rvalue_references:
+
+Rvalue References
+=================
+
+Normally, no bindings are generated for functions taking rvalue references.
+Experimental support has been added in 6.6. The functions need to be explicitly
+specified using the :ref:`add-function`, :ref:`declare-function` or
+:ref:`function` elements. For :ref:`value-type` objects, this does not have any
+implications since the arguments are copied in the generated code and the copy
+is moved from. For :ref:`object-type` objects however, it means that the object
+instance is moved from and should no longer be referenced.
+
+.. _duck-punching-and-virtual-methods:
+
+Duck punching and virtual methods
+=================================
+
+The combination of duck punching, the practice of altering class characteristics
+of already instantiated objects, and virtual methods of wrapped C++ classes, can
+be tricky. That was an optimistic statement.
+
+Let's see duck punching in action for educational purposes.
+
+.. code-block:: python
+
+ import types
+ import Binding
+
+ obj = Binding.CppClass()
+
+ # CppClass has a virtual method called 'virtualMethod',
+ # but we don't like it anymore.
+ def myVirtualMethod(self_obj, arg):
+ pass
+
+ obj.virtualMethod = types.MethodType(myVirtualMethod, obj, Binding.CppClass)
+
+
+If some C++ code happens to call `CppClass::virtualMethod(...)` on the C++ object
+held by "obj" Python object, the new duck punched "virtualMethod" method will be
+properly called. That happens because the underlying C++ object is in fact an instance
+of a generated C++ class that inherits from `CppClass`, let's call it `CppClassWrapper`,
+responsible for receiving the C++ virtual method calls and finding out the proper Python
+override to which handle such a call.
+
+Now that you know this, consider the case when C++ has a factory method that gives you
+new C++ objects originated somewhere in C++-land, in opposition to the ones generated in
+Python-land by the usage of class constructors, like in the example above.
+
+Brief interruption to show what I was saying:
+
+.. code-block:: python
+
+ import types
+ import Binding
+
+ obj = Binding.createCppClass()
+ def myVirtualMethod(self_obj, arg):
+ pass
+
+ # Punching a dead duck...
+ obj.virtualMethod = types.MethodType(myVirtualMethod, obj, Binding.CppClass)
+
+
+The `Binding.createCppClass()` factory method is just an example, C++ created objects
+can pop out for a number of other reasons. Objects created this way have a Python wrapper
+holding them as usual, but the object held is not a `CppClassWrapper`, but a regular
+`CppClass`. All virtual method calls originated in C++ will stay in C++ and never reach
+a Python virtual method overridden via duck punching.
+
+Although duck punching is an interesting Python feature, it don't mix well with wrapped
+C++ virtual methods, specially when you can't tell the origin of every single wrapped
+C++ object. In summary: don't do it!
+
+
+.. _pyside-old-style-class:
+
+Python old style classes and PySide
+===================================
+
+Because of some architectural decisions and deprecated Python types.
+Since PySide 1.1 old style classes are not supported with multiple inheritance.
+
+Below you can check the examples:
+
+Example with old style class:
+
+.. code-block:: python
+
+ from PySide6 import QtCore
+
+ class MyOldStyleObject:
+ pass
+
+ class MyObject(QtCore, MyOldStyleObject):
+ pass
+
+
+this example will raise a 'TypeError' due to the limitation on PySide, to fix
+this you will need use the new style class:
+
+
+.. code-block:: python
+
+ from PySide6 import QtCore
+
+ class MyOldStyleObject(object):
+ pass
+
+ class MyObject(QtCore, MyOldStyleObject):
+ pass
+
+
+All classes used for multiple inheritance with other PySide types need to have
+'object' as base class.
+
+**************************
+Frequently Asked Questions
+**************************
+
+This is a list of Frequently Asked Questions about |project|.
+Feel free to suggest new entries using our `Mailing list`_ or our IRC channel!
+
+General
+=======
+
+What is Shiboken?
+-----------------
+
+Shiboken is a Generator Runner plugin that outputs C++ code for CPython
+extensions.
+The first version of PySide had source code based on Boost templates.
+It was easier to produce code but a paradigm change was needed, as the next
+question explains.
+
+
+Why did you switch from Boost.Python to Shiboken?
+-------------------------------------------------
+
+The main reason was the size reduction. Boost.Python makes excessive use of
+templates resulting in a significant increase of the binaries size.
+On the other hand, as Shiboken generates CPython code, the resulting binaries
+are smaller.
+
+Creating bindings
+=================
+
+Can I wrap non-Qt libraries?
+----------------------------
+
+Yes. Check Shiboken source code for an example (libsample).
+
+
+Is there any runtime dependency on the generated binding?
+---------------------------------------------------------
+
+Yes. Only libshiboken, and the obvious Python interpreter
+and the C++ library that is being wrapped.
+
+What do I have to do to create my bindings?
+-------------------------------------------
+
+Most of the work is already done by the API Extractor.
+The developer creates a :std:doc:`typesystem <typesystem>`
+file with any customization wanted in
+the generated code, like removing classes or changing method signatures.
+The generator will output the *.h* and *.cpp* files with the CPython code that
+will wrap the target library for python.
+
+
+Is there any recommended build system?
+--------------------------------------
+
+Both API Extractor and generator uses and recommends the CMake build system.
+
+Can I write closed-source bindings with the generator?
+------------------------------------------------------
+
+Yes, as long as you use a LGPL version of Qt, due to runtime requirements.
+
+What is 'inject code'?
+----------------------
+
+That's how we call customized code that will be *injected* into the
+generated at specific locations. They are specified inside the typesystem.
+
+.. _`Mailing list`: https://lists.qt-project.org/mailman/listinfo/pyside
diff --git a/sources/shiboken6/doc/dependency-pyside.svg b/sources/shiboken6/doc/dependency-pyside.svg
new file mode 100644
index 000000000..786bdb8a6
--- /dev/null
+++ b/sources/shiboken6/doc/dependency-pyside.svg
@@ -0,0 +1,527 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="900"
+ height="560"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="dependency-pyside.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/tmp/dependency-pyside.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path3270"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.8,0,0,0.8,10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lend"
+ style="overflow:visible">
+ <path
+ id="path3679"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.79440331"
+ inkscape:cx="-36.66006"
+ inkscape:cy="372.04724"
+ inkscape:document-units="px"
+ inkscape:current-layer="svg2"
+ showgrid="false"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-width="1278"
+ inkscape:window-height="949"
+ inkscape:window-x="0"
+ inkscape:window-y="0">
+ <sodipodi:guide
+ orientation="1,0"
+ position="384.28571,590"
+ id="guide2601" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="678.57143,491.42857"
+ id="guide2603" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="78.571429,257.14286"
+ id="guide2605" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="93.571429,280.71429"
+ id="guide7565" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="148.57143,216.42857"
+ id="guide7567" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-78.088635,-190.95252)" />
+ <g
+ id="g5394"
+ transform="translate(6.1314759,14.304617)">
+ <g
+ transform="translate(-65.84289,-190.95252)"
+ id="g5205">
+ <g
+ id="g5171">
+ <rect
+ rx="9.3643799"
+ y="338.7739"
+ x="678.57141"
+ height="73.281754"
+ width="274.54263"
+ id="rect2393"
+ style="fill:#aaeeff;fill-rule:evenodd;stroke:#006078;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="13.104657" />
+ <text
+ id="text2395"
+ y="355.93701"
+ x="683.46539"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="355.93701"
+ x="683.46539"
+ id="tspan2397"
+ sodipodi:role="line">boost::python</tspan></text>
+ <text
+ id="text2399"
+ y="371.60172"
+ x="683.46539"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="371.60172"
+ x="683.46539"
+ id="tspan2401"
+ sodipodi:role="line">1.38.0</tspan></text>
+ <text
+ id="text2403"
+ y="387.14166"
+ x="683.46539"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2435"
+ y="387.14166"
+ x="683.46539"
+ sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ id="text2413"
+ y="402.4646"
+ x="683.46539"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="402.4646"
+ x="683.46539"
+ id="tspan2415"
+ sodipodi:role="line">Boost Software License 1.0</tspan></text>
+ </g>
+ <g
+ id="g5193">
+ <rect
+ rx="8.3239012"
+ y="342.86383"
+ x="78.571426"
+ height="73.282379"
+ width="274.18781"
+ id="rect2417"
+ style="fill:#b3ff80;fill-rule:evenodd;stroke:#2a7800;stroke-width:0.96558368px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="9.2689295" />
+ <text
+ id="text2419"
+ y="359.67014"
+ x="88.822823"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="359.67014"
+ x="88.822823"
+ id="tspan2421"
+ sodipodi:role="line">Qt 4.5</tspan></text>
+ <text
+ id="text2423"
+ y="375.33484"
+ x="88.822823"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="375.33484"
+ x="88.822823"
+ id="tspan2425"
+ sodipodi:role="line">4.5</tspan></text>
+ <text
+ id="text2427"
+ y="390.87479"
+ x="88.822823"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="390.87479"
+ x="88.822823"
+ id="tspan2429"
+ sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ id="text2431"
+ y="400.84058"
+ x="88.822823"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="400.84058"
+ x="88.822823"
+ id="tspan2433"
+ sodipodi:role="line">GNU General Public License v3 /</tspan><tspan
+ y="411.1687"
+ x="88.822823"
+ sodipodi:role="line"
+ id="tspan2472">GNU Lesser General Public Licence v2.1</tspan></text>
+ </g>
+ <g
+ id="g5120">
+ <rect
+ y="496.43558"
+ x="384.28571"
+ height="73.281754"
+ width="274.54263"
+ id="rect2441"
+ style="fill:#e9ddaf;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="13.104635"
+ rx="10.404889" />
+ <text
+ id="text2443"
+ y="513.59869"
+ x="389.17969"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="513.59869"
+ x="389.17969"
+ id="tspan2445"
+ sodipodi:role="line">libapiextractor</tspan></text>
+ <text
+ id="text2447"
+ y="529.26337"
+ x="389.17969"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="529.26337"
+ x="389.17969"
+ id="tspan2449"
+ sodipodi:role="line">0.1</tspan></text>
+ <text
+ id="text2451"
+ y="544.80334"
+ x="389.17969"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2453"
+ y="544.80334"
+ x="389.17969"
+ sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ id="text2455"
+ y="560.12628"
+ x="389.17969"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="560.12628"
+ x="389.17969"
+ id="tspan2457"
+ sodipodi:role="line">LGPL version 2.1</tspan></text>
+ </g>
+ <g
+ id="g5131">
+ <rect
+ y="340.72134"
+ x="384.28571"
+ height="73.281754"
+ width="274.54263"
+ id="rect2459"
+ style="fill:#e9ddaf;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="10.309408"
+ rx="9.3644047" />
+ <text
+ id="text2461"
+ y="357.88449"
+ x="389.17969"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="357.88449"
+ x="389.17969"
+ id="tspan2463"
+ sodipodi:role="line">BoostPythonGenerator</tspan></text>
+ <text
+ id="text2465"
+ y="373.54916"
+ x="389.17969"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="373.54916"
+ x="389.17969"
+ id="tspan2467"
+ sodipodi:role="line">0.1</tspan></text>
+ <text
+ id="text2469"
+ y="389.08914"
+ x="389.17969"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2471"
+ y="389.08914"
+ x="389.17969"
+ sodipodi:role="line">Binary executable - compile-time</tspan></text>
+ <text
+ id="text2473"
+ y="404.41208"
+ x="389.17969"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="404.41208"
+ x="389.17969"
+ id="tspan2475"
+ sodipodi:role="line">LGPL version 2.1</tspan></text>
+ </g>
+ <g
+ id="g5142">
+ <rect
+ y="191.43562"
+ x="384.28571"
+ height="73.281754"
+ width="274.54263"
+ id="rect2523"
+ style="fill:#e9ddaf;fill-opacity:1;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="14.285714" />
+ <text
+ id="text2525"
+ y="208.59874"
+ x="389.17966"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="208.59874"
+ x="389.17966"
+ id="tspan2527"
+ sodipodi:role="line">Qt Python bindings</tspan></text>
+ <text
+ id="text2529"
+ y="224.26344"
+ x="389.17966"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="224.26344"
+ x="389.17966"
+ id="tspan2531"
+ sodipodi:role="line">0.1</tspan></text>
+ <text
+ id="text2533"
+ y="239.80339"
+ x="389.17966"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2535"
+ y="239.80339"
+ x="389.17966"
+ sodipodi:role="line">Target</tspan></text>
+ <text
+ id="text2537"
+ y="255.12633"
+ x="389.17966"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="255.12633"
+ x="389.17966"
+ id="tspan2539"
+ sodipodi:role="line">LGPL version 2.1</tspan></text>
+ </g>
+ <g
+ id="g5182">
+ <rect
+ rx="10.404877"
+ y="648.57843"
+ x="384.28571"
+ height="73.281754"
+ width="274.54263"
+ id="rect2563"
+ style="fill:#aaeeff;fill-rule:evenodd;stroke:#006078;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ ry="11.287985" />
+ <text
+ id="text2565"
+ y="665.74158"
+ x="389.17969"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="665.74158"
+ x="389.17969"
+ id="tspan2567"
+ sodipodi:role="line">boost::graph</tspan></text>
+ <text
+ id="text2569"
+ y="681.40625"
+ x="389.17969"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="681.40625"
+ x="389.17969"
+ id="tspan2571"
+ sodipodi:role="line">1.38.0</tspan></text>
+ <text
+ id="text2573"
+ y="696.94623"
+ x="389.17969"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan2575"
+ y="696.94623"
+ x="389.17969"
+ sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ id="text2577"
+ y="712.26917"
+ x="389.17969"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="712.26917"
+ x="389.17969"
+ id="tspan2579"
+ sodipodi:role="line">Boost Software License 1.0</tspan></text>
+ </g>
+ </g>
+ <path
+ inkscape:connector-type="polyline"
+ id="path2869"
+ d="M 212.85114,151.42852 L 368.56822,74.247959"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <path
+ inkscape:connector-type="polyline"
+ id="path2871"
+ d="M 663.60462,147.33826 L 517.61788,74.247959"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <path
+ inkscape:connector-type="polyline"
+ id="path2877"
+ d="M 443.4684,149.28571 L 443.46839,74.247959"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <path
+ inkscape:connector-type="polyline"
+ id="path2879"
+ d="M 443.4684,304.99994 L 443.4684,223.53367"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <path
+ inkscape:connector-type="polyline"
+ id="path2881"
+ d="M 443.4684,457.14279 L 443.4684,379.2479"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-mid:none;marker-end:none;stroke-opacity:1" />
+ <rect
+ ry="17.142857"
+ y="293.85626"
+ x="0.48279184"
+ height="124.28571"
+ width="211.42857"
+ id="rect7541"
+ style="fill:#e3e2db;stroke:#000000;stroke-opacity:1" />
+ <text
+ id="text7543"
+ y="325.44049"
+ x="70.482788"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="325.44049"
+ x="70.482788"
+ id="tspan7545"
+ sodipodi:role="line">Boost</tspan></text>
+ <text
+ id="text7547"
+ y="358.37042"
+ x="70.482788"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="358.37042"
+ x="70.482788"
+ id="tspan7549"
+ sodipodi:role="line">Qt Software</tspan></text>
+ <text
+ id="text7551"
+ y="394.07593"
+ x="70.482788"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="394.07593"
+ x="70.482788"
+ id="tspan7553"
+ sodipodi:role="line">INdT/Nokia</tspan></text>
+ <rect
+ ry="6.4285707"
+ y="307.24911"
+ x="15.482792"
+ height="22.5"
+ width="43.163269"
+ id="rect7555"
+ style="fill:#aaeeff;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1" />
+ <rect
+ ry="6.4285707"
+ y="341.17767"
+ x="15.482792"
+ height="22.5"
+ width="43.163269"
+ id="rect7561"
+ style="fill:#b3ff80;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1" />
+ <rect
+ ry="6.4285707"
+ y="376.17767"
+ x="15.482792"
+ height="22.5"
+ width="43.163269"
+ id="rect7563"
+ style="fill:#e9ddaf;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/sources/shiboken6/doc/examples/index.rst b/sources/shiboken6/doc/examples/index.rst
new file mode 100644
index 000000000..e3575bc06
--- /dev/null
+++ b/sources/shiboken6/doc/examples/index.rst
@@ -0,0 +1,23 @@
+Examples
+========
+
+C++ examples
+------------
+
+.. grid:: 1 4 4 4
+ :gutter: 2
+
+ .. grid-item-card:: Sample Binding
+ :class-item: cover-img
+ :link: ../../examples/example_samplebinding_samplebinding.html
+ :img-top: ../images/icecream.png
+
+ .. grid-item-card:: Scriptable Application
+ :class-item: cover-img
+ :link: ../../examples/example_scriptableapplication_scriptableapplication.html
+ :img-top: ../../../_images/example_no_image.png
+
+ .. grid-item-card:: Widget Binding
+ :class-item: cover-img
+ :link: ../../examples/example_widgetbinding_widgetbinding.html
+ :img-top: ../../../_images/example_no_image.png
diff --git a/sources/shiboken6/doc/gettingstarted.rst b/sources/shiboken6/doc/gettingstarted.rst
new file mode 100644
index 000000000..cad49086d
--- /dev/null
+++ b/sources/shiboken6/doc/gettingstarted.rst
@@ -0,0 +1,74 @@
+Getting started
+===============
+
+Building from source
+--------------------
+
+This step is focused on building Shiboken from source, both the Generator and Python module.
+Please notice that these are built when you are building PySide from source too, so there is no
+need to continue if you already have a built PySide.
+
+General Requirements
+^^^^^^^^^^^^^^^^^^^^
+
+* **Python**: 3.7+
+* **Qt:** 6.0+
+* **libclang:** The libclang library, recommended: version 10 for 6.0+.
+ Prebuilt versions of it can be `downloaded here`_.
+* **CMake:** 3.1+ is needed.
+
+.. _downloaded here: https://download.qt.io/development_releases/prebuilt/libclang/
+
+Simple build
+^^^^^^^^^^^^
+
+If you need only Shiboken Generator, a simple build run would look like this::
+
+ # For the required libraries (this will also build the shiboken6 python module)
+ python setup.py install --qtpaths=/path/to/qtpaths \
+ --build-tests \
+ --verbose-build \
+ --internal-build-type=shiboken6
+
+ # For the executable
+ python setup.py install --qtpaths=/path/to/qtpaths \
+ --build-tests \
+ --verbose-build \
+ --internal-build-type=shiboken6-generator
+
+The same can be used for the module, changing the value of ``internal-build-type`` to
+``shiboken6-module``.
+
+.. warning:: If you are planning to use PySide too, for examples like
+ 'scriptableapplication' you need to have build it as well. The main issue is
+ that your PySide and Shiboken needs to be build using the same dependencies
+ from Qt and libclang.
+
+Using the wheels
+----------------
+
+Installing ``pyside6`` or ``shiboken6`` from pip **does not** install ``shiboken6_generator``,
+because the wheels are not on PyPi.
+
+You can get the ``shiboken6_generator`` wheels from Qt servers, and you can still install it
+via ``pip``::
+
+ pip install \
+ --index-url=https://download.qt.io/official_releases/QtForPython/ \
+ --trusted-host download.qt.io \
+ shiboken6 pyside6 shiboken6_generator
+
+
+The ``whl`` package cannot automatically discover in your system the location for:
+
+* Clang installation,
+* Qt location (indicated by the path of the ``qtpaths`` tool) with the same
+ version/build as the one described in the wheel,
+* Qt libraries with the same package version.
+
+So using this process requires you to manually modify the variables:
+
+* ``CLANG_INSTALL_DIR`` must be set to where the libraries are,
+* ``PATH`` must include the location for the ``qtpaths`` tool with the same Qt
+ version as the package,
+* ``LD_LIBRARY_PATH`` including the Qt libraries and Clang libraries paths.
diff --git a/sources/shiboken6/doc/images/.directory b/sources/shiboken6/doc/images/.directory
new file mode 100644
index 000000000..e65475f65
--- /dev/null
+++ b/sources/shiboken6/doc/images/.directory
@@ -0,0 +1,3 @@
+[Dolphin]
+ShowPreview=true
+Timestamp=2009,5,5,17,43,26
diff --git a/sources/shiboken6/doc/images/bindinggen-development.png b/sources/shiboken6/doc/images/bindinggen-development.png
new file mode 100644
index 000000000..5931b126a
--- /dev/null
+++ b/sources/shiboken6/doc/images/bindinggen-development.png
Binary files differ
diff --git a/sources/shiboken6/doc/images/bindinggen-development.svg b/sources/shiboken6/doc/images/bindinggen-development.svg
new file mode 100644
index 000000000..591e1f2d1
--- /dev/null
+++ b/sources/shiboken6/doc/images/bindinggen-development.svg
@@ -0,0 +1,542 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="640"
+ height="200"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.92.2 2405546, 2018-03-11"
+ version="1.0"
+ sodipodi:docname="bindinggen-development.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="bindinggen-development.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="EmptyDiamondL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="EmptyDiamondL"
+ style="overflow:visible">
+ <path
+ id="path3930"
+ d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(0.8,0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="EmptyTriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="EmptyTriangleInL"
+ style="overflow:visible">
+ <path
+ id="path3975"
+ d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.8,0,0,-0.8,4.8,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Sstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Sstart"
+ style="overflow:visible">
+ <path
+ id="path3835"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.2,0,0,0.2,1.2,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Mend"
+ style="overflow:visible">
+ <path
+ id="path3832"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.4,0,0,-0.4,-4,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Tail"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Tail"
+ style="overflow:visible">
+ <g
+ id="g3859"
+ transform="scale(-1.2,-1.2)">
+ <path
+ id="path3861"
+ d="M -3.8048674,-3.9585227 L 0.54352094,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3863"
+ d="M -1.2866832,-3.9585227 L 3.0617053,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3865"
+ d="M 1.3053582,-3.9585227 L 5.6537466,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3867"
+ d="M -3.8048674,4.1775838 L 0.54352094,0.21974226"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3869"
+ d="M -1.2866832,4.1775838 L 3.0617053,0.21974226"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ <path
+ id="path3871"
+ d="M 1.3053582,4.1775838 L 5.6537466,0.21974226"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" />
+ </g>
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend"
+ style="overflow:visible">
+ <path
+ id="path3636"
+ style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.76787377"
+ inkscape:cx="286.61779"
+ inkscape:cy="101.18182"
+ inkscape:document-units="px"
+ inkscape:current-layer="g5440"
+ showgrid="false"
+ inkscape:window-width="1116"
+ inkscape:window-height="1042"
+ inkscape:window-x="10"
+ inkscape:window-y="28"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-maximized="0">
+ <sodipodi:guide
+ orientation="1,0"
+ position="-557.55608,678.10875"
+ id="guide7299"
+ inkscape:locked="false" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-1758.7331,-2056.8567)">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3229"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:'Bitstream Vera Sans';fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="translate(4.1137413,-2.3429609)"><flowRegion
+ id="flowRegion3231"><rect
+ id="rect3233"
+ width="125.74072"
+ height="40.5849"
+ x="388.45547"
+ y="279.5423" /></flowRegion><flowPara
+ id="flowPara3235"
+ style="font-size:40px;line-height:1.25"> </flowPara></flowRoot> <g
+ id="g5658"
+ transform="translate(6.5767925,7.0112479)">
+ <g
+ transform="matrix(0,-1,1,0,697.50638,3244.256)"
+ id="g5624"
+ style="">
+ <g
+ id="g5626"
+ transform="matrix(0,-1,1,0,-294.81158,2953.0504)"
+ style="">
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path5628"
+ d="m 1586.5317,1348.2858 0.091,41.5266"
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ d="m 1586.7489,1389.4756 7.9979,-9.1068"
+ id="path5630"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ d="m 1586.6031,1389.5063 -7.9979,-9.1069"
+ id="path5632"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ transform="matrix(0,-1,1,0,908.50929,3242.9612)"
+ id="g5648"
+ style="">
+ <g
+ id="g5650"
+ transform="matrix(0,-1,1,0,-294.81158,2953.0504)"
+ style="">
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path5652"
+ d="m 1586.5317,1348.2858 0.091,41.5266"
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ d="m 1586.7489,1389.4756 7.9979,-9.1068"
+ id="path5654"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ d="m 1586.6031,1389.5063 -7.9979,-9.1069"
+ id="path5656"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5634"
+ style="">
+ <g
+ id="g6271"
+ transform="translate(1086.3689,746.93837)"
+ style="">
+ <g
+ transform="matrix(0,-1,1,0,-294.81158,2953.0504)"
+ id="g6252"
+ style="">
+ <path
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ d="m 1586.5317,1300.2858 0.091,89.5266"
+ id="path11089"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path2758"
+ d="m 1586.7489,1389.4756 7.9979,-9.1068"
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path2760"
+ d="m 1586.6031,1389.5063 -7.9979,-9.1069"
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ <g
+ id="g5641"
+ style="">
+ <g
+ id="g5465"
+ transform="translate(874.42628,746.93837)"
+ style="">
+ <g
+ transform="matrix(0,-1,1,0,-294.81158,2953.0504)"
+ id="g5467"
+ style="">
+ <path
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ d="m 1586.5317,1300.2858 0.091,89.5266"
+ id="path5469"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path5471"
+ d="m 1586.7489,1389.4756 7.9979,-9.1068"
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-type="polyline"
+ id="path5473"
+ d="m 1586.6031,1389.5063 -7.9979,-9.1069"
+ style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:none"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(-194.79968,-212.08495)"
+ id="g5440">
+ <path
+ style="fill:#41cd52;fill-opacity:1;stroke:none;stroke-width:2.18747473;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 2378.6251,2292.247 v 66.9548 h 171.1068 l 14.8788,-14.8788 v -66.9549 h -171.1068 z"
+ id="path3715-5-6-7-9-8-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:0%;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.29069424px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+ x="2471.614"
+ y="2309.093"
+ id="text5174"><tspan
+ sodipodi:role="line"
+ x="2471.614"
+ y="2309.093"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:24px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.29069424px;"
+ id="tspan953">Qt for Python</tspan><tspan
+ id="tspan6109"
+ sodipodi:role="line"
+ x="2471.614"
+ y="2339.093"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.29069424px;">(generated code)</tspan></text>
+ <path
+ style="fill:#6b7080;fill-opacity:1;stroke:none;stroke-width:2.18747473;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 2166.5963,2292.247 v 66.9548 h 171.1068 l 14.8788,-14.8788 v -66.9549 h -171.1068 z"
+ id="path3715-5-6-7-9-8-7-9-94"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:0%;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.50930572px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+ x="2259.1294"
+ y="2311.0505"
+ id="text3627"
+ transform="scale(1.0000266,0.9999734)"><tspan
+ id="tspan3697"
+ sodipodi:role="line"
+ x="2259.1294"
+ y="2311.0505"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.50930572px;">generator</tspan><tspan
+ sodipodi:role="line"
+ x="2259.1294"
+ y="2341.0505"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.50930572px;"
+ id="tspan2464">front-end</tspan></text>
+ <path
+ style="fill:#6b7080;fill-opacity:1;stroke:none;stroke-width:2.18747473;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 1959.8625,2292.2469 v 66.9548 h 171.1068 l 14.8788,-14.8788 v -66.9549 h -171.1068 z"
+ id="path3715-5-6-7-9-8-7-9-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <text
+ id="text3168"
+ y="2326.4568"
+ x="2052.7678"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:0%;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.65129721px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.65129721px;"
+ y="2326.4568"
+ x="2052.7678"
+ sodipodi:role="line"
+ id="tspan5424">API Extractor</tspan></text>
+ <path
+ style="fill:#9d9faa;fill-opacity:1;stroke:none;stroke-width:2.18747473;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 2378.6251,2393.0867 v 66.9548 h 171.1068 l 14.8788,-14.8788 v -66.9549 h -171.1068 z"
+ id="path3715-5-6-7-9-8-7-9-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <text
+ id="text3487"
+ y="2410.3647"
+ x="2471.614"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:0%;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.44197154px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+ xml:space="preserve"><tspan
+ id="tspan2509"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:24px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.44197154px;"
+ y="2410.3647"
+ x="2471.614"
+ sodipodi:role="line">typesystem</tspan><tspan
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.44197154px;"
+ y="2440.3647"
+ x="2471.614"
+ sodipodi:role="line"
+ id="tspan5432">(handwritten)</tspan></text>
+ <path
+ style="fill:#9d9faa;fill-opacity:1;stroke:none;stroke-width:2.18747473;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 2166.5963,2394.0075 v 66.9548 h 171.1068 l 14.8788,-14.8788 v -66.9549 h -171.1068 z"
+ id="path3715-5-6-7-9-8-7-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:0%;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.58586931px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+ x="2259.5852"
+ y="2412.0415"
+ id="text2735"><tspan
+ sodipodi:role="line"
+ x="2259.5852"
+ y="2412.0415"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:24px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.58586931px;"
+ id="tspan2737">injected code</tspan><tspan
+ id="tspan2743"
+ sodipodi:role="line"
+ x="2259.5852"
+ y="2442.0415"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.58586931px;">(handwritten)</tspan></text>
+ </g>
+ <g
+ transform="translate(-102.30216,-279.71223)"
+ id="g5541"
+ style="stroke:none">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f28888;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5535"
+ sodipodi:cx="255.10791"
+ sodipodi:cy="326.69064"
+ sodipodi:rx="38.848923"
+ sodipodi:ry="38.848923"
+ d="m 293.95683,326.69064 a 38.848923,38.848923 0 0 1 -38.84892,38.84893 38.848923,38.848923 0 0 1 -38.84892,-38.84893 38.848923,38.848923 0 0 1 38.84892,-38.84892 38.848923,38.848923 0 0 1 38.84892,38.84892 z"
+ transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;line-height:0%;font-family:Titillium;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'Titillium, Normal';font-stretch:normal;font-variant:normal;font-size:26.66666667px;text-anchor:start;text-align:start;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
+ x="1946.3259"
+ y="2435.7"
+ id="text5537"><tspan
+ sodipodi:role="line"
+ id="tspan5539"
+ x="1946.3259"
+ y="2435.7"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.66666667px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';text-anchor:start;text-align:start;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;stroke:none">1</tspan></text>
+ </g>
+ <g
+ transform="translate(52.589867,-352.69787)"
+ id="g5546"
+ style="stroke:none">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f28888;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5548"
+ sodipodi:cx="255.10791"
+ sodipodi:cy="326.69064"
+ sodipodi:rx="38.848923"
+ sodipodi:ry="38.848923"
+ d="m 293.95683,326.69064 a 38.848923,38.848923 0 0 1 -38.84892,38.84893 38.848923,38.848923 0 0 1 -38.84892,-38.84893 38.848923,38.848923 0 0 1 38.84892,-38.84892 38.848923,38.848923 0 0 1 38.84892,38.84892 z"
+ transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;line-height:0%;font-family:Titillium;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'Titillium, Normal';font-stretch:normal;font-variant:normal;font-size:26.66666667px;text-anchor:start;text-align:start;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
+ x="1946.3259"
+ y="2435.7"
+ id="text5550"><tspan
+ sodipodi:role="line"
+ id="tspan5552"
+ x="1946.3259"
+ y="2435.7"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.66666667px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';text-anchor:start;text-align:start;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;stroke:none">2</tspan></text>
+ </g>
+ <g
+ transform="translate(200.4676,-222.96766)"
+ id="g5554"
+ style="stroke:none">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f28888;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5556"
+ sodipodi:cx="255.10791"
+ sodipodi:cy="326.69064"
+ sodipodi:rx="38.848923"
+ sodipodi:ry="38.848923"
+ d="m 293.95683,326.69064 a 38.848923,38.848923 0 0 1 -38.84892,38.84893 38.848923,38.848923 0 0 1 -38.84892,-38.84893 38.848923,38.848923 0 0 1 38.84892,-38.84892 38.848923,38.848923 0 0 1 38.84892,38.84892 z"
+ transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;line-height:0%;font-family:Titillium;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'Titillium, Normal';font-stretch:normal;font-variant:normal;font-size:26.66666667px;text-anchor:start;text-align:start;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
+ x="1946.3259"
+ y="2435.7"
+ id="text5558"><tspan
+ sodipodi:role="line"
+ id="tspan5560"
+ x="1946.3259"
+ y="2435.7"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.66666667px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';text-anchor:start;text-align:start;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;stroke:none">3</tspan></text>
+ </g>
+ <g
+ transform="translate(413.633,-206.84535)"
+ id="g5562"
+ style="stroke:none">
+ <path
+ sodipodi:type="arc"
+ style="fill:#f28888;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5564"
+ sodipodi:cx="255.10791"
+ sodipodi:cy="326.69064"
+ sodipodi:rx="38.848923"
+ sodipodi:ry="38.848923"
+ d="m 293.95683,326.69064 a 38.848923,38.848923 0 0 1 -38.84892,38.84893 38.848923,38.848923 0 0 1 -38.84892,-38.84893 38.848923,38.848923 0 0 1 38.84892,-38.84892 38.848923,38.848923 0 0 1 38.84892,38.84892 z"
+ transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;line-height:0%;font-family:Titillium;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'Titillium, Normal';font-stretch:normal;font-variant:normal;font-size:26.66666667px;text-anchor:start;text-align:start;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
+ x="1946.3259"
+ y="2435.7"
+ id="text5566"><tspan
+ sodipodi:role="line"
+ id="tspan5568"
+ x="1946.3259"
+ y="2435.7"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.66666667px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Normal';text-anchor:start;text-align:start;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;stroke:none">4</tspan></text>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/sources/shiboken6/doc/images/converter.png b/sources/shiboken6/doc/images/converter.png
new file mode 100644
index 000000000..3935fdc60
--- /dev/null
+++ b/sources/shiboken6/doc/images/converter.png
Binary files differ
diff --git a/sources/shiboken6/doc/images/converter.svg b/sources/shiboken6/doc/images/converter.svg
new file mode 100644
index 000000000..2df5c88e5
--- /dev/null
+++ b/sources/shiboken6/doc/images/converter.svg
@@ -0,0 +1,2227 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="908.50861"
+ zoomAndPan="magnify"
+ viewBox="0 0 681.38145 434.11857"
+ height="578.82477"
+ preserveAspectRatio="xMidYMid"
+ version="1.0"
+ id="svg5080"
+ sodipodi:docname="converter.svg"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview5082"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ showgrid="false"
+ inkscape:zoom="0.80648148"
+ inkscape:cx="413.52468"
+ inkscape:cy="205.2124"
+ inkscape:window-width="2552"
+ inkscape:window-height="1432"
+ inkscape:window-x="1924"
+ inkscape:window-y="4"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg5080" />
+ <defs
+ id="defs4108">
+ <g
+ id="g4028" />
+ <clipPath
+ id="24985ca8b2">
+ <path
+ d="m 325.10547,297.75 h 159.75 V 405 h -159.75 z m 0,0"
+ clip-rule="nonzero"
+ id="path4030" />
+ </clipPath>
+ <clipPath
+ id="3cea3902db">
+ <path
+ d="m 382.58984,359.24609 h 18 v 11.25 h -18 z m 0,0"
+ clip-rule="nonzero"
+ id="path4033" />
+ </clipPath>
+ <clipPath
+ id="dfab995897">
+ <path
+ d="m 325.10547,473.32031 h 159.75 v 107.25 h -159.75 z m 0,0"
+ clip-rule="nonzero"
+ id="path4036" />
+ </clipPath>
+ <clipPath
+ id="2d1327caba">
+ <path
+ d="m 411.91016,534.82031 h 18 v 11.25 h -18 z m 0,0"
+ clip-rule="nonzero"
+ id="path4039" />
+ </clipPath>
+ <clipPath
+ id="f03e985e13">
+ <path
+ d="m 113,313.11719 h 113.76172 v 76.5 H 113 Z m 0,0"
+ clip-rule="nonzero"
+ id="path4042" />
+ </clipPath>
+ <clipPath
+ id="c71ef1b2fa">
+ <path
+ d="m 112.76172,313.11719 h 114 v 76.5 h -114 z m 0,0"
+ clip-rule="nonzero"
+ id="path4045" />
+ </clipPath>
+ <clipPath
+ id="3bddcdf684">
+ <path
+ d="m 593.35156,488.69141 h 114 v 76.5 h -114 z m 0,0"
+ clip-rule="nonzero"
+ id="path4048" />
+ </clipPath>
+ <clipPath
+ id="cd19a8dfa8">
+ <path
+ d="m 588,313.11719 h 113.98828 v 76.5 H 588 Z m 0,0"
+ clip-rule="nonzero"
+ id="path4051" />
+ </clipPath>
+ <clipPath
+ id="61b05d6a70">
+ <path
+ d="m 125,427 h 89.71094 v 60 H 125 Z m 0,0"
+ clip-rule="nonzero"
+ id="path4054" />
+ </clipPath>
+ <clipPath
+ id="ea42d02648">
+ <path
+ d="m 124.77344,426.82031 h 89.9375 v 60.35547 h -89.9375 z m 0,0"
+ clip-rule="nonzero"
+ id="path4057" />
+ </clipPath>
+ <clipPath
+ id="84bd6662f0">
+ <path
+ d="m 125,497 h 89.71094 v 60 H 125 Z m 0,0"
+ clip-rule="nonzero"
+ id="path4060" />
+ </clipPath>
+ <clipPath
+ id="728d290ff8">
+ <path
+ d="m 124.77344,496.94922 h 89.9375 v 60.35547 h -89.9375 z m 0,0"
+ clip-rule="nonzero"
+ id="path4063" />
+ </clipPath>
+ <clipPath
+ id="00b091b271">
+ <path
+ d="m 125,567 h 89.71094 v 60 H 125 Z m 0,0"
+ clip-rule="nonzero"
+ id="path4066" />
+ </clipPath>
+ <clipPath
+ id="be13ebcaaa">
+ <path
+ d="m 124.77344,566.78125 h 89.9375 v 60.35156 h -89.9375 z m 0,0"
+ clip-rule="nonzero"
+ id="path4069" />
+ </clipPath>
+ <clipPath
+ id="12ef88673f">
+ <path
+ d="m 242.54687,336.47266 h 66 v 30 h -66 z m 0,0"
+ clip-rule="nonzero"
+ id="path4072" />
+ </clipPath>
+ <clipPath
+ id="4425bd08fe">
+ <path
+ d="m 503.92969,336.47266 h 66 v 30 h -66 z m 0,0"
+ clip-rule="nonzero"
+ id="path4075" />
+ </clipPath>
+ <clipPath
+ id="29f410bb45">
+ <path
+ d="m 503.92969,512.04297 h 66 v 30 h -66 z m 0,0"
+ clip-rule="nonzero"
+ id="path4078" />
+ </clipPath>
+ <clipPath
+ id="8612924f50">
+ <path
+ d="m 236.54297,511.73437 h 66 v 30 h -66 z m 0,0"
+ clip-rule="nonzero"
+ id="path4081" />
+ </clipPath>
+ <clipPath
+ id="9616827f5c">
+ <path
+ d="m 238,451 h 62 v 38 h -62 z m 0,0"
+ clip-rule="nonzero"
+ id="path4084" />
+ </clipPath>
+ <clipPath
+ id="6d6215aef9">
+ <path
+ d="m 246.00781,440.04297 59.81641,27.89453 -12.67969,27.1875 -59.81641,-27.89063 z m 0,0"
+ clip-rule="nonzero"
+ id="path4087" />
+ </clipPath>
+ <clipPath
+ id="506e24dd3d">
+ <path
+ d="m 246.00781,440.04297 59.81641,27.89453 -12.67969,27.1875 -59.81641,-27.89063 z m 0,0"
+ clip-rule="nonzero"
+ id="path4090" />
+ </clipPath>
+ <clipPath
+ id="85c10bb5f0">
+ <path
+ d="m 246.00781,440.04297 59.81641,27.89453 -12.67969,27.1875 -59.81641,-27.89063 z m 0,0"
+ clip-rule="nonzero"
+ id="path4093" />
+ </clipPath>
+ <clipPath
+ id="96382ab88a">
+ <path
+ d="m 238,565 h 62 v 38 h -62 z m 0,0"
+ clip-rule="nonzero"
+ id="path4096" />
+ </clipPath>
+ <clipPath
+ id="8ee2f579d3">
+ <path
+ d="m 233.26953,586.86719 59.81641,-27.89063 12.67578,27.1875 -59.81641,27.89453 z m 0,0"
+ clip-rule="nonzero"
+ id="path4099" />
+ </clipPath>
+ <clipPath
+ id="c24345751d">
+ <path
+ d="m 246.00781,614.18359 59.81641,-27.89062 -12.67969,-27.19141 -59.81641,27.89453 z m 0,0"
+ clip-rule="nonzero"
+ id="path4102" />
+ </clipPath>
+ <clipPath
+ id="6c1dc82097">
+ <path
+ d="m 246.00781,614.18359 59.81641,-27.89062 -12.67969,-27.19141 -59.81641,27.89453 z m 0,0"
+ clip-rule="nonzero"
+ id="path4105" />
+ </clipPath>
+ </defs>
+ <rect
+ x="-1.4210855e-14"
+ width="681.38147"
+ fill="#ffffff"
+ y="-2.8421709e-14"
+ height="434.11859"
+ fill-opacity="1"
+ id="rect4110"
+ style="stroke-width:0.559543" />
+ <path
+ fill="#41cb51"
+ d="M 256.85164,139.32657 V 62.127352 c 0,-0.9336 0.0898,-1.85938 0.27344,-2.77344 0.17968,-0.91406 0.44922,-1.80078 0.80468,-2.66406 0.35547,-0.86328 0.79297,-1.67969 1.3086,-2.45703 0.51562,-0.77344 1.10547,-1.49219 1.76172,-2.15235 0.65625,-0.66015 1.37109,-1.25 2.14453,-1.76562 0.77344,-0.51953 1.58984,-0.95703 2.44922,-1.3125 0.85937,-0.35938 1.74218,-0.62891 2.65625,-0.8086 0.91015,-0.18359 1.83203,-0.27343 2.76172,-0.27343 h 129.44531 c 0.92969,0 1.85156,0.0898 2.76172,0.27343 0.91406,0.17969 1.79687,0.44922 2.65625,0.8086 0.85937,0.35547 1.67578,0.79297 2.44922,1.3125 0.77343,0.51562 1.48828,1.10547 2.14453,1.76562 0.66015,0.66016 1.24609,1.37891 1.76172,2.15235 0.51562,0.77734 0.95312,1.59375 1.30859,2.45703 0.35547,0.86328 0.625,1.75 0.80469,2.66406 0.18359,0.91406 0.27343,1.83984 0.27343,2.77344 v 77.199218 c 0,0.93359 -0.0898,1.85937 -0.27343,2.77343 -0.17969,0.91407 -0.44922,1.80469 -0.80469,2.66407 -0.35547,0.86328 -0.79297,1.68359 -1.30859,2.45703 -0.51563,0.77734 -1.10157,1.49218 -1.76172,2.15234 -0.65625,0.66016 -1.3711,1.25 -2.14453,1.76953 -0.77344,0.51563 -1.58985,0.95313 -2.44922,1.3125 -0.85938,0.35547 -1.74219,0.625 -2.65625,0.8086 -0.91016,0.17968 -1.83203,0.27343 -2.76172,0.27343 H 271.0118 c -0.92969,0 -1.85157,-0.0937 -2.76172,-0.27343 -0.91407,-0.1836 -1.79688,-0.45313 -2.65625,-0.8086 -0.85938,-0.35937 -1.67578,-0.79687 -2.44922,-1.3125 -0.77344,-0.51953 -1.48828,-1.10937 -2.14453,-1.76953 -0.65625,-0.66016 -1.2461,-1.375 -1.76172,-2.15234 -0.51563,-0.77344 -0.95313,-1.59375 -1.3086,-2.45703 -0.35546,-0.85938 -0.625,-1.75 -0.80468,-2.66407 -0.1836,-0.91406 -0.27344,-1.83984 -0.27344,-2.77343 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4116" />
+ <g
+ clip-path="url(#24985ca8b2)"
+ id="g4120"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#41cb51"
+ d="m 484.67187,312.77344 v 77.19922 c 0,0.98437 -0.0937,1.96093 -0.28515,2.92968 -0.19531,0.96875 -0.47656,1.90625 -0.85547,2.82032 -0.375,0.91015 -0.83594,1.77734 -1.38281,2.59765 -0.54688,0.82031 -1.16797,1.57813 -1.86328,2.27735 -0.69532,0.69531 -1.44922,1.32031 -2.26954,1.86718 -0.8164,0.55078 -1.67968,1.01172 -2.58984,1.39063 -0.90625,0.375 -1.84375,0.66015 -2.80859,0.85547 -0.96485,0.1914 -1.9375,0.28906 -2.92188,0.28906 h -129.4375 c -0.98437,0 -1.95703,-0.0977 -2.92187,-0.28906 -0.96485,-0.19532 -1.90235,-0.48047 -2.8086,-0.85547 -0.91015,-0.37891 -1.77343,-0.83985 -2.58984,-1.39063 -0.82031,-0.54687 -1.57422,-1.17187 -2.26953,-1.86718 -0.69531,-0.69922 -1.31641,-1.45704 -1.86328,-2.27735 -0.54688,-0.82031 -1.00782,-1.6875 -1.38282,-2.59765 -0.3789,-0.91407 -0.66015,-1.85157 -0.85546,-2.82032 -0.19141,-0.96875 -0.28516,-1.94531 -0.28516,-2.92968 v -77.19922 c 0,-0.98828 0.0937,-1.96485 0.28516,-2.9336 0.19531,-0.96484 0.47656,-1.90625 0.85546,-2.8164 0.375,-0.91407 0.83594,-1.77735 1.38282,-2.59766 0.54687,-0.82422 1.16797,-1.58203 1.86328,-2.27734 0.69531,-0.69922 1.44922,-1.32422 2.26953,-1.8711 0.81641,-0.54687 1.67969,-1.01172 2.58984,-1.38672 0.90625,-0.3789 1.84375,-0.66406 2.8086,-0.85546 0.96484,-0.19532 1.9375,-0.28907 2.92187,-0.28907 h 129.44141 c 0.98437,0 1.95703,0.0977 2.92187,0.28907 0.96485,0.1914 1.90235,0.47656 2.8086,0.85546 0.91015,0.37891 1.76953,0.83985 2.58984,1.38672 0.81641,0.55078 1.57422,1.17188 2.26953,1.8711 0.69531,0.69531 1.3125,1.45703 1.85938,2.27734 0.54687,0.82031 1.00781,1.68359 1.38281,2.59766 0.37891,0.91015 0.66406,1.85156 0.85547,2.8164 0.1914,0.96875 0.28515,1.94532 0.28515,2.9336 z m -157.76171,77.19922 c 0,0.8789 0.082,1.75 0.2539,2.61328 0.17188,0.85937 0.42578,1.69922 0.76172,2.51172 0.33594,0.8125 0.74609,1.58203 1.23047,2.3164 0.48828,0.73047 1.04297,1.40625 1.66016,2.02735 0.62109,0.62109 1.29687,1.17968 2.02343,1.66796 0.73047,0.48829 1.5,0.89844 2.3086,1.23438 0.80859,0.33984 1.64453,0.59375 2.5039,0.76562 0.85938,0.17188 1.72657,0.25391 2.60547,0.25391 h 129.44141 c 0.875,0 1.74609,-0.082 2.60547,-0.25391 0.85937,-0.17187 1.69531,-0.42578 2.5039,-0.76562 0.8086,-0.33594 1.57813,-0.74609 2.3086,-1.23438 0.72656,-0.48828 1.40234,-1.04687 2.01953,-1.66796 0.62109,-0.6211 1.17578,-1.29688 1.66015,-2.02735 0.48829,-0.73437 0.89844,-1.5039 1.23438,-2.3164 0.33594,-0.8125 0.58984,-1.65235 0.76172,-2.51172 0.16797,-0.86328 0.2539,-1.73438 0.2539,-2.61328 v -77.19922 c 0,-0.87891 -0.0859,-1.75 -0.2539,-2.61328 -0.17188,-0.86329 -0.42578,-1.69922 -0.76172,-2.51172 -0.33594,-0.8125 -0.74609,-1.58594 -1.23438,-2.31641 -0.48437,-0.73047 -1.03906,-1.41016 -1.66015,-2.03125 -0.61719,-0.62109 -1.29297,-1.17578 -2.01953,-1.66406 -0.73047,-0.48828 -1.5,-0.90235 -2.3086,-1.23828 -0.80859,-0.33594 -1.64453,-0.58985 -2.5039,-0.76172 -0.85938,-0.17188 -1.73047,-0.25781 -2.60547,-0.25781 H 340.25781 c -0.8789,0 -1.74609,0.0859 -2.60547,0.25781 -0.85937,0.17187 -1.69531,0.42578 -2.5039,0.76172 -0.8086,0.33593 -1.57813,0.75 -2.3086,1.23828 -0.72656,0.48828 -1.40234,1.04297 -2.02343,1.66406 -0.61719,0.62109 -1.17188,1.30078 -1.66016,2.03125 -0.48438,0.73047 -0.89453,1.50391 -1.23047,2.31641 -0.33594,0.8125 -0.58984,1.64843 -0.76172,2.51172 -0.17187,0.86328 -0.2539,1.73437 -0.2539,2.61328 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4118" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4128"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(334.04375,371.84414)"
+ id="g4126">
+ <g
+ id="g4124">
+ <path
+ d="M 11.0625,-0.234375 C 9.550781,0.0664062 8.191406,0.21875 6.984375,0.21875 5.785156,0.21875 4.816406,0.0546875 4.078125,-0.265625 3.335938,-0.597656 2.765625,-1.113281 2.359375,-1.8125 1.960938,-2.507812 1.6875,-3.304688 1.53125,-4.203125 c -0.15625,-0.90625 -0.234375,-2.03125 -0.234375,-3.375 0,-1.351563 0.078125,-2.488281 0.234375,-3.40625 0.15625,-0.914063 0.429688,-1.722656 0.828125,-2.421875 0.40625,-0.707031 0.972656,-1.222656 1.703125,-1.546875 0.738281,-0.320313 1.691406,-0.484375 2.859375,-0.484375 1.175781,0 2.554687,0.164062 4.140625,0.484375 L 11,-13.53125 c -1.480469,-0.257812 -2.796875,-0.390625 -3.953125,-0.390625 -1.617187,0 -2.683594,0.480469 -3.203125,1.4375 -0.523438,0.960937 -0.78125,2.601563 -0.78125,4.921875 0,1.15625 0.046875,2.089844 0.140625,2.796875 0.09375,0.699219 0.28125,1.328125 0.5625,1.890625 0.28125,0.5625 0.6875,0.96875 1.21875,1.21875 0.53125,0.242188 1.3125,0.359375 2.34375,0.359375 1.039063,0 2.265625,-0.128906 3.671875,-0.390625 z m 0,0"
+ id="path4122" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4136"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(346.00962,371.84414)"
+ id="g4134">
+ <g
+ id="g4132">
+ <path
+ d="M 1.203125,-4.78125 V -6.265625 H 5.375 V -10.5625 h 1.53125 v 4.296875 h 4.203125 V -4.78125 H 6.90625 V -0.4375 H 5.375 v -4.34375 z m 0,0"
+ id="path4130" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4144"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(358.32742,371.84414)"
+ id="g4142">
+ <g
+ id="g4140">
+ <path
+ d="M 1.203125,-4.78125 V -6.265625 H 5.375 V -10.5625 h 1.53125 v 4.296875 h 4.203125 V -4.78125 H 6.90625 V -0.4375 H 5.375 v -4.34375 z m 0,0"
+ id="path4138" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4150"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(370.6414,371.84414)"
+ id="g4148">
+ <g
+ id="g4146" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4156"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(375.48053,371.84414)"
+ id="g4154">
+ <g
+ id="g4152" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4162"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(380.31967,371.84414)"
+ id="g4160">
+ <g
+ id="g4158" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4168"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(385.1588,371.84414)"
+ id="g4166">
+ <g
+ id="g4164" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4174"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(389.99794,371.84414)"
+ id="g4172">
+ <g
+ id="g4170" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4180"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(394.83707,371.84414)"
+ id="g4178">
+ <g
+ id="g4176" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4186"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(399.6762,371.84414)"
+ id="g4184">
+ <g
+ id="g4182" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4192"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(404.51534,371.84414)"
+ id="g4190">
+ <g
+ id="g4188" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4200"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(409.34843,371.84414)"
+ id="g4198">
+ <g
+ id="g4196">
+ <path
+ d="M 7.4375,-5.125 H 3.5625 V 0 H 1.875 v -15.21875 h 5.5625 c 1.65625,0 2.878906,0.40625 3.671875,1.21875 0.789063,0.804688 1.1875,2.03125 1.1875,3.6875 0,3.460938 -1.621094,5.1875 -4.859375,5.1875 z m -3.875,-1.5 h 3.84375 c 2.101562,0 3.15625,-1.226562 3.15625,-3.6875 0,-1.175781 -0.25,-2.039062 -0.75,-2.59375 -0.5,-0.550781 -1.304688,-0.828125 -2.40625,-0.828125 H 3.5625 Z m 0,0"
+ id="path4194" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4208"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(422.39211,371.84414)"
+ id="g4206">
+ <g
+ id="g4204">
+ <path
+ d="m 0.546875,-11 h 1.65625 l 2.75,9.5625 h 0.71875 L 8.453125,-11 H 10.09375 L 5.515625,4.890625 H 3.875 L 5.296875,0 h -1.625 z m 0,0"
+ id="path4202" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4216"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(433.01622,371.84414)"
+ id="g4214">
+ <g
+ id="g4212">
+ <path
+ d="m 7.28125,-9.5625 h -3.5 v 5.25 c 0,1.261719 0.085938,2.089844 0.265625,2.484375 0.1875,0.398437 0.628906,0.59375 1.328125,0.59375 l 1.953125,-0.125 L 7.4375,0 c -0.980469,0.15625 -1.730469,0.234375 -2.25,0.234375 -1.148438,0 -1.9375,-0.2734375 -2.375,-0.828125 -0.4375,-0.5625 -0.65625,-1.625 -0.65625,-3.1875 V -9.5625 H 0.59375 V -11 h 1.5625 v -3.359375 h 1.625 V -11 h 3.5 z m 0,0"
+ id="path4210" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4224"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(440.73684,371.84414)"
+ id="g4222">
+ <g
+ id="g4220">
+ <path
+ d="m 3.234375,0 h -1.65625 v -15.796875 h 1.65625 v 5.40625 c 1.175781,-0.550781 2.304687,-0.828125 3.390625,-0.828125 1.46875,0 2.453125,0.398438 2.953125,1.1875 0.507813,0.792969 0.765625,2.199219 0.765625,4.21875 V 0 H 8.6875 v -5.765625 c 0,-1.519531 -0.152344,-2.5625 -0.453125,-3.125 C 7.929688,-9.460938 7.300781,-9.75 6.34375,-9.75 c -0.929688,0 -1.824219,0.171875 -2.6875,0.515625 L 3.234375,-9.09375 Z m 0,0"
+ id="path4218" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4232"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(452.54873,371.84414)"
+ id="g4230">
+ <g
+ id="g4228">
+ <path
+ d="m 1.09375,-5.515625 c 0,-2.007813 0.359375,-3.460937 1.078125,-4.359375 0.71875,-0.894531 1.929687,-1.34375 3.640625,-1.34375 1.707031,0 2.914062,0.449219 3.625,1.34375 0.71875,0.898438 1.078125,2.351562 1.078125,4.359375 0,2 -0.339844,3.460937 -1.015625,4.375 -0.679688,0.90625 -1.914062,1.359375 -3.703125,1.359375 -1.78125,0 -3.011719,-0.453125 -3.6875,-1.359375 -0.679687,-0.914063 -1.015625,-2.375 -1.015625,-4.375 z m 1.703125,-0.03125 c 0,1.605469 0.191406,2.730469 0.578125,3.375 0.382812,0.648437 1.195312,0.96875 2.4375,0.96875 1.238281,0 2.050781,-0.316406 2.4375,-0.953125 0.382812,-0.644531 0.578125,-1.773438 0.578125,-3.390625 0,-1.613281 -0.214844,-2.722656 -0.640625,-3.328125 -0.429688,-0.613281 -1.21875,-0.921875 -2.375,-0.921875 -1.148438,0 -1.9375,0.308594 -2.375,0.921875 -0.429688,0.605469 -0.640625,1.714844 -0.640625,3.328125 z m 0,0"
+ id="path4226" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4240"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(464.16266,371.84414)"
+ id="g4238">
+ <g
+ id="g4236">
+ <path
+ d="M 3.234375,0 H 1.578125 V -11 H 3.21875 v 0.765625 c 1.1875,-0.65625 2.320312,-0.984375 3.40625,-0.984375 1.46875,0 2.453125,0.398438 2.953125,1.1875 0.507813,0.792969 0.765625,2.199219 0.765625,4.21875 V 0 h -1.625 v -5.765625 c 0,-1.519531 -0.152344,-2.5625 -0.453125,-3.125 C 7.960938,-9.460938 7.320312,-9.75 6.34375,-9.75 c -0.480469,0 -0.980469,0.074219 -1.5,0.21875 -0.523438,0.136719 -0.917969,0.273438 -1.1875,0.40625 l -0.421875,0.1875 z m 0,0"
+ id="path4234" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#3cea3902db)"
+ id="g4244"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#ffffff"
+ d="m 400.46484,364.71094 -7.35156,-5.36328 c -0.11328,-0.082 -0.25,-0.0899 -0.375,-0.0274 -0.0586,0.0312 -0.1875,0.125 -0.1875,0.32031 v 2.9375 c 0,0.17969 -0.14453,0.32813 -0.32031,0.32813 h -9.28516 c -0.17578,0 -0.32031,0.14844 -0.32031,0.33203 v 3.29688 c 0,0.18359 0.14453,0.33203 0.32031,0.33203 h 9.28516 c 0.17578,0 0.32031,0.14843 0.32031,0.32812 v 2.9375 c 0,0.19531 0.12891,0.28906 0.1875,0.32031 0.125,0.0664 0.26172,0.0547 0.375,-0.0273 l 7.35156,-5.36328 c 0.0781,-0.0586 0.0859,-0.14063 0.0859,-0.17578 0,-0.0352 -0.008,-0.11719 -0.0859,-0.17578"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4242" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4252"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(358.72771,337.8254)"
+ id="g4250">
+ <g
+ id="g4248">
+ <path
+ d="m 6.796875,0.234375 c -2.199219,0 -3.695313,-0.601563 -4.484375,-1.8125 -0.78125,-1.21875 -1.171875,-3.21875 -1.171875,-6 0,-2.789063 0.394531,-4.773437 1.1875,-5.953125 0.789063,-1.1875 2.28125,-1.78125 4.46875,-1.78125 1.300781,0 2.738281,0.183594 4.3125,0.546875 l -0.09375,1.984375 c -1.3125,-0.238281 -2.632813,-0.359375 -3.953125,-0.359375 -1.324219,0 -2.21875,0.398437 -2.6875,1.1875 -0.46875,0.78125 -0.703125,2.257813 -0.703125,4.421875 0,2.15625 0.222656,3.632812 0.671875,4.421875 0.457031,0.78125 1.347656,1.171875 2.671875,1.171875 1.320313,0 2.65625,-0.109375 4,-0.328125 l 0.07813,2.03125 c -1.511719,0.3125 -2.945312,0.46875 -4.296875,0.46875 z m 0,0"
+ id="path4246" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4260"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(370.69358,337.8254)"
+ id="g4258">
+ <g
+ id="g4256">
+ <path
+ d="m 2.046875,-9.796875 c 0.757813,-0.957031 2.019531,-1.4375 3.78125,-1.4375 1.757813,0 3.015625,0.480469 3.765625,1.4375 0.757812,0.949219 1.140625,2.375 1.140625,4.28125 0,1.90625 -0.371094,3.34375 -1.109375,4.3125 -0.730469,0.960937 -1.996094,1.4375 -3.796875,1.4375 -1.804687,0 -3.074219,-0.476563 -3.8125,-1.4375 -0.730469,-0.96875 -1.09375,-2.40625 -1.09375,-4.3125 0,-1.90625 0.375,-3.332031 1.125,-4.28125 z M 3.84375,-2.65625 c 0.34375,0.585938 1.003906,0.875 1.984375,0.875 0.976563,0 1.632813,-0.289062 1.96875,-0.875 C 8.140625,-3.25 8.3125,-4.210938 8.3125,-5.546875 c 0,-1.332031 -0.183594,-2.273437 -0.546875,-2.828125 -0.355469,-0.5625 -1,-0.84375 -1.9375,-0.84375 -0.9375,0 -1.589844,0.28125 -1.953125,0.84375 -0.355469,0.554688 -0.53125,1.496094 -0.53125,2.828125 0,1.335937 0.164062,2.296875 0.5,2.890625 z m 0,0"
+ id="path4254" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4268"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(382.3515,337.8254)"
+ id="g4266">
+ <g
+ id="g4264">
+ <path
+ d="M 3.84375,0 H 1.453125 v -11 h 2.375 v 0.6875 c 1.070313,-0.613281 2.082031,-0.921875 3.03125,-0.921875 1.46875,0 2.46875,0.417969 3,1.25 0.539063,0.824219 0.8125,2.1875 0.8125,4.09375 V 0 h -2.375 v -5.828125 c 0,-1.1875 -0.132813,-2.03125 -0.390625,-2.53125 -0.25,-0.5 -0.773438,-0.75 -1.5625,-0.75 -0.75,0 -1.46875,0.148437 -2.15625,0.4375 L 3.84375,-8.53125 Z m 0,0"
+ id="path4262" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4276"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(394.36136,337.8254)"
+ id="g4274">
+ <g
+ id="g4272">
+ <path
+ d="m 0.421875,-11 h 2.5 L 5.03125,-2.046875 H 5.734375 L 7.9375,-11 h 2.453125 L 7.53125,0 H 3.25 Z m 0,0"
+ id="path4270" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4284"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(405.16143,337.8254)"
+ id="g4282">
+ <g
+ id="g4280">
+ <path
+ d="m 9.28125,-1.984375 0.625,-0.0625 0.03125,1.78125 c -1.667969,0.3320312 -3.148438,0.5 -4.4375,0.5 -1.625,0 -2.796875,-0.441406 -3.515625,-1.328125 -0.710937,-0.894531 -1.0625,-2.328125 -1.0625,-4.296875 0,-3.894531 1.59375,-5.84375 4.78125,-5.84375 3.070313,0 4.609375,1.679687 4.609375,5.03125 l -0.15625,1.71875 h -6.8125 c 0.00781,0.90625 0.207031,1.574219 0.59375,2 0.382812,0.429687 1.097656,0.640625 2.140625,0.640625 1.039063,0 2.109375,-0.046875 3.203125,-0.140625 z M 7.96875,-6.34375 c 0,-1.082031 -0.171875,-1.835938 -0.515625,-2.265625 -0.34375,-0.4375 -0.929687,-0.65625 -1.75,-0.65625 -0.824219,0 -1.421875,0.230469 -1.796875,0.6875 -0.375,0.460937 -0.570312,1.203125 -0.578125,2.234375 z m 0,0"
+ id="path4278" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4292"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(416.33545,337.8254)"
+ id="g4290">
+ <g
+ id="g4288">
+ <path
+ d="m 1.453125,0 v -11 h 2.375 v 1.3125 c 1.25,-0.800781 2.492187,-1.316406 3.734375,-1.546875 v 2.390625 c -1.261719,0.25 -2.339844,0.574219 -3.234375,0.96875 L 3.84375,-7.671875 V 0 Z m 0,0"
+ id="path4286" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4300"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(424.27603,337.8254)"
+ id="g4298">
+ <g
+ id="g4296">
+ <path
+ d="M 7.375,-8.953125 H 4.328125 v 4.84375 c 0,0.898437 0.066406,1.492187 0.203125,1.78125 0.132812,0.292969 0.472656,0.4375 1.015625,0.4375 l 1.796875,-0.0625 0.109375,1.90625 c -0.980469,0.1875 -1.726563,0.28125 -2.234375,0.28125 -1.25,0 -2.109375,-0.28125 -2.578125,-0.84375 -0.460937,-0.570313 -0.6875,-1.648437 -0.6875,-3.234375 V -8.953125 H 0.546875 V -11 h 1.40625 v -3.1875 h 2.375 V -11 H 7.375 Z m 0,0"
+ id="path4294" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4308"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(432.15063,337.8254)"
+ id="g4306">
+ <g
+ id="g4304">
+ <path
+ d="m 9.28125,-1.984375 0.625,-0.0625 0.03125,1.78125 c -1.667969,0.3320312 -3.148438,0.5 -4.4375,0.5 -1.625,0 -2.796875,-0.441406 -3.515625,-1.328125 -0.710937,-0.894531 -1.0625,-2.328125 -1.0625,-4.296875 0,-3.894531 1.59375,-5.84375 4.78125,-5.84375 3.070313,0 4.609375,1.679687 4.609375,5.03125 l -0.15625,1.71875 h -6.8125 c 0.00781,0.90625 0.207031,1.574219 0.59375,2 0.382812,0.429687 1.097656,0.640625 2.140625,0.640625 1.039063,0 2.109375,-0.046875 3.203125,-0.140625 z M 7.96875,-6.34375 c 0,-1.082031 -0.171875,-1.835938 -0.515625,-2.265625 -0.34375,-0.4375 -0.929687,-0.65625 -1.75,-0.65625 -0.824219,0 -1.421875,0.230469 -1.796875,0.6875 -0.375,0.460937 -0.570312,1.203125 -0.578125,2.234375 z m 0,0"
+ id="path4302" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4316"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(443.32464,337.8254)"
+ id="g4314">
+ <g
+ id="g4312">
+ <path
+ d="m 1.453125,0 v -11 h 2.375 v 1.3125 c 1.25,-0.800781 2.492187,-1.316406 3.734375,-1.546875 v 2.390625 c -1.261719,0.25 -2.339844,0.574219 -3.234375,0.96875 L 3.84375,-7.671875 V 0 Z m 0,0"
+ id="path4310" />
+ </g>
+ </g>
+ </g>
+ <path
+ fill="#41cb51"
+ d="m 256.85164,314.90078 v -77.19921 c 0,-0.9336 0.0898,-1.85938 0.27344,-2.77344 0.17968,-0.91406 0.44922,-1.80469 0.80468,-2.66406 0.35547,-0.86329 0.79297,-1.6836 1.3086,-2.45704 0.51562,-0.77734 1.10547,-1.49218 1.76172,-2.15234 0.65625,-0.66016 1.37109,-1.25 2.14453,-1.76953 0.77344,-0.51563 1.58984,-0.95313 2.44922,-1.3125 0.85937,-0.35547 1.74218,-0.625 2.65625,-0.80859 0.91015,-0.17969 1.83203,-0.27344 2.76172,-0.27344 h 129.44531 c 0.92969,0 1.85156,0.0937 2.76172,0.27344 0.91406,0.18359 1.79687,0.45312 2.65625,0.80859 0.85937,0.35937 1.67578,0.79687 2.44922,1.3125 0.77343,0.51953 1.48828,1.10937 2.14453,1.76953 0.66015,0.66016 1.24609,1.375 1.76172,2.15234 0.51562,0.77344 0.95312,1.59375 1.30859,2.45704 0.35547,0.85937 0.625,1.75 0.80469,2.66406 0.18359,0.91406 0.27343,1.83984 0.27343,2.77344 v 77.19921 c 0,0.9336 -0.0898,1.85938 -0.27343,2.77344 -0.17969,0.91406 -0.44922,1.80078 -0.80469,2.66406 -0.35547,0.86329 -0.79297,1.67969 -1.30859,2.45704 -0.51563,0.77343 -1.10157,1.49218 -1.76172,2.15234 -0.65625,0.66016 -1.3711,1.25 -2.14453,1.76562 -0.77344,0.51954 -1.58985,0.95704 -2.44922,1.3125 -0.85938,0.35938 -1.74219,0.62891 -2.65625,0.8086 -0.91016,0.18359 -1.83203,0.27344 -2.76172,0.27344 H 271.0118 c -0.92969,0 -1.85157,-0.0899 -2.76172,-0.27344 -0.91407,-0.17969 -1.79688,-0.44922 -2.65625,-0.8086 -0.85938,-0.35546 -1.67578,-0.79296 -2.44922,-1.3125 -0.77344,-0.51562 -1.48828,-1.10546 -2.14453,-1.76562 -0.65625,-0.66016 -1.2461,-1.37891 -1.76172,-2.15234 -0.51563,-0.77735 -0.95313,-1.59375 -1.3086,-2.45704 -0.35546,-0.86328 -0.625,-1.75 -0.80468,-2.66406 -0.1836,-0.91406 -0.27344,-1.83984 -0.27344,-2.77344 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4318" />
+ <g
+ clip-path="url(#dfab995897)"
+ id="g4322"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#41cb51"
+ d="m 484.67187,488.34766 v 77.19531 c 0,0.98828 -0.0937,1.96484 -0.28515,2.93359 -0.19531,0.96875 -0.47656,1.90625 -0.85547,2.82031 -0.375,0.91016 -0.83594,1.77735 -1.38281,2.59766 -0.54688,0.82031 -1.16797,1.57813 -1.86328,2.27734 -0.69532,0.69532 -1.44922,1.32032 -2.26954,1.86719 -0.8164,0.54688 -1.67968,1.01172 -2.58984,1.39063 -0.90625,0.375 -1.84375,0.66015 -2.80859,0.85156 -0.96485,0.19531 -1.9375,0.28906 -2.92188,0.28906 h -129.4375 c -0.98437,0 -1.95703,-0.0937 -2.92187,-0.28906 -0.96485,-0.19141 -1.90235,-0.47656 -2.8086,-0.85156 -0.91015,-0.37891 -1.77343,-0.84375 -2.58984,-1.39063 -0.82031,-0.54687 -1.57422,-1.17187 -2.26953,-1.86719 -0.69531,-0.69921 -1.31641,-1.45703 -1.86328,-2.27734 -0.54688,-0.82031 -1.00782,-1.6875 -1.38282,-2.59766 -0.3789,-0.91406 -0.66015,-1.85156 -0.85546,-2.82031 -0.19141,-0.96875 -0.28516,-1.94531 -0.28516,-2.93359 v -77.19531 c 0,-0.98829 0.0937,-1.96485 0.28516,-2.9336 0.19531,-0.96875 0.47656,-1.90625 0.85546,-2.82031 0.375,-0.91016 0.83594,-1.77734 1.38282,-2.59766 0.54687,-0.82031 1.16797,-1.57812 1.86328,-2.27734 0.69531,-0.69531 1.44922,-1.32031 2.26953,-1.86719 0.81641,-0.54687 1.67969,-1.01172 2.58984,-1.39062 0.90625,-0.375 1.84375,-0.66016 2.8086,-0.85547 0.96484,-0.19141 1.9375,-0.28516 2.92187,-0.28516 h 129.44141 c 0.98437,0 1.95703,0.0937 2.92187,0.28906 0.96485,0.19141 1.90235,0.47657 2.8086,0.85547 0.91015,0.375 1.76953,0.83985 2.58984,1.38672 0.81641,0.55078 1.57422,1.17188 2.26953,1.8711 0.69531,0.69531 1.3125,1.45703 1.85938,2.27734 0.54687,0.82031 1.00781,1.68359 1.38281,2.59766 0.37891,0.91015 0.66406,1.84765 0.85547,2.8164 0.1914,0.96875 0.28515,1.94531 0.28515,2.9336 z m -157.76171,77.19531 c 0,0.88281 0.082,1.7539 0.2539,2.61328 0.17188,0.86328 0.42578,1.70312 0.76172,2.51562 0.33594,0.8125 0.74609,1.58204 1.23047,2.3125 0.48828,0.73438 1.04297,1.41016 1.66016,2.03125 0.62109,0.6211 1.29687,1.17579 2.02343,1.66407 0.73047,0.48828 1.5,0.90234 2.3086,1.23828 0.80859,0.33594 1.64453,0.58984 2.5039,0.76172 0.85938,0.17187 1.72657,0.25781 2.60547,0.25781 h 129.44141 c 0.875,0 1.74609,-0.0859 2.60547,-0.25781 0.85937,-0.17188 1.69531,-0.42578 2.5039,-0.76172 0.8086,-0.33594 1.57813,-0.75 2.3086,-1.23828 0.72656,-0.48828 1.40234,-1.04297 2.01953,-1.66407 0.62109,-0.62109 1.17578,-1.29687 1.66015,-2.03125 0.48829,-0.73046 0.89844,-1.5 1.23438,-2.3125 0.33594,-0.8125 0.58984,-1.65234 0.76172,-2.51562 0.16797,-0.85938 0.2539,-1.73047 0.2539,-2.61328 v -77.19531 c 0,-0.88282 -0.0859,-1.75391 -0.2539,-2.61329 -0.17188,-0.86328 -0.42578,-1.70312 -0.76172,-2.51562 -0.33594,-0.8125 -0.74609,-1.58203 -1.23438,-2.3125 -0.48437,-0.73438 -1.03906,-1.41016 -1.66015,-2.03125 -0.61719,-0.62109 -1.29297,-1.17578 -2.01953,-1.66406 -0.73047,-0.48828 -1.5,-0.90235 -2.3086,-1.23828 -0.80859,-0.33594 -1.64453,-0.58985 -2.5039,-0.76172 -0.85938,-0.17188 -1.73047,-0.25782 -2.60547,-0.25782 H 340.25781 c -0.8789,0 -1.74609,0.0859 -2.60547,0.25782 -0.85937,0.17187 -1.69531,0.42578 -2.5039,0.76172 -0.8086,0.33593 -1.57813,0.75 -2.3086,1.23828 -0.72656,0.48828 -1.40234,1.04297 -2.02343,1.66406 -0.61719,0.62109 -1.17188,1.29687 -1.66016,2.03125 -0.48438,0.73047 -0.89453,1.5 -1.23047,2.3125 -0.33594,0.8125 -0.58984,1.65234 -0.76172,2.51562 -0.17187,0.85938 -0.2539,1.73047 -0.2539,2.61329 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4320" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4330"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(336.46249,547.41743)"
+ id="g4328">
+ <g
+ id="g4326">
+ <path
+ d="M 7.4375,-5.125 H 3.5625 V 0 H 1.875 v -15.21875 h 5.5625 c 1.65625,0 2.878906,0.40625 3.671875,1.21875 0.789063,0.804688 1.1875,2.03125 1.1875,3.6875 0,3.460938 -1.621094,5.1875 -4.859375,5.1875 z m -3.875,-1.5 h 3.84375 c 2.101562,0 3.15625,-1.226562 3.15625,-3.6875 0,-1.175781 -0.25,-2.039062 -0.75,-2.59375 -0.5,-0.550781 -1.304688,-0.828125 -2.40625,-0.828125 H 3.5625 Z m 0,0"
+ id="path4324" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4338"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(349.50617,547.41743)"
+ id="g4336">
+ <g
+ id="g4334">
+ <path
+ d="m 0.546875,-11 h 1.65625 l 2.75,9.5625 h 0.71875 L 8.453125,-11 H 10.09375 L 5.515625,4.890625 H 3.875 L 5.296875,0 h -1.625 z m 0,0"
+ id="path4332" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4346"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(360.13028,547.41743)"
+ id="g4344">
+ <g
+ id="g4342">
+ <path
+ d="m 7.28125,-9.5625 h -3.5 v 5.25 c 0,1.261719 0.085938,2.089844 0.265625,2.484375 0.1875,0.398437 0.628906,0.59375 1.328125,0.59375 l 1.953125,-0.125 L 7.4375,0 c -0.980469,0.15625 -1.730469,0.234375 -2.25,0.234375 -1.148438,0 -1.9375,-0.2734375 -2.375,-0.828125 -0.4375,-0.5625 -0.65625,-1.625 -0.65625,-3.1875 V -9.5625 H 0.59375 V -11 h 1.5625 v -3.359375 h 1.625 V -11 h 3.5 z m 0,0"
+ id="path4340" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4354"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(367.8509,547.41743)"
+ id="g4352">
+ <g
+ id="g4350">
+ <path
+ d="m 3.234375,0 h -1.65625 v -15.796875 h 1.65625 v 5.40625 c 1.175781,-0.550781 2.304687,-0.828125 3.390625,-0.828125 1.46875,0 2.453125,0.398438 2.953125,1.1875 0.507813,0.792969 0.765625,2.199219 0.765625,4.21875 V 0 H 8.6875 v -5.765625 c 0,-1.519531 -0.152344,-2.5625 -0.453125,-3.125 C 7.929688,-9.460938 7.300781,-9.75 6.34375,-9.75 c -0.929688,0 -1.824219,0.171875 -2.6875,0.515625 L 3.234375,-9.09375 Z m 0,0"
+ id="path4348" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4362"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(379.6628,547.41743)"
+ id="g4360">
+ <g
+ id="g4358">
+ <path
+ d="m 1.09375,-5.515625 c 0,-2.007813 0.359375,-3.460937 1.078125,-4.359375 0.71875,-0.894531 1.929687,-1.34375 3.640625,-1.34375 1.707031,0 2.914062,0.449219 3.625,1.34375 0.71875,0.898438 1.078125,2.351562 1.078125,4.359375 0,2 -0.339844,3.460937 -1.015625,4.375 -0.679688,0.90625 -1.914062,1.359375 -3.703125,1.359375 -1.78125,0 -3.011719,-0.453125 -3.6875,-1.359375 -0.679687,-0.914063 -1.015625,-2.375 -1.015625,-4.375 z m 1.703125,-0.03125 c 0,1.605469 0.191406,2.730469 0.578125,3.375 0.382812,0.648437 1.195312,0.96875 2.4375,0.96875 1.238281,0 2.050781,-0.316406 2.4375,-0.953125 0.382812,-0.644531 0.578125,-1.773438 0.578125,-3.390625 0,-1.613281 -0.214844,-2.722656 -0.640625,-3.328125 -0.429688,-0.613281 -1.21875,-0.921875 -2.375,-0.921875 -1.148438,0 -1.9375,0.308594 -2.375,0.921875 -0.429688,0.605469 -0.640625,1.714844 -0.640625,3.328125 z m 0,0"
+ id="path4356" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4370"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(391.27673,547.41743)"
+ id="g4368">
+ <g
+ id="g4366">
+ <path
+ d="M 3.234375,0 H 1.578125 V -11 H 3.21875 v 0.765625 c 1.1875,-0.65625 2.320312,-0.984375 3.40625,-0.984375 1.46875,0 2.453125,0.398438 2.953125,1.1875 0.507813,0.792969 0.765625,2.199219 0.765625,4.21875 V 0 h -1.625 v -5.765625 c 0,-1.519531 -0.152344,-2.5625 -0.453125,-3.125 C 7.960938,-9.460938 7.320312,-9.75 6.34375,-9.75 c -0.480469,0 -0.980469,0.074219 -1.5,0.21875 -0.523438,0.136719 -0.917969,0.273438 -1.1875,0.40625 l -0.421875,0.1875 z m 0,0"
+ id="path4364" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4376"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(403.08359,547.41743)"
+ id="g4374">
+ <g
+ id="g4372" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4382"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(407.92272,547.41743)"
+ id="g4380">
+ <g
+ id="g4378" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4388"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(412.76185,547.41743)"
+ id="g4386">
+ <g
+ id="g4384" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4394"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(417.60099,547.41743)"
+ id="g4392">
+ <g
+ id="g4390" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4400"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(422.44012,547.41743)"
+ id="g4398">
+ <g
+ id="g4396" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4406"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(427.27926,547.41743)"
+ id="g4404">
+ <g
+ id="g4402" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4412"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(432.11839,547.41743)"
+ id="g4410">
+ <g
+ id="g4408" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4420"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(436.95077,547.41743)"
+ id="g4418">
+ <g
+ id="g4416">
+ <path
+ d="M 11.0625,-0.234375 C 9.550781,0.0664062 8.191406,0.21875 6.984375,0.21875 5.785156,0.21875 4.816406,0.0546875 4.078125,-0.265625 3.335938,-0.597656 2.765625,-1.113281 2.359375,-1.8125 1.960938,-2.507812 1.6875,-3.304688 1.53125,-4.203125 c -0.15625,-0.90625 -0.234375,-2.03125 -0.234375,-3.375 0,-1.351563 0.078125,-2.488281 0.234375,-3.40625 0.15625,-0.914063 0.429688,-1.722656 0.828125,-2.421875 0.40625,-0.707031 0.972656,-1.222656 1.703125,-1.546875 0.738281,-0.320313 1.691406,-0.484375 2.859375,-0.484375 1.175781,0 2.554687,0.164062 4.140625,0.484375 L 11,-13.53125 c -1.480469,-0.257812 -2.796875,-0.390625 -3.953125,-0.390625 -1.617187,0 -2.683594,0.480469 -3.203125,1.4375 -0.523438,0.960937 -0.78125,2.601563 -0.78125,4.921875 0,1.15625 0.046875,2.089844 0.140625,2.796875 0.09375,0.699219 0.28125,1.328125 0.5625,1.890625 0.28125,0.5625 0.6875,0.96875 1.21875,1.21875 0.53125,0.242188 1.3125,0.359375 2.34375,0.359375 1.039063,0 2.265625,-0.128906 3.671875,-0.390625 z m 0,0"
+ id="path4414" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4428"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(448.91665,547.41743)"
+ id="g4426">
+ <g
+ id="g4424">
+ <path
+ d="M 1.203125,-4.78125 V -6.265625 H 5.375 V -10.5625 h 1.53125 v 4.296875 h 4.203125 V -4.78125 H 6.90625 V -0.4375 H 5.375 v -4.34375 z m 0,0"
+ id="path4422" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4436"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(461.23445,547.41743)"
+ id="g4434">
+ <g
+ id="g4432">
+ <path
+ d="M 1.203125,-4.78125 V -6.265625 H 5.375 V -10.5625 h 1.53125 v 4.296875 h 4.203125 V -4.78125 H 6.90625 V -0.4375 H 5.375 v -4.34375 z m 0,0"
+ id="path4430" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#2d1327caba)"
+ id="g4440"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#ffffff"
+ d="m 429.78516,540.28516 -7.35157,-5.36329 c -0.10937,-0.082 -0.25,-0.0937 -0.375,-0.0273 -0.0547,0.0312 -0.1875,0.125 -0.1875,0.32031 v 2.9375 c 0,0.17969 -0.14453,0.32813 -0.32031,0.32813 h -9.28516 c -0.17578,0 -0.32031,0.14844 -0.32031,0.32812 v 3.30078 c 0,0.1836 0.14453,0.33204 0.32031,0.33204 h 9.28516 c 0.17578,0 0.32031,0.14453 0.32031,0.32812 v 2.9375 c 0,0.19531 0.13282,0.28906 0.1875,0.32031 0.125,0.0625 0.26563,0.0547 0.375,-0.0273 l 7.35157,-5.36328 c 0.0781,-0.0586 0.0898,-0.14453 0.0898,-0.17578 0,-0.0352 -0.0117,-0.11719 -0.0898,-0.17578"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4438" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4448"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(358.72771,513.39871)"
+ id="g4446">
+ <g
+ id="g4444">
+ <path
+ d="m 6.796875,0.234375 c -2.199219,0 -3.695313,-0.601563 -4.484375,-1.8125 -0.78125,-1.21875 -1.171875,-3.21875 -1.171875,-6 0,-2.789063 0.394531,-4.773437 1.1875,-5.953125 0.789063,-1.1875 2.28125,-1.78125 4.46875,-1.78125 1.300781,0 2.738281,0.183594 4.3125,0.546875 l -0.09375,1.984375 c -1.3125,-0.238281 -2.632813,-0.359375 -3.953125,-0.359375 -1.324219,0 -2.21875,0.398437 -2.6875,1.1875 -0.46875,0.78125 -0.703125,2.257813 -0.703125,4.421875 0,2.15625 0.222656,3.632812 0.671875,4.421875 0.457031,0.78125 1.347656,1.171875 2.671875,1.171875 1.320313,0 2.65625,-0.109375 4,-0.328125 l 0.07813,2.03125 c -1.511719,0.3125 -2.945312,0.46875 -4.296875,0.46875 z m 0,0"
+ id="path4442" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4456"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(370.69358,513.39871)"
+ id="g4454">
+ <g
+ id="g4452">
+ <path
+ d="m 2.046875,-9.796875 c 0.757813,-0.957031 2.019531,-1.4375 3.78125,-1.4375 1.757813,0 3.015625,0.480469 3.765625,1.4375 0.757812,0.949219 1.140625,2.375 1.140625,4.28125 0,1.90625 -0.371094,3.34375 -1.109375,4.3125 -0.730469,0.960937 -1.996094,1.4375 -3.796875,1.4375 -1.804687,0 -3.074219,-0.476563 -3.8125,-1.4375 -0.730469,-0.96875 -1.09375,-2.40625 -1.09375,-4.3125 0,-1.90625 0.375,-3.332031 1.125,-4.28125 z M 3.84375,-2.65625 c 0.34375,0.585938 1.003906,0.875 1.984375,0.875 0.976563,0 1.632813,-0.289062 1.96875,-0.875 C 8.140625,-3.25 8.3125,-4.210938 8.3125,-5.546875 c 0,-1.332031 -0.183594,-2.273437 -0.546875,-2.828125 -0.355469,-0.5625 -1,-0.84375 -1.9375,-0.84375 -0.9375,0 -1.589844,0.28125 -1.953125,0.84375 -0.355469,0.554688 -0.53125,1.496094 -0.53125,2.828125 0,1.335937 0.164062,2.296875 0.5,2.890625 z m 0,0"
+ id="path4450" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4464"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(382.3515,513.39871)"
+ id="g4462">
+ <g
+ id="g4460">
+ <path
+ d="M 3.84375,0 H 1.453125 v -11 h 2.375 v 0.6875 c 1.070313,-0.613281 2.082031,-0.921875 3.03125,-0.921875 1.46875,0 2.46875,0.417969 3,1.25 0.539063,0.824219 0.8125,2.1875 0.8125,4.09375 V 0 h -2.375 v -5.828125 c 0,-1.1875 -0.132813,-2.03125 -0.390625,-2.53125 -0.25,-0.5 -0.773438,-0.75 -1.5625,-0.75 -0.75,0 -1.46875,0.148437 -2.15625,0.4375 L 3.84375,-8.53125 Z m 0,0"
+ id="path4458" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4472"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(394.36136,513.39871)"
+ id="g4470">
+ <g
+ id="g4468">
+ <path
+ d="m 0.421875,-11 h 2.5 L 5.03125,-2.046875 H 5.734375 L 7.9375,-11 h 2.453125 L 7.53125,0 H 3.25 Z m 0,0"
+ id="path4466" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4480"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(405.16143,513.39871)"
+ id="g4478">
+ <g
+ id="g4476">
+ <path
+ d="m 9.28125,-1.984375 0.625,-0.0625 0.03125,1.78125 c -1.667969,0.3320312 -3.148438,0.5 -4.4375,0.5 -1.625,0 -2.796875,-0.441406 -3.515625,-1.328125 -0.710937,-0.894531 -1.0625,-2.328125 -1.0625,-4.296875 0,-3.894531 1.59375,-5.84375 4.78125,-5.84375 3.070313,0 4.609375,1.679687 4.609375,5.03125 l -0.15625,1.71875 h -6.8125 c 0.00781,0.90625 0.207031,1.574219 0.59375,2 0.382812,0.429687 1.097656,0.640625 2.140625,0.640625 1.039063,0 2.109375,-0.046875 3.203125,-0.140625 z M 7.96875,-6.34375 c 0,-1.082031 -0.171875,-1.835938 -0.515625,-2.265625 -0.34375,-0.4375 -0.929687,-0.65625 -1.75,-0.65625 -0.824219,0 -1.421875,0.230469 -1.796875,0.6875 -0.375,0.460937 -0.570312,1.203125 -0.578125,2.234375 z m 0,0"
+ id="path4474" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4488"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(416.33545,513.39871)"
+ id="g4486">
+ <g
+ id="g4484">
+ <path
+ d="m 1.453125,0 v -11 h 2.375 v 1.3125 c 1.25,-0.800781 2.492187,-1.316406 3.734375,-1.546875 v 2.390625 c -1.261719,0.25 -2.339844,0.574219 -3.234375,0.96875 L 3.84375,-7.671875 V 0 Z m 0,0"
+ id="path4482" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4496"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(424.27603,513.39871)"
+ id="g4494">
+ <g
+ id="g4492">
+ <path
+ d="M 7.375,-8.953125 H 4.328125 v 4.84375 c 0,0.898437 0.066406,1.492187 0.203125,1.78125 0.132812,0.292969 0.472656,0.4375 1.015625,0.4375 l 1.796875,-0.0625 0.109375,1.90625 c -0.980469,0.1875 -1.726563,0.28125 -2.234375,0.28125 -1.25,0 -2.109375,-0.28125 -2.578125,-0.84375 -0.460937,-0.570313 -0.6875,-1.648437 -0.6875,-3.234375 V -8.953125 H 0.546875 V -11 h 1.40625 v -3.1875 h 2.375 V -11 H 7.375 Z m 0,0"
+ id="path4490" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4504"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(432.15063,513.39871)"
+ id="g4502">
+ <g
+ id="g4500">
+ <path
+ d="m 9.28125,-1.984375 0.625,-0.0625 0.03125,1.78125 c -1.667969,0.3320312 -3.148438,0.5 -4.4375,0.5 -1.625,0 -2.796875,-0.441406 -3.515625,-1.328125 -0.710937,-0.894531 -1.0625,-2.328125 -1.0625,-4.296875 0,-3.894531 1.59375,-5.84375 4.78125,-5.84375 3.070313,0 4.609375,1.679687 4.609375,5.03125 l -0.15625,1.71875 h -6.8125 c 0.00781,0.90625 0.207031,1.574219 0.59375,2 0.382812,0.429687 1.097656,0.640625 2.140625,0.640625 1.039063,0 2.109375,-0.046875 3.203125,-0.140625 z M 7.96875,-6.34375 c 0,-1.082031 -0.171875,-1.835938 -0.515625,-2.265625 -0.34375,-0.4375 -0.929687,-0.65625 -1.75,-0.65625 -0.824219,0 -1.421875,0.230469 -1.796875,0.6875 -0.375,0.460937 -0.570312,1.203125 -0.578125,2.234375 z m 0,0"
+ id="path4498" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4512"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(443.32464,513.39871)"
+ id="g4510">
+ <g
+ id="g4508">
+ <path
+ d="m 1.453125,0 v -11 h 2.375 v 1.3125 c 1.25,-0.800781 2.492187,-1.316406 3.734375,-1.546875 v 2.390625 c -1.261719,0.25 -2.339844,0.574219 -3.234375,0.96875 L 3.84375,-7.671875 V 0 Z m 0,0"
+ id="path4506" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#f03e985e13)"
+ id="g4516"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#09102b"
+ d="m 113.46875,378.90234 v -55.07031 c 0,-0.66406 0.0625,-1.32422 0.19141,-1.97656 0.13281,-0.65235 0.32422,-1.28516 0.57812,-1.89844 0.25391,-0.61719 0.5625,-1.19922 0.9336,-1.75391 0.36718,-0.55468 0.78515,-1.0664 1.2539,-1.53515 0.46875,-0.46875 0.98047,-0.89063 1.53125,-1.26172 0.55469,-0.36719 1.13672,-0.67969 1.75,-0.93359 0.60938,-0.25782 1.24219,-0.44922 1.89453,-0.57813 0.64844,-0.12891 1.3086,-0.19531 1.96875,-0.19531 h 92.375 c 0.66016,0 1.32031,0.0664 1.96875,0.19531 0.65235,0.12891 1.28516,0.32031 1.89453,0.57813 0.61328,0.2539 1.19532,0.5664 1.75,0.93359 0.55078,0.37109 1.0625,0.79297 1.53125,1.26172 0.46875,0.46875 0.88672,0.98047 1.25391,1.53515 0.37109,0.55469 0.67969,1.13672 0.93359,1.75391 0.25391,0.61328 0.44532,1.24609 0.57813,1.89844 0.1289,0.65234 0.1914,1.3125 0.1914,1.97656 v 55.07031 c 0,0.66407 -0.0625,1.32422 -0.1914,1.97657 -0.13281,0.65234 -0.32422,1.28515 -0.57813,1.89843 -0.2539,0.61719 -0.5625,1.19922 -0.93359,1.75391 -0.36719,0.55469 -0.78516,1.06641 -1.25391,1.53516 -0.46875,0.46875 -0.98047,0.89062 -1.53125,1.26171 -0.55468,0.36719 -1.13672,0.67969 -1.75,0.9336 -0.60937,0.25781 -1.24218,0.44922 -1.89453,0.57812 -0.64844,0.12891 -1.30859,0.19532 -1.96875,0.19532 h -92.375 c -0.66015,0 -1.32031,-0.0664 -1.96875,-0.19532 -0.65234,-0.1289 -1.28515,-0.32031 -1.89453,-0.57812 -0.61328,-0.25391 -1.19531,-0.56641 -1.75,-0.9336 -0.55078,-0.37109 -1.0625,-0.79296 -1.53125,-1.26171 -0.46875,-0.46875 -0.88672,-0.98047 -1.2539,-1.53516 -0.3711,-0.55469 -0.67969,-1.13672 -0.9336,-1.75391 -0.2539,-0.61328 -0.44531,-1.24609 -0.57812,-1.89843 -0.12891,-0.65235 -0.19141,-1.3125 -0.19141,-1.97657 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4514" />
+ </g>
+ <g
+ clip-path="url(#c71ef1b2fa)"
+ id="g4520"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#09102b"
+ d="m 226.62891,323.83203 v 55.06641 c 0,0.70312 -0.0703,1.40234 -0.20704,2.08984 -0.13671,0.69141 -0.33984,1.36328 -0.60546,2.01172 -0.26954,0.65234 -0.59766,1.26953 -0.98829,1.85156 -0.39062,0.58594 -0.83203,1.12891 -1.32812,1.625 -0.49609,0.5 -1.03906,0.94141 -1.62109,1.33594 -0.58204,0.39062 -1.19922,0.71875 -1.84766,0.98828 -0.64844,0.26953 -1.31641,0.47266 -2.00391,0.60938 -0.6875,0.13671 -1.38281,0.20703 -2.08593,0.20703 h -92.36719 c -0.70313,0 -1.39844,-0.0703 -2.08594,-0.20703 -0.6875,-0.13672 -1.35547,-0.33985 -2.0039,-0.60938 -0.64844,-0.26953 -1.26563,-0.59766 -1.84766,-0.98828 -0.58203,-0.39453 -1.125,-0.83594 -1.62109,-1.33594 -0.4961,-0.49609 -0.9375,-1.03906 -1.32813,-1.625 -0.39062,-0.58203 -0.71875,-1.19922 -0.98828,-1.85156 -0.26563,-0.64844 -0.46875,-1.32031 -0.60547,-2.01172 -0.13672,-0.6875 -0.20703,-1.38672 -0.20703,-2.08984 v -55.06641 c 0,-0.70312 0.0703,-1.39844 0.20703,-2.08984 0.13672,-0.69141 0.33984,-1.35938 0.60547,-2.01172 0.26953,-0.64844 0.59766,-1.26563 0.98828,-1.85156 0.39063,-0.58594 0.83203,-1.125 1.32813,-1.625 0.49609,-0.4961 1.03906,-0.94141 1.62109,-1.33204 0.58203,-0.39062 1.19922,-0.72265 1.84766,-0.99218 0.64843,-0.26953 1.3164,-0.47266 2.0039,-0.60938 0.6875,-0.13672 1.38281,-0.20703 2.08594,-0.20703 h 92.37109 c 0.69922,0 1.39453,0.0703 2.08203,0.20703 0.6875,0.13672 1.35547,0.33985 2.00391,0.60938 0.64844,0.26953 1.26562,0.60156 1.84766,0.99218 0.58593,0.39063 1.125,0.83594 1.62109,1.33204 0.49609,0.5 0.9375,1.03906 1.32812,1.625 0.39063,0.58593 0.71875,1.20312 0.98829,1.85156 0.26562,0.65234 0.46875,1.32031 0.60546,2.01172 0.13672,0.6914 0.20704,1.38672 0.20704,2.08984 z m -112.58203,55.06641 c 0,0.6289 0.0625,1.25 0.18359,1.86328 0.125,0.61719 0.30469,1.21484 0.54297,1.79297 0.23828,0.57812 0.53125,1.1289 0.8789,1.65234 0.34766,0.51953 0.74219,1.00391 1.1875,1.44531 0.44141,0.44532 0.92188,0.83985 1.44141,1.19141 0.51953,0.34766 1.07031,0.64062 1.64844,0.88281 0.57812,0.23828 1.17187,0.41797 1.78515,0.54297 0.61329,0.12109 1.23438,0.18359 1.85938,0.18359 h 92.37109 c 0.625,0 1.24219,-0.0625 1.85547,-0.18359 0.61328,-0.125 1.21094,-0.30469 1.78906,-0.54297 0.57813,-0.24219 1.125,-0.53515 1.64453,-0.88281 0.52344,-0.35156 1.00391,-0.74609 1.44532,-1.19141 0.4414,-0.4414 0.83593,-0.92578 1.18359,-1.44531 0.34766,-0.52344 0.64063,-1.07422 0.88281,-1.65234 0.23828,-0.57813 0.41797,-1.17578 0.53907,-1.79297 0.125,-0.61328 0.18359,-1.23438 0.18359,-1.86328 v -55.06641 c 0,-0.625 -0.0586,-1.24609 -0.18359,-1.86328 -0.1211,-0.61328 -0.30079,-1.21094 -0.53907,-1.79297 -0.24218,-0.57812 -0.53515,-1.12891 -0.88281,-1.64844 -0.34766,-0.52343 -0.74219,-1.0039 -1.18359,-1.44922 -0.44141,-0.44531 -0.92188,-0.83984 -1.44532,-1.1875 -0.51953,-0.34765 -1.0664,-0.64453 -1.64453,-0.88281 -0.57812,-0.24219 -1.17578,-0.42187 -1.78906,-0.54297 -0.61328,-0.125 -1.23047,-0.18359 -1.85547,-0.18359 h -92.37109 c -0.625,0 -1.24609,0.0586 -1.85938,0.18359 -0.61328,0.1211 -1.20703,0.30078 -1.78515,0.54297 -0.57813,0.23828 -1.12891,0.53516 -1.64844,0.88281 -0.51953,0.34766 -1,0.74219 -1.44141,1.1875 -0.44531,0.44532 -0.83984,0.92579 -1.1875,1.44922 -0.34765,0.51953 -0.64062,1.07032 -0.8789,1.64844 -0.23828,0.58203 -0.41797,1.17969 -0.54297,1.79297 -0.12109,0.61719 -0.18359,1.23828 -0.18359,1.86328 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4518" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4528"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(126.50046,359.41913)"
+ id="g4526">
+ <g
+ id="g4524">
+ <path
+ d="M 11.0625,-0.234375 C 9.550781,0.0664062 8.191406,0.21875 6.984375,0.21875 5.785156,0.21875 4.816406,0.0546875 4.078125,-0.265625 3.335938,-0.597656 2.765625,-1.113281 2.359375,-1.8125 1.960938,-2.507812 1.6875,-3.304688 1.53125,-4.203125 c -0.15625,-0.90625 -0.234375,-2.03125 -0.234375,-3.375 0,-1.351563 0.078125,-2.488281 0.234375,-3.40625 0.15625,-0.914063 0.429688,-1.722656 0.828125,-2.421875 0.40625,-0.707031 0.972656,-1.222656 1.703125,-1.546875 0.738281,-0.320313 1.691406,-0.484375 2.859375,-0.484375 1.175781,0 2.554687,0.164062 4.140625,0.484375 L 11,-13.53125 c -1.480469,-0.257812 -2.796875,-0.390625 -3.953125,-0.390625 -1.617187,0 -2.683594,0.480469 -3.203125,1.4375 -0.523438,0.960937 -0.78125,2.601563 -0.78125,4.921875 0,1.15625 0.046875,2.089844 0.140625,2.796875 0.09375,0.699219 0.28125,1.328125 0.5625,1.890625 0.28125,0.5625 0.6875,0.96875 1.21875,1.21875 0.53125,0.242188 1.3125,0.359375 2.34375,0.359375 1.039063,0 2.265625,-0.128906 3.671875,-0.390625 z m 0,0"
+ id="path4522" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4536"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(138.46633,359.41913)"
+ id="g4534">
+ <g
+ id="g4532">
+ <path
+ d="M 1.203125,-4.78125 V -6.265625 H 5.375 V -10.5625 h 1.53125 v 4.296875 h 4.203125 V -4.78125 H 6.90625 V -0.4375 H 5.375 v -4.34375 z m 0,0"
+ id="path4530" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4544"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(150.78413,359.41913)"
+ id="g4542">
+ <g
+ id="g4540">
+ <path
+ d="M 1.203125,-4.78125 V -6.265625 H 5.375 V -10.5625 h 1.53125 v 4.296875 h 4.203125 V -4.78125 H 6.90625 V -0.4375 H 5.375 v -4.34375 z m 0,0"
+ id="path4538" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4550"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(163.10194,359.41913)"
+ id="g4548">
+ <g
+ id="g4546" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4558"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(167.94108,359.41913)"
+ id="g4556">
+ <g
+ id="g4554">
+ <path
+ d="m 0.28125,-13.703125 v -1.515625 h 11 v 1.515625 H 6.640625 V 0 H 4.96875 v -13.703125 z m 0,0"
+ id="path4552" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4566"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(179.51102,359.41913)"
+ id="g4564">
+ <g
+ id="g4562">
+ <path
+ d="m 0.546875,-11 h 1.65625 l 2.75,9.5625 h 0.71875 L 8.453125,-11 H 10.09375 L 5.515625,4.890625 H 3.875 L 5.296875,0 h -1.625 z m 0,0"
+ id="path4560" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4574"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(190.13512,359.41913)"
+ id="g4572">
+ <g
+ id="g4570">
+ <path
+ d="M 1.578125,4.890625 V -11 H 3.21875 v 0.796875 c 1.113281,-0.675781 2.210938,-1.015625 3.296875,-1.015625 1.394531,0 2.40625,0.445312 3.03125,1.328125 C 10.179688,-9.003906 10.5,-7.539062 10.5,-5.5 c 0,2.042969 -0.375,3.507812 -1.125,4.390625 -0.742188,0.886719 -1.964844,1.328125 -3.671875,1.328125 -0.898437,0 -1.71875,-0.078125 -2.46875,-0.234375 v 4.90625 z M 6.265625,-9.75 c -0.4375,0 -0.914063,0.074219 -1.421875,0.21875 -0.5,0.148438 -0.898438,0.292969 -1.1875,0.4375 l -0.421875,0.234375 v 7.40625 c 1.039063,0.167969 1.832031,0.25 2.375,0.25 1.1875,0 2.019531,-0.335937 2.5,-1.015625 0.476563,-0.675781 0.71875,-1.773438 0.71875,-3.296875 0,-1.53125 -0.21875,-2.617187 -0.65625,-3.265625 C 7.742188,-9.425781 7.109375,-9.75 6.265625,-9.75 Z m 0,0"
+ id="path4568" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4582"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(201.72705,359.41913)"
+ id="g4580">
+ <g
+ id="g4578">
+ <path
+ d="M 9.0625,-1.359375 9.703125,-1.4375 9.75,-0.125 C 8.070312,0.101562 6.640625,0.21875 5.453125,0.21875 c -1.585937,0 -2.710937,-0.457031 -3.375,-1.375 C 1.421875,-2.070312 1.09375,-3.5 1.09375,-5.4375 c 0,-3.851562 1.535156,-5.78125 4.609375,-5.78125 1.476563,0 2.582031,0.417969 3.3125,1.25 0.738281,0.824219 1.109375,2.121094 1.109375,3.890625 L 10.03125,-4.8125 H 2.765625 c 0,1.21875 0.21875,2.121094 0.65625,2.703125 0.445313,0.585937 1.21875,0.875 2.3125,0.875 1.09375,0 2.203125,-0.039063 3.328125,-0.125 z m -0.59375,-4.78125 c 0,-1.34375 -0.21875,-2.289063 -0.65625,-2.84375 -0.429688,-0.5625 -1.132812,-0.84375 -2.109375,-0.84375 -0.96875,0 -1.703125,0.292969 -2.203125,0.875 -0.492188,0.585937 -0.742188,1.523437 -0.75,2.8125 z m 0,0"
+ id="path4576" />
+ </g>
+ </g>
+ </g>
+ <path
+ fill="#09102b"
+ d="m 524.81258,303.82657 v -55.06641 c 0,-0.66406 0.0664,-1.32422 0.19531,-1.97656 0.12891,-0.65235 0.32031,-1.28516 0.57422,-1.90235 0.2539,-0.61328 0.5664,-1.19531 0.93359,-1.75 0.3711,-0.55468 0.78906,-1.0664 1.25781,-1.53515 0.46875,-0.47266 0.98047,-0.89063 1.53125,-1.26172 0.55079,-0.3711 1.13282,-0.67969 1.7461,-0.9375 0.61328,-0.25391 1.24609,-0.44531 1.89453,-0.57422 0.65234,-0.12891 1.30859,-0.19531 1.97266,-0.19531 h 92.37109 c 0.66406,0 1.32031,0.0664 1.97266,0.19531 0.64843,0.12891 1.28125,0.32031 1.89453,0.57422 0.61328,0.25781 1.19531,0.5664 1.74609,0.9375 0.55469,0.37109 1.0625,0.78906 1.53125,1.26172 0.46875,0.46875 0.89063,0.98047 1.25781,1.53515 0.36719,0.55469 0.67969,1.13672 0.9336,1.75 0.2539,0.61719 0.44531,1.25 0.57422,1.90235 0.1289,0.65234 0.19531,1.3125 0.19531,1.97656 v 55.06641 c 0,0.66796 -0.0664,1.32421 -0.19531,1.97656 -0.12891,0.65625 -0.32032,1.28906 -0.57422,1.90234 -0.25391,0.61328 -0.56641,1.19922 -0.9336,1.75391 -0.36718,0.55078 -0.78906,1.0625 -1.25781,1.53515 -0.46875,0.46875 -0.97656,0.89063 -1.53125,1.25782 -0.55078,0.37109 -1.13281,0.68359 -1.74609,0.9375 -0.61328,0.2539 -1.2461,0.44922 -1.89453,0.57812 -0.65235,0.12891 -1.3086,0.19531 -1.97266,0.19531 h -92.37109 c -0.66407,0 -1.32032,-0.0664 -1.97266,-0.19531 -0.64844,-0.1289 -1.28125,-0.32422 -1.89453,-0.57812 -0.61328,-0.25391 -1.19531,-0.56641 -1.7461,-0.9375 -0.55078,-0.36719 -1.0625,-0.78907 -1.53125,-1.25782 -0.46875,-0.47265 -0.88671,-0.98437 -1.25781,-1.53515 -0.36719,-0.55469 -0.67969,-1.14063 -0.93359,-1.75391 -0.25391,-0.61328 -0.44531,-1.24609 -0.57422,-1.90234 -0.12891,-0.65235 -0.19531,-1.3086 -0.19531,-1.97656 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4584" />
+ <g
+ clip-path="url(#3bddcdf684)"
+ id="g4588"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#09102b"
+ d="m 707.21875,499.40625 v 55.06641 c 0,0.70312 -0.0703,1.39843 -0.20703,2.08984 -0.13672,0.69141 -0.33985,1.35937 -0.60938,2.01172 -0.26562,0.64844 -0.59765,1.26562 -0.98828,1.85156 -0.38672,0.58594 -0.83203,1.12891 -1.32812,1.625 -0.4961,0.49609 -1.03516,0.94141 -1.61719,1.33203 -0.58594,0.39063 -1.19922,0.72266 -1.84766,0.99219 -0.64843,0.26953 -1.3164,0.47266 -2.00781,0.60937 -0.6875,0.13672 -1.38281,0.20704 -2.08203,0.20704 h -92.36719 c -0.70312,0 -1.39844,-0.0703 -2.08594,-0.20704 -0.6875,-0.13671 -1.35546,-0.33984 -2.0039,-0.60937 -0.64844,-0.26953 -1.26563,-0.60156 -1.84766,-0.99219 -0.58594,-0.39062 -1.125,-0.83594 -1.62109,-1.33203 -0.4961,-0.49609 -0.9375,-1.03906 -1.32813,-1.625 -0.39062,-0.58594 -0.71875,-1.20312 -0.98828,-1.85156 -0.26953,-0.65235 -0.47265,-1.32031 -0.60937,-2.01172 -0.13672,-0.69141 -0.20313,-1.38672 -0.20313,-2.08984 v -55.06641 c 0,-0.70313 0.0664,-1.39844 0.20313,-2.08984 0.13672,-0.69141 0.33984,-1.35938 0.60937,-2.01172 0.26953,-0.64844 0.59766,-1.26953 0.98828,-1.85157 0.39063,-0.58593 0.83203,-1.1289 1.32813,-1.625 0.49609,-0.5 1.03515,-0.9414 1.62109,-1.33203 0.58203,-0.39062 1.19922,-0.72265 1.84766,-0.99218 0.64844,-0.26954 1.3164,-0.47266 2.0039,-0.60938 0.6875,-0.13672 1.38282,-0.20703 2.08594,-0.20703 h 92.36719 c 0.70312,0 1.39844,0.0703 2.08594,0.20703 0.6875,0.13672 1.35547,0.33984 2.0039,0.60938 0.64844,0.26953 1.26563,0.60156 1.84766,0.99218 0.58203,0.39063 1.12109,0.83594 1.61719,1.33203 0.49609,0.4961 0.9414,1.03907 1.33203,1.625 0.38672,0.58594 0.71875,1.20313 0.98437,1.85157 0.26953,0.65234 0.47266,1.32031 0.60938,2.01172 0.13672,0.6914 0.20703,1.38671 0.20703,2.08984 z m -112.58203,55.06641 c 0,0.625 0.0625,1.24609 0.18359,1.86328 0.1211,0.61328 0.30078,1.21093 0.54297,1.79297 0.23828,0.57812 0.53125,1.1289 0.87891,1.65234 0.34765,0.51953 0.74218,1.00391 1.18359,1.44531 0.44531,0.44531 0.92578,0.83985 1.44531,1.1875 0.51953,0.35156 1.06641,0.64453 1.64453,0.88281 0.57813,0.24219 1.17579,0.42188 1.78907,0.54297 0.61328,0.125 1.23047,0.1836 1.85937,0.1836 h 92.36719 c 0.625,0 1.24609,-0.0586 1.85937,-0.1836 0.61329,-0.12109 1.20704,-0.30078 1.78516,-0.54297 0.57813,-0.23828 1.12891,-0.53125 1.64844,-0.88281 0.51953,-0.34765 1,-0.74219 1.44531,-1.1875 0.44141,-0.4414 0.83594,-0.92578 1.18359,-1.44531 0.34766,-0.52344 0.64063,-1.07422 0.87891,-1.65234 0.23828,-0.58204 0.42188,-1.17969 0.54297,-1.79297 0.12109,-0.61719 0.18359,-1.23828 0.18359,-1.86328 v -55.06641 c 0,-0.625 -0.0625,-1.24609 -0.18359,-1.86328 -0.12109,-0.61328 -0.30469,-1.21094 -0.54297,-1.79297 -0.23828,-0.57813 -0.53125,-1.12891 -0.87891,-1.65234 -0.34765,-0.51954 -0.74218,-1.00391 -1.18359,-1.44532 -0.44531,-0.44531 -0.92578,-0.83984 -1.44531,-1.1875 -0.51953,-0.35156 -1.07031,-0.64453 -1.64844,-0.88281 -0.57812,-0.24219 -1.17187,-0.42187 -1.78516,-0.54687 -0.61328,-0.1211 -1.23437,-0.1836 -1.85937,-0.1836 h -92.36719 c -0.6289,0 -1.24609,0.0625 -1.85937,0.1836 -0.61328,0.125 -1.21094,0.30468 -1.78907,0.54687 -0.57812,0.23828 -1.125,0.53125 -1.64453,0.88281 -0.51953,0.34766 -1,0.74219 -1.44531,1.1875 -0.44141,0.44141 -0.83594,0.92578 -1.18359,1.44532 -0.34766,0.52343 -0.64063,1.07421 -0.87891,1.65234 -0.24219,0.58203 -0.42187,1.17969 -0.54297,1.79297 -0.12109,0.61719 -0.18359,1.23828 -0.18359,1.86328 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4586" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4596"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(607.08883,534.99247)"
+ id="g4594">
+ <g
+ id="g4592">
+ <path
+ d="M 11.0625,-0.234375 C 9.550781,0.0664062 8.191406,0.21875 6.984375,0.21875 5.785156,0.21875 4.816406,0.0546875 4.078125,-0.265625 3.335938,-0.597656 2.765625,-1.113281 2.359375,-1.8125 1.960938,-2.507812 1.6875,-3.304688 1.53125,-4.203125 c -0.15625,-0.90625 -0.234375,-2.03125 -0.234375,-3.375 0,-1.351563 0.078125,-2.488281 0.234375,-3.40625 0.15625,-0.914063 0.429688,-1.722656 0.828125,-2.421875 0.40625,-0.707031 0.972656,-1.222656 1.703125,-1.546875 0.738281,-0.320313 1.691406,-0.484375 2.859375,-0.484375 1.175781,0 2.554687,0.164062 4.140625,0.484375 L 11,-13.53125 c -1.480469,-0.257812 -2.796875,-0.390625 -3.953125,-0.390625 -1.617187,0 -2.683594,0.480469 -3.203125,1.4375 -0.523438,0.960937 -0.78125,2.601563 -0.78125,4.921875 0,1.15625 0.046875,2.089844 0.140625,2.796875 0.09375,0.699219 0.28125,1.328125 0.5625,1.890625 0.28125,0.5625 0.6875,0.96875 1.21875,1.21875 0.53125,0.242188 1.3125,0.359375 2.34375,0.359375 1.039063,0 2.265625,-0.128906 3.671875,-0.390625 z m 0,0"
+ id="path4590" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4604"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(619.0547,534.99247)"
+ id="g4602">
+ <g
+ id="g4600">
+ <path
+ d="M 1.203125,-4.78125 V -6.265625 H 5.375 V -10.5625 h 1.53125 v 4.296875 h 4.203125 V -4.78125 H 6.90625 V -0.4375 H 5.375 v -4.34375 z m 0,0"
+ id="path4598" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4612"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(631.37251,534.99247)"
+ id="g4610">
+ <g
+ id="g4608">
+ <path
+ d="M 1.203125,-4.78125 V -6.265625 H 5.375 V -10.5625 h 1.53125 v 4.296875 h 4.203125 V -4.78125 H 6.90625 V -0.4375 H 5.375 v -4.34375 z m 0,0"
+ id="path4606" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4618"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(643.69031,534.99247)"
+ id="g4616">
+ <g
+ id="g4614" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4626"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(648.52945,534.99247)"
+ id="g4624">
+ <g
+ id="g4622">
+ <path
+ d="m 0.28125,-13.703125 v -1.515625 h 11 v 1.515625 H 6.640625 V 0 H 4.96875 v -13.703125 z m 0,0"
+ id="path4620" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4634"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(660.09939,534.99247)"
+ id="g4632">
+ <g
+ id="g4630">
+ <path
+ d="m 0.546875,-11 h 1.65625 l 2.75,9.5625 h 0.71875 L 8.453125,-11 H 10.09375 L 5.515625,4.890625 H 3.875 L 5.296875,0 h -1.625 z m 0,0"
+ id="path4628" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4642"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(670.72349,534.99247)"
+ id="g4640">
+ <g
+ id="g4638">
+ <path
+ d="M 1.578125,4.890625 V -11 H 3.21875 v 0.796875 c 1.113281,-0.675781 2.210938,-1.015625 3.296875,-1.015625 1.394531,0 2.40625,0.445312 3.03125,1.328125 C 10.179688,-9.003906 10.5,-7.539062 10.5,-5.5 c 0,2.042969 -0.375,3.507812 -1.125,4.390625 -0.742188,0.886719 -1.964844,1.328125 -3.671875,1.328125 -0.898437,0 -1.71875,-0.078125 -2.46875,-0.234375 v 4.90625 z M 6.265625,-9.75 c -0.4375,0 -0.914063,0.074219 -1.421875,0.21875 -0.5,0.148438 -0.898438,0.292969 -1.1875,0.4375 l -0.421875,0.234375 v 7.40625 c 1.039063,0.167969 1.832031,0.25 2.375,0.25 1.1875,0 2.019531,-0.335937 2.5,-1.015625 0.476563,-0.675781 0.71875,-1.773438 0.71875,-3.296875 0,-1.53125 -0.21875,-2.617187 -0.65625,-3.265625 C 7.742188,-9.425781 7.109375,-9.75 6.265625,-9.75 Z m 0,0"
+ id="path4636" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4650"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(682.31543,534.99247)"
+ id="g4648">
+ <g
+ id="g4646">
+ <path
+ d="M 9.0625,-1.359375 9.703125,-1.4375 9.75,-0.125 C 8.070312,0.101562 6.640625,0.21875 5.453125,0.21875 c -1.585937,0 -2.710937,-0.457031 -3.375,-1.375 C 1.421875,-2.070312 1.09375,-3.5 1.09375,-5.4375 c 0,-3.851562 1.535156,-5.78125 4.609375,-5.78125 1.476563,0 2.582031,0.417969 3.3125,1.25 0.738281,0.824219 1.109375,2.121094 1.109375,3.890625 L 10.03125,-4.8125 H 2.765625 c 0,1.21875 0.21875,2.121094 0.65625,2.703125 0.445313,0.585937 1.21875,0.875 2.3125,0.875 1.09375,0 2.203125,-0.039063 3.328125,-0.125 z m -0.59375,-4.78125 c 0,-1.34375 -0.21875,-2.289063 -0.65625,-2.84375 -0.429688,-0.5625 -1.132812,-0.84375 -2.109375,-0.84375 -0.96875,0 -1.703125,0.292969 -2.203125,0.875 -0.492188,0.585937 -0.742188,1.523437 -0.75,2.8125 z m 0,0"
+ id="path4644" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#cd19a8dfa8)"
+ id="g4656"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#306998"
+ d="m 588.69141,378.90234 v -55.07031 c 0,-0.66406 0.0664,-1.32422 0.19531,-1.97656 0.1289,-0.65235 0.32031,-1.28516 0.57422,-1.89844 0.2539,-0.61719 0.5664,-1.19922 0.93359,-1.75391 0.37109,-0.55468 0.78906,-1.0664 1.25781,-1.53515 0.46875,-0.46875 0.98047,-0.89063 1.53125,-1.26172 0.55078,-0.36719 1.13282,-0.67969 1.7461,-0.93359 0.61328,-0.25782 1.24609,-0.44922 1.89843,-0.57813 0.64844,-0.12891 1.30469,-0.19531 1.96875,-0.19531 h 92.3711 c 0.66406,0 1.32031,0.0664 1.97265,0.19531 0.65235,0.12891 1.28125,0.32031 1.89454,0.57813 0.61328,0.2539 1.19531,0.5664 1.74609,0.93359 0.55469,0.37109 1.0625,0.79297 1.53125,1.26172 0.46875,0.46875 0.89062,0.98047 1.25781,1.53515 0.36719,0.55469 0.67969,1.13672 0.9336,1.75391 0.2539,0.61328 0.44531,1.24609 0.57421,1.89844 0.12891,0.65234 0.19532,1.3125 0.19532,1.97656 v 55.07031 c 0,0.66407 -0.0664,1.32422 -0.19532,1.97657 -0.1289,0.65234 -0.32031,1.28515 -0.57421,1.89843 -0.25391,0.61719 -0.56641,1.19922 -0.9336,1.75391 -0.36719,0.55469 -0.78906,1.06641 -1.25781,1.53516 -0.46875,0.46875 -0.97656,0.89062 -1.53125,1.26171 -0.55078,0.36719 -1.13281,0.67969 -1.74609,0.9336 -0.61329,0.25781 -1.24219,0.44922 -1.89454,0.57812 -0.65234,0.12891 -1.30859,0.19532 -1.97265,0.19532 h -92.3711 c -0.66406,0 -1.32031,-0.0664 -1.96875,-0.19532 -0.65234,-0.1289 -1.28515,-0.32031 -1.89843,-0.57812 -0.61328,-0.25391 -1.19532,-0.56641 -1.7461,-0.9336 -0.55078,-0.37109 -1.0625,-0.79296 -1.53125,-1.26171 -0.46875,-0.46875 -0.88672,-0.98047 -1.25781,-1.53516 -0.36719,-0.55469 -0.67969,-1.13672 -0.93359,-1.75391 -0.25391,-0.61328 -0.44532,-1.24609 -0.57422,-1.89843 -0.12891,-0.65235 -0.19531,-1.3125 -0.19531,-1.97657 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4652" />
+ <path
+ fill="#306998"
+ d="m 701.85547,323.83203 v 55.06641 c 0,0.70312 -0.0703,1.40234 -0.20703,2.08984 -0.13672,0.69141 -0.33985,1.36328 -0.60938,2.01172 -0.26562,0.65234 -0.59765,1.26953 -0.98437,1.85156 -0.39063,0.58594 -0.83594,1.12891 -1.33203,1.625 -0.4961,0.5 -1.03516,0.94141 -1.61719,1.33594 -0.58594,0.39062 -1.19922,0.71875 -1.84766,0.98828 -0.64844,0.26953 -1.3164,0.47266 -2.0039,0.60938 -0.69141,0.13671 -1.38672,0.20703 -2.08594,0.20703 h -92.36719 c -0.70312,0 -1.39844,-0.0703 -2.08594,-0.20703 -0.6875,-0.13672 -1.35547,-0.33985 -2.0039,-0.60938 -0.64844,-0.26953 -1.26563,-0.59766 -1.84766,-0.98828 -0.58594,-0.39453 -1.125,-0.83594 -1.62109,-1.33594 -0.4961,-0.49609 -0.9375,-1.03906 -1.32813,-1.625 -0.39062,-0.58203 -0.71875,-1.19922 -0.98828,-1.85156 -0.26953,-0.64844 -0.47266,-1.32031 -0.60937,-2.01172 -0.13672,-0.6875 -0.20313,-1.38672 -0.20313,-2.08984 v -55.06641 c 0,-0.70312 0.0664,-1.39844 0.20313,-2.08984 0.13671,-0.69141 0.33984,-1.35938 0.60937,-2.01172 0.26953,-0.64844 0.59766,-1.26563 0.98828,-1.85156 0.39063,-0.58594 0.83203,-1.125 1.32813,-1.625 0.49609,-0.4961 1.03515,-0.94141 1.62109,-1.33204 0.58203,-0.39062 1.19922,-0.72265 1.84766,-0.99218 0.64843,-0.26953 1.3164,-0.47266 2.0039,-0.60938 0.6875,-0.13672 1.38282,-0.20703 2.08594,-0.20703 h 92.36719 c 0.70312,0 1.39844,0.0703 2.08594,0.20703 0.6875,0.13672 1.35546,0.33985 2.0039,0.60938 0.64844,0.26953 1.26563,0.60156 1.84766,0.99218 0.58203,0.39063 1.125,0.83594 1.62109,1.33204 0.4961,0.5 0.9375,1.03906 1.32813,1.625 0.39062,0.58593 0.71875,1.20312 0.98437,1.85156 0.26953,0.65234 0.47266,1.32031 0.60938,2.01172 0.13672,0.6914 0.20703,1.38672 0.20703,2.08984 z m -112.58203,55.06641 c 0,0.6289 0.0625,1.25 0.18359,1.86328 0.12109,0.61719 0.30469,1.21484 0.54297,1.79297 0.23828,0.57812 0.53125,1.1289 0.87891,1.65234 0.34765,0.51953 0.74218,1.00391 1.18359,1.44531 0.44531,0.44532 0.92578,0.83985 1.44531,1.19141 0.51953,0.34766 1.07031,0.64062 1.64844,0.88281 0.57422,0.23828 1.17187,0.41797 1.78516,0.54297 0.61328,0.12109 1.23437,0.18359 1.85937,0.18359 h 92.36719 c 0.625,0 1.24609,-0.0625 1.85937,-0.18359 0.61328,-0.125 1.21094,-0.30469 1.78907,-0.54297 0.57421,-0.24219 1.125,-0.53515 1.64453,-0.88281 0.51953,-0.35156 1,-0.74609 1.44531,-1.19141 0.44141,-0.4414 0.83594,-0.92578 1.18359,-1.44531 0.34766,-0.52344 0.64063,-1.07422 0.87891,-1.65234 0.24219,-0.57813 0.42187,-1.17578 0.54297,-1.79297 0.12109,-0.61328 0.18359,-1.23438 0.18359,-1.86328 v -55.06641 c 0,-0.625 -0.0625,-1.24609 -0.18359,-1.86328 -0.1211,-0.61328 -0.30078,-1.21094 -0.54297,-1.79297 -0.23828,-0.57812 -0.53125,-1.12891 -0.87891,-1.64844 -0.34765,-0.52343 -0.74218,-1.0039 -1.18359,-1.44922 -0.44531,-0.44531 -0.92578,-0.83984 -1.44531,-1.1875 -0.51953,-0.34765 -1.07032,-0.64453 -1.64453,-0.88281 -0.57813,-0.24219 -1.17579,-0.42187 -1.78907,-0.54297 -0.61328,-0.125 -1.23437,-0.18359 -1.85937,-0.18359 h -92.36719 c -0.625,0 -1.24609,0.0586 -1.85937,0.18359 -0.61329,0.1211 -1.21094,0.30078 -1.78516,0.54297 -0.57813,0.23828 -1.12891,0.53516 -1.64844,0.88281 -0.51953,0.34766 -1,0.74219 -1.44531,1.1875 -0.44141,0.44532 -0.83594,0.92579 -1.18359,1.44922 -0.34766,0.51953 -0.64063,1.07032 -0.87891,1.64844 -0.23828,0.58203 -0.42188,1.17969 -0.54297,1.79297 -0.12109,0.61719 -0.18359,1.23828 -0.18359,1.86328 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4654" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4664"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(611.5815,344.04413)"
+ id="g4662">
+ <g
+ id="g4660">
+ <path
+ d="M 7.4375,-5.125 H 3.5625 V 0 H 1.875 v -15.21875 h 5.5625 c 1.65625,0 2.878906,0.40625 3.671875,1.21875 0.789063,0.804688 1.1875,2.03125 1.1875,3.6875 0,3.460938 -1.621094,5.1875 -4.859375,5.1875 z m -3.875,-1.5 h 3.84375 c 2.101562,0 3.15625,-1.226562 3.15625,-3.6875 0,-1.175781 -0.25,-2.039062 -0.75,-2.59375 -0.5,-0.550781 -1.304688,-0.828125 -2.40625,-0.828125 H 3.5625 Z m 0,0"
+ id="path4658" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4672"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(624.62518,344.04413)"
+ id="g4670">
+ <g
+ id="g4668">
+ <path
+ d="m 0.546875,-11 h 1.65625 l 2.75,9.5625 h 0.71875 L 8.453125,-11 H 10.09375 L 5.515625,4.890625 H 3.875 L 5.296875,0 h -1.625 z m 0,0"
+ id="path4666" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4680"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(635.24928,344.04413)"
+ id="g4678">
+ <g
+ id="g4676">
+ <path
+ d="m 7.28125,-9.5625 h -3.5 v 5.25 c 0,1.261719 0.085938,2.089844 0.265625,2.484375 0.1875,0.398437 0.628906,0.59375 1.328125,0.59375 l 1.953125,-0.125 L 7.4375,0 c -0.980469,0.15625 -1.730469,0.234375 -2.25,0.234375 -1.148438,0 -1.9375,-0.2734375 -2.375,-0.828125 -0.4375,-0.5625 -0.65625,-1.625 -0.65625,-3.1875 V -9.5625 H 0.59375 V -11 h 1.5625 v -3.359375 h 1.625 V -11 h 3.5 z m 0,0"
+ id="path4674" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4688"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(642.96991,344.04413)"
+ id="g4686">
+ <g
+ id="g4684">
+ <path
+ d="m 3.234375,0 h -1.65625 v -15.796875 h 1.65625 v 5.40625 c 1.175781,-0.550781 2.304687,-0.828125 3.390625,-0.828125 1.46875,0 2.453125,0.398438 2.953125,1.1875 0.507813,0.792969 0.765625,2.199219 0.765625,4.21875 V 0 H 8.6875 v -5.765625 c 0,-1.519531 -0.152344,-2.5625 -0.453125,-3.125 C 7.929688,-9.460938 7.300781,-9.75 6.34375,-9.75 c -0.929688,0 -1.824219,0.171875 -2.6875,0.515625 L 3.234375,-9.09375 Z m 0,0"
+ id="path4682" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4696"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(654.7818,344.04413)"
+ id="g4694">
+ <g
+ id="g4692">
+ <path
+ d="m 1.09375,-5.515625 c 0,-2.007813 0.359375,-3.460937 1.078125,-4.359375 0.71875,-0.894531 1.929687,-1.34375 3.640625,-1.34375 1.707031,0 2.914062,0.449219 3.625,1.34375 0.71875,0.898438 1.078125,2.351562 1.078125,4.359375 0,2 -0.339844,3.460937 -1.015625,4.375 -0.679688,0.90625 -1.914062,1.359375 -3.703125,1.359375 -1.78125,0 -3.011719,-0.453125 -3.6875,-1.359375 -0.679687,-0.914063 -1.015625,-2.375 -1.015625,-4.375 z m 1.703125,-0.03125 c 0,1.605469 0.191406,2.730469 0.578125,3.375 0.382812,0.648437 1.195312,0.96875 2.4375,0.96875 1.238281,0 2.050781,-0.316406 2.4375,-0.953125 0.382812,-0.644531 0.578125,-1.773438 0.578125,-3.390625 0,-1.613281 -0.214844,-2.722656 -0.640625,-3.328125 -0.429688,-0.613281 -1.21875,-0.921875 -2.375,-0.921875 -1.148438,0 -1.9375,0.308594 -2.375,0.921875 -0.429688,0.605469 -0.640625,1.714844 -0.640625,3.328125 z m 0,0"
+ id="path4690" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4704"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(666.39573,344.04413)"
+ id="g4702">
+ <g
+ id="g4700">
+ <path
+ d="M 3.234375,0 H 1.578125 V -11 H 3.21875 v 0.765625 c 1.1875,-0.65625 2.320312,-0.984375 3.40625,-0.984375 1.46875,0 2.453125,0.398438 2.953125,1.1875 0.507813,0.792969 0.765625,2.199219 0.765625,4.21875 V 0 h -1.625 v -5.765625 c 0,-1.519531 -0.152344,-2.5625 -0.453125,-3.125 C 7.960938,-9.460938 7.320312,-9.75 6.34375,-9.75 c -0.480469,0 -0.980469,0.074219 -1.5,0.21875 -0.523438,0.136719 -0.917969,0.273438 -1.1875,0.40625 l -0.421875,0.1875 z m 0,0"
+ id="path4698" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4712"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(622.45064,374.79413)"
+ id="g4710">
+ <g
+ id="g4708">
+ <path
+ d="m 0.28125,-13.703125 v -1.515625 h 11 v 1.515625 H 6.640625 V 0 H 4.96875 v -13.703125 z m 0,0"
+ id="path4706" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4720"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(634.02058,374.79413)"
+ id="g4718">
+ <g
+ id="g4716">
+ <path
+ d="m 0.546875,-11 h 1.65625 l 2.75,9.5625 h 0.71875 L 8.453125,-11 H 10.09375 L 5.515625,4.890625 H 3.875 L 5.296875,0 h -1.625 z m 0,0"
+ id="path4714" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4728"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(644.64468,374.79413)"
+ id="g4726">
+ <g
+ id="g4724">
+ <path
+ d="M 1.578125,4.890625 V -11 H 3.21875 v 0.796875 c 1.113281,-0.675781 2.210938,-1.015625 3.296875,-1.015625 1.394531,0 2.40625,0.445312 3.03125,1.328125 C 10.179688,-9.003906 10.5,-7.539062 10.5,-5.5 c 0,2.042969 -0.375,3.507812 -1.125,4.390625 -0.742188,0.886719 -1.964844,1.328125 -3.671875,1.328125 -0.898437,0 -1.71875,-0.078125 -2.46875,-0.234375 v 4.90625 z M 6.265625,-9.75 c -0.4375,0 -0.914063,0.074219 -1.421875,0.21875 -0.5,0.148438 -0.898438,0.292969 -1.1875,0.4375 l -0.421875,0.234375 v 7.40625 c 1.039063,0.167969 1.832031,0.25 2.375,0.25 1.1875,0 2.019531,-0.335937 2.5,-1.015625 0.476563,-0.675781 0.71875,-1.773438 0.71875,-3.296875 0,-1.53125 -0.21875,-2.617187 -0.65625,-3.265625 C 7.742188,-9.425781 7.109375,-9.75 6.265625,-9.75 Z m 0,0"
+ id="path4722" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4736"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(656.23661,374.79413)"
+ id="g4734">
+ <g
+ id="g4732">
+ <path
+ d="M 9.0625,-1.359375 9.703125,-1.4375 9.75,-0.125 C 8.070312,0.101562 6.640625,0.21875 5.453125,0.21875 c -1.585937,0 -2.710937,-0.457031 -3.375,-1.375 C 1.421875,-2.070312 1.09375,-3.5 1.09375,-5.4375 c 0,-3.851562 1.535156,-5.78125 4.609375,-5.78125 1.476563,0 2.582031,0.417969 3.3125,1.25 0.738281,0.824219 1.109375,2.121094 1.109375,3.890625 L 10.03125,-4.8125 H 2.765625 c 0,1.21875 0.21875,2.121094 0.65625,2.703125 0.445313,0.585937 1.21875,0.875 2.3125,0.875 1.09375,0 2.203125,-0.039063 3.328125,-0.125 z m -0.59375,-4.78125 c 0,-1.34375 -0.21875,-2.289063 -0.65625,-2.84375 -0.429688,-0.5625 -1.132812,-0.84375 -2.109375,-0.84375 -0.96875,0 -1.703125,0.292969 -2.203125,0.875 -0.492188,0.585937 -0.742188,1.523437 -0.75,2.8125 z m 0,0"
+ id="path4730" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#61b05d6a70)"
+ id="g4740"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#306998"
+ d="m 125.32813,478.72266 v -43.44532 c 0,-0.52734 0.0508,-1.04687 0.15625,-1.5625 0.10156,-0.51172 0.25,-1.01172 0.45312,-1.49609 0.19922,-0.48828 0.44531,-0.94922 0.73438,-1.38281 0.29296,-0.4375 0.62109,-0.83985 0.99218,-1.21094 0.3711,-0.375 0.77344,-0.70313 1.20703,-0.99609 0.4375,-0.29297 0.89453,-0.53907 1.37891,-0.73829 0.48437,-0.20312 0.98437,-0.35156 1.49609,-0.45703 0.51172,-0.10156 1.03125,-0.15234 1.55469,-0.15234 h 72.875 c 0.52344,0 1.04297,0.0508 1.55859,0.15234 0.51172,0.10547 1.01172,0.25391 1.49219,0.45703 0.48438,0.19922 0.94531,0.44532 1.37891,0.73829 0.4375,0.29296 0.83984,0.62109 1.20703,0.99609 0.37109,0.37109 0.70312,0.77344 0.99219,1.21094 0.29297,0.43359 0.53906,0.89453 0.73828,1.38281 0.19922,0.48437 0.35156,0.98437 0.45312,1.49609 0.10157,0.51563 0.15235,1.03516 0.15235,1.5625 v 43.44532 c 0,0.52343 -0.0508,1.04296 -0.15235,1.55859 -0.10156,0.51562 -0.2539,1.01562 -0.45312,1.5 -0.19922,0.48437 -0.44531,0.94531 -0.73828,1.38281 -0.28907,0.4375 -0.6211,0.83985 -0.99219,1.21094 -0.36719,0.37109 -0.76953,0.70312 -1.20703,0.99219 -0.4336,0.29297 -0.89453,0.53906 -1.37891,0.74218 -0.48047,0.19922 -0.98047,0.35157 -1.49219,0.45313 -0.51562,0.10156 -1.03515,0.15234 -1.55859,0.15234 h -72.875 c -0.52344,0 -1.04297,-0.0508 -1.55469,-0.15234 -0.51172,-0.10156 -1.01172,-0.25391 -1.49609,-0.45313 -0.48438,-0.20312 -0.94141,-0.44921 -1.37891,-0.74218 -0.43359,-0.28907 -0.83593,-0.6211 -1.20703,-0.99219 -0.37109,-0.37109 -0.69922,-0.77344 -0.99218,-1.21094 -0.28907,-0.4375 -0.53516,-0.89844 -0.73438,-1.38281 -0.20312,-0.48438 -0.35156,-0.98438 -0.45312,-1.5 -0.10547,-0.51563 -0.15625,-1.03516 -0.15625,-1.55859 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4738" />
+ </g>
+ <g
+ clip-path="url(#ea42d02648)"
+ id="g4744"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#306998"
+ d="m 214.60547,435.27734 v 43.44141 c 0,0.55469 -0.0508,1.10547 -0.16016,1.65234 -0.10937,0.54297 -0.26953,1.07032 -0.48047,1.58594 -0.21093,0.51172 -0.47265,1 -0.77734,1.46094 -0.30859,0.46094 -0.66016,0.88672 -1.05078,1.28125 -0.39063,0.39453 -0.81641,0.74219 -1.27735,1.05078 -0.46093,0.30859 -0.94531,0.57031 -1.45703,0.78125 -0.51172,0.21484 -1.03906,0.375 -1.58203,0.48047 -0.54297,0.10937 -1.08984,0.16406 -1.64453,0.16406 h -72.87109 c -0.55469,0 -1.10547,-0.0547 -1.64844,-0.16406 -0.54297,-0.10547 -1.07031,-0.26563 -1.57813,-0.48047 -0.51171,-0.21094 -1,-0.47266 -1.46093,-0.78125 -0.46094,-0.30859 -0.88672,-0.65625 -1.27735,-1.05078 -0.39062,-0.39453 -0.73828,-0.82031 -1.04687,-1.28125 -0.30859,-0.46094 -0.56641,-0.94922 -0.78125,-1.46094 -0.21094,-0.51562 -0.37109,-1.04297 -0.47656,-1.58594 -0.10938,-0.54687 -0.16407,-1.09765 -0.16407,-1.65234 v -43.44141 c 0,-0.55468 0.0547,-1.10547 0.16407,-1.65234 0.10547,-0.54297 0.26562,-1.07031 0.47656,-1.58594 0.21484,-0.51172 0.47266,-1 0.78125,-1.46094 0.30859,-0.46093 0.65625,-0.88671 1.04687,-1.28125 0.39063,-0.39453 0.81641,-0.74218 1.27735,-1.05078 0.46093,-0.30859 0.94922,-0.57031 1.46093,-0.78125 0.50782,-0.21484 1.03516,-0.375 1.57813,-0.48047 0.54297,-0.10937 1.09375,-0.16406 1.64844,-0.16406 h 72.87109 c 0.55469,0 1.10156,0.0547 1.64453,0.16406 0.54297,0.10547 1.07031,0.26563 1.58203,0.48047 0.51172,0.21094 1,0.47266 1.45703,0.78125 0.46094,0.3086 0.88672,0.66016 1.27735,1.05078 0.39453,0.39454 0.74219,0.82032 1.05078,1.28125 0.30469,0.46094 0.56641,0.94922 0.77734,1.46094 0.21094,0.51563 0.3711,1.04297 0.48047,1.58985 0.10938,0.54296 0.16016,1.09375 0.16016,1.64843 z m -88.81641,43.44141 c 0,0.49609 0.0469,0.98437 0.14453,1.47266 0.0937,0.48437 0.23829,0.95703 0.42579,1.41406 0.1875,0.45703 0.42187,0.89062 0.69531,1.30078 0.27344,0.41406 0.58594,0.79297 0.93359,1.14453 0.34766,0.34766 0.73047,0.66016 1.14063,0.9375 0.41015,0.27344 0.84375,0.50391 1.29687,0.69531 0.45703,0.1875 0.92578,0.33203 1.41016,0.42969 0.48437,0.0937 0.97265,0.14453 1.46875,0.14453 h 72.87109 c 0.49609,0 0.98438,-0.0508 1.46875,-0.14453 0.48438,-0.0977 0.95313,-0.24219 1.41016,-0.42969 0.45312,-0.1914 0.88672,-0.42187 1.29687,-0.69531 0.41016,-0.27734 0.78906,-0.58984 1.14063,-0.9375 0.34765,-0.35156 0.66015,-0.73047 0.93359,-1.14453 0.27344,-0.41016 0.50781,-0.84375 0.69531,-1.30078 0.1875,-0.45703 0.33203,-0.92969 0.42578,-1.41406 0.0977,-0.48829 0.14454,-0.97657 0.14454,-1.47266 v -43.44141 c 0,-0.49609 -0.0469,-0.98437 -0.14454,-1.47265 -0.0937,-0.48438 -0.23828,-0.95703 -0.42578,-1.41407 -0.1875,-0.45703 -0.42187,-0.89062 -0.69531,-1.30078 -0.27344,-0.41406 -0.58594,-0.79297 -0.93359,-1.14453 -0.35157,-0.34765 -0.73047,-0.66015 -1.14063,-0.9375 -0.41015,-0.27344 -0.84375,-0.5039 -1.29687,-0.69531 -0.45703,-0.1875 -0.92578,-0.33203 -1.41016,-0.42969 -0.48437,-0.0937 -0.97266,-0.14453 -1.46875,-0.14453 h -72.87109 c -0.4961,0 -0.98438,0.0508 -1.46875,0.14453 -0.48438,0.0977 -0.95313,0.24219 -1.41016,0.42969 -0.45312,0.19141 -0.88672,0.42187 -1.29687,0.69531 -0.41016,0.27735 -0.79297,0.58985 -1.14063,0.9375 -0.34765,0.35156 -0.66015,0.73047 -0.93359,1.14453 -0.27344,0.41016 -0.50781,0.84375 -0.69531,1.30078 -0.1875,0.45704 -0.33204,0.92969 -0.42579,1.41407 -0.0977,0.48828 -0.14453,0.97656 -0.14453,1.47265 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4742" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4752"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(143.38693,451.22147)"
+ id="g4750">
+ <g
+ id="g4748">
+ <path
+ d="M 5.875,-4.046875 H 2.8125 V 0 H 1.46875 V -12.015625 H 5.875 c 1.300781,0 2.265625,0.320313 2.890625,0.953125 0.625,0.636719 0.9375,1.609375 0.9375,2.921875 0,2.730469 -1.277344,4.09375 -3.828125,4.09375 z M 2.8125,-5.21875 h 3.03125 c 1.65625,0 2.484375,-0.972656 2.484375,-2.921875 0,-0.925781 -0.199219,-1.601563 -0.59375,-2.03125 -0.386719,-0.4375 -1.015625,-0.65625 -1.890625,-0.65625 H 2.8125 Z m 0,0"
+ id="path4746" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4760"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(153.67768,451.22147)"
+ id="g4758">
+ <g
+ id="g4756">
+ <path
+ d="M 0.4375,-8.671875 H 1.734375 L 3.90625,-1.125 h 0.578125 l 2.1875,-7.546875 H 7.96875 L 4.359375,3.859375 H 3.0625 L 4.1875,0 H 2.90625 Z m 0,0"
+ id="path4754" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4768"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(162.05952,451.22147)"
+ id="g4766">
+ <g
+ id="g4764">
+ <path
+ d="M 5.75,-7.546875 H 2.984375 v 4.140625 c 0,1 0.070313,1.65625 0.21875,1.96875 0.144531,0.3125 0.488281,0.46875 1.03125,0.46875 L 5.78125,-1.078125 5.875,0 C 5.09375,0.125 4.5,0.1875 4.09375,0.1875 3.195312,0.1875 2.570312,-0.03125 2.21875,-0.46875 1.875,-0.90625 1.703125,-1.742188 1.703125,-2.984375 v -4.5625 H 0.46875 v -1.125 h 1.234375 v -2.65625 h 1.28125 v 2.65625 H 5.75 Z m 0,0"
+ id="path4762" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4776"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(168.15067,451.22147)"
+ id="g4774">
+ <g
+ id="g4772">
+ <path
+ d="M 2.546875,0 H 1.25 v -12.46875 h 1.296875 v 4.28125 c 0.925781,-0.445312 1.816406,-0.671875 2.671875,-0.671875 1.164062,0 1.945312,0.3125 2.34375,0.9375 0.394531,0.625 0.59375,1.742187 0.59375,3.34375 V 0 H 6.859375 V -4.546875 C 6.859375,-5.753906 6.738281,-6.578125 6.5,-7.015625 6.257812,-7.460938 5.757812,-7.6875 5,-7.6875 c -0.730469,0 -1.4375,0.132812 -2.125,0.390625 l -0.328125,0.125 z m 0,0"
+ id="path4770" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4784"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(177.4696,451.22147)"
+ id="g4782">
+ <g
+ id="g4780">
+ <path
+ d="m 0.875,-4.359375 c 0,-1.582031 0.28125,-2.726563 0.84375,-3.4375 0.5625,-0.707031 1.515625,-1.0625 2.859375,-1.0625 1.351563,0 2.3125,0.355469 2.875,1.0625 0.5625,0.710937 0.84375,1.855469 0.84375,3.4375 C 8.296875,-2.773438 8.03125,-1.625 7.5,-0.90625 6.96875,-0.1875 5.992188,0.171875 4.578125,0.171875 c -1.40625,0 -2.375,-0.359375 -2.90625,-1.078125 C 1.140625,-1.625 0.875,-2.773438 0.875,-4.359375 Z M 2.203125,-4.375 c 0,1.261719 0.148437,2.148438 0.453125,2.65625 0.3125,0.511719 0.957031,0.765625 1.9375,0.765625 0.976562,0 1.617188,-0.25 1.921875,-0.75 C 6.816406,-2.210938 6.96875,-3.101562 6.96875,-4.375 6.96875,-5.644531 6.796875,-6.519531 6.453125,-7 6.117188,-7.476562 5.5,-7.71875 4.59375,-7.71875 3.6875,-7.71875 3.0625,-7.476562 2.71875,-7 2.375,-6.519531 2.203125,-5.644531 2.203125,-4.375 Z m 0,0"
+ id="path4778" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4792"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(186.63236,451.22147)"
+ id="g4790">
+ <g
+ id="g4788">
+ <path
+ d="M 2.546875,0 H 1.25 v -8.671875 h 1.28125 v 0.59375 c 0.9375,-0.519531 1.832031,-0.78125 2.6875,-0.78125 1.164062,0 1.945312,0.3125 2.34375,0.9375 0.394531,0.625 0.59375,1.742187 0.59375,3.34375 V 0 H 6.875 v -4.546875 c 0,-1.207031 -0.121094,-2.03125 -0.359375,-2.46875 C 6.273438,-7.460938 5.769531,-7.6875 5,-7.6875 c -0.375,0 -0.765625,0.058594 -1.171875,0.171875 -0.40625,0.105469 -0.726563,0.210937 -0.953125,0.3125 l -0.328125,0.15625 z m 0,0"
+ id="path4786" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4800"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(145.18979,475.48154)"
+ id="g4798">
+ <g
+ id="g4796">
+ <path
+ d="m 0.21875,-10.8125 v -1.203125 h 8.6875 V -10.8125 H 5.25 V 0 H 3.921875 v -10.8125 z m 0,0"
+ id="path4794" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4808"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(154.31784,475.48154)"
+ id="g4806">
+ <g
+ id="g4804">
+ <path
+ d="M 0.4375,-8.671875 H 1.734375 L 3.90625,-1.125 h 0.578125 l 2.1875,-7.546875 H 7.96875 L 4.359375,3.859375 H 3.0625 L 4.1875,0 H 2.90625 Z m 0,0"
+ id="path4802" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4816"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(162.69968,475.48154)"
+ id="g4814">
+ <g
+ id="g4812">
+ <path
+ d="M 1.25,3.859375 V -8.671875 H 2.53125 V -8.0625 c 0.882812,-0.53125 1.753906,-0.796875 2.609375,-0.796875 1.09375,0 1.890625,0.355469 2.390625,1.0625 0.5,0.699219 0.75,1.855469 0.75,3.46875 0,1.605469 -0.292969,2.757813 -0.875,3.453125 C 6.820312,-0.175781 5.851562,0.171875 4.5,0.171875 c -0.710938,0 -1.359375,-0.0625 -1.953125,-0.1875 v 3.875 z M 4.953125,-7.6875 c -0.355469,0 -0.730469,0.058594 -1.125,0.171875 C 3.429688,-7.398438 3.113281,-7.285156 2.875,-7.171875 L 2.546875,-7 v 5.859375 c 0.820313,0.125 1.445313,0.1875 1.875,0.1875 0.9375,0 1.59375,-0.265625 1.96875,-0.796875 0.382813,-0.53125 0.578125,-1.394531 0.578125,-2.59375 0,-1.207031 -0.171875,-2.066406 -0.515625,-2.578125 -0.34375,-0.507813 -0.84375,-0.765625 -1.5,-0.765625 z m 0,0"
+ id="path4810" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4824"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(171.84508,475.48154)"
+ id="g4822">
+ <g
+ id="g4820">
+ <path
+ d="m 7.15625,-1.078125 0.5,-0.046875 0.03125,1.015625 C 6.375,0.078125 5.25,0.171875 4.3125,0.171875 3.0625,0.171875 2.175781,-0.1875 1.65625,-0.90625 1.132812,-1.632812 0.875,-2.757812 0.875,-4.28125 c 0,-3.050781 1.207031,-4.578125 3.625,-4.578125 1.164062,0 2.035156,0.328125 2.609375,0.984375 0.582031,0.65625 0.875,1.683594 0.875,3.078125 l -0.0625,1 H 2.1875 c 0,0.960937 0.171875,1.671875 0.515625,2.140625 0.351563,0.460938 0.957031,0.6875 1.8125,0.6875 0.863281,0 1.742187,-0.035156 2.640625,-0.109375 z M 6.6875,-4.84375 c 0,-1.0625 -0.171875,-1.8125 -0.515625,-2.25 C 5.828125,-7.539062 5.269531,-7.765625 4.5,-7.765625 c -0.773438,0 -1.351562,0.234375 -1.734375,0.703125 -0.386719,0.460938 -0.585937,1.199219 -0.59375,2.21875 z m 0,0"
+ id="path4818" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4830"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(180.6087,475.48154)"
+ id="g4828">
+ <g
+ id="g4826" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4838"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(184.42651,475.48154)"
+ id="g4836">
+ <g
+ id="g4834">
+ <path
+ d="M 6.75,-11.453125 V 0 H 5.421875 V -9.96875 L 2.46875,-8.015625 1.859375,-9.03125 5.5,-11.453125 Z m 0,0"
+ id="path4832" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#84bd6662f0)"
+ id="g4842"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#306998"
+ d="m 125.32813,548.84766 v -43.44532 c 0,-0.52343 0.0508,-1.04297 0.15625,-1.55859 0.10156,-0.51563 0.25,-1.01563 0.45312,-1.5 0.19922,-0.48438 0.44531,-0.94531 0.73438,-1.38281 0.29296,-0.4336 0.62109,-0.83985 0.99218,-1.21094 0.3711,-0.37109 0.77344,-0.70313 1.20703,-0.99219 0.4375,-0.29297 0.89453,-0.53906 1.37891,-0.73828 0.48437,-0.20312 0.98437,-0.35547 1.49609,-0.45703 0.51172,-0.10156 1.03125,-0.15234 1.55469,-0.15234 h 72.875 c 0.52344,0 1.04297,0.0508 1.55859,0.15234 0.51172,0.10156 1.01172,0.25391 1.49219,0.45703 0.48438,0.19922 0.94531,0.44531 1.37891,0.73828 0.4375,0.28906 0.83984,0.6211 1.20703,0.99219 0.37109,0.37109 0.70312,0.77734 0.99219,1.21094 0.29297,0.4375 0.53906,0.89843 0.73828,1.38281 0.19922,0.48437 0.35156,0.98437 0.45312,1.5 0.10157,0.51562 0.15235,1.03516 0.15235,1.55859 v 43.44532 c 0,0.52734 -0.0508,1.04687 -0.15235,1.5625 -0.10156,0.51171 -0.2539,1.01171 -0.45312,1.5 -0.19922,0.48437 -0.44531,0.94531 -0.73828,1.3789 -0.28907,0.4375 -0.6211,0.84375 -0.99219,1.21485 -0.36719,0.37109 -0.76953,0.69921 -1.20703,0.99218 -0.4336,0.29297 -0.89453,0.53907 -1.37891,0.73828 -0.48047,0.20313 -0.98047,0.35547 -1.49219,0.45704 -0.51562,0.10156 -1.03515,0.15234 -1.55859,0.15234 h -72.875 c -0.52344,0 -1.04297,-0.0508 -1.55469,-0.15234 -0.51172,-0.10157 -1.01172,-0.25391 -1.49609,-0.45704 -0.48438,-0.19921 -0.94141,-0.44531 -1.37891,-0.73828 -0.43359,-0.29297 -0.83593,-0.62109 -1.20703,-0.99218 -0.37109,-0.3711 -0.69922,-0.77735 -0.99218,-1.21485 -0.28907,-0.43359 -0.53516,-0.89453 -0.73438,-1.3789 -0.20312,-0.48829 -0.35156,-0.98829 -0.45312,-1.5 -0.10547,-0.51563 -0.15625,-1.03516 -0.15625,-1.5625 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4840" />
+ </g>
+ <g
+ clip-path="url(#728d290ff8)"
+ id="g4846"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#306998"
+ d="m 214.60547,505.40234 v 43.44532 c 0,0.55468 -0.0508,1.10546 -0.16016,1.64843 -0.10937,0.54688 -0.26953,1.07422 -0.48047,1.58594 -0.21093,0.51563 -0.47265,1 -0.77734,1.46484 -0.30859,0.46094 -0.66016,0.88672 -1.05078,1.28125 -0.39063,0.39063 -0.81641,0.74219 -1.27735,1.05079 -0.46093,0.30859 -0.94531,0.57031 -1.45703,0.78125 -0.51172,0.21093 -1.03906,0.37109 -1.58203,0.48046 -0.54297,0.10938 -1.08984,0.16407 -1.64453,0.16407 h -72.87109 c -0.55469,0 -1.10547,-0.0547 -1.64844,-0.16407 -0.54297,-0.10937 -1.07031,-0.26953 -1.57813,-0.48046 -0.51171,-0.21094 -1,-0.47266 -1.46093,-0.78125 -0.46094,-0.3086 -0.88672,-0.66016 -1.27735,-1.05079 -0.39062,-0.39453 -0.73828,-0.82031 -1.04687,-1.28125 -0.30859,-0.46484 -0.56641,-0.94921 -0.78125,-1.46484 -0.21094,-0.51172 -0.37109,-1.03906 -0.47656,-1.58594 -0.10938,-0.54297 -0.16407,-1.09375 -0.16407,-1.64843 v -43.44532 c 0,-0.55468 0.0547,-1.10156 0.16407,-1.64843 0.10547,-0.54297 0.26562,-1.07422 0.47656,-1.58594 0.21484,-0.51172 0.47266,-1 0.78125,-1.46094 0.30859,-0.46094 0.65625,-0.89062 1.04687,-1.28125 0.39063,-0.39453 0.81641,-0.74609 1.27735,-1.05469 0.46093,-0.30859 0.94922,-0.5664 1.46093,-0.78125 0.50782,-0.21093 1.03516,-0.37109 1.57813,-0.48047 0.54297,-0.10937 1.09375,-0.16015 1.64844,-0.16015 h 72.87109 c 0.55469,0 1.10156,0.0547 1.64453,0.16015 0.54297,0.10938 1.07031,0.26954 1.58203,0.48438 0.51172,0.21094 1,0.47266 1.45703,0.78125 0.46094,0.30859 0.88672,0.65625 1.27735,1.05078 0.39453,0.39063 0.74219,0.82031 1.05078,1.28125 0.30469,0.46094 0.56641,0.94922 0.77734,1.46094 0.21094,0.51172 0.3711,1.04297 0.48047,1.58594 0.10938,0.54687 0.16016,1.09375 0.16016,1.64843 z m -88.81641,43.44532 c 0,0.49609 0.0469,0.98437 0.14453,1.46875 0.0937,0.48828 0.23829,0.95703 0.42579,1.41406 0.1875,0.45703 0.42187,0.89453 0.69531,1.30469 0.27344,0.41015 0.58594,0.79296 0.93359,1.14062 0.34766,0.35156 0.73047,0.66406 1.14063,0.9375 0.41015,0.27734 0.84375,0.50781 1.29687,0.69922 0.45703,0.1875 0.92578,0.33203 1.41016,0.42578 0.48437,0.0977 0.97265,0.14453 1.46875,0.14453 h 72.87109 c 0.49609,0 0.98438,-0.0469 1.46875,-0.14453 0.48438,-0.0937 0.95313,-0.23828 1.41016,-0.42578 0.45312,-0.19141 0.88672,-0.42188 1.29687,-0.69922 0.41016,-0.27344 0.78906,-0.58594 1.14063,-0.9375 0.34765,-0.34766 0.66015,-0.73047 0.93359,-1.14062 0.27344,-0.41016 0.50781,-0.84766 0.69531,-1.30469 0.1875,-0.45703 0.33203,-0.92578 0.42578,-1.41406 0.0977,-0.48438 0.14454,-0.97266 0.14454,-1.46875 v -43.44532 c 0,-0.49218 -0.0469,-0.98437 -0.14454,-1.46875 -0.0937,-0.48437 -0.23828,-0.95703 -0.42578,-1.41406 -0.1875,-0.45703 -0.42187,-0.89062 -0.69531,-1.30469 -0.27344,-0.41015 -0.58594,-0.78906 -0.93359,-1.14062 -0.35157,-0.35156 -0.73047,-0.66406 -1.14063,-0.9375 -0.41015,-0.27344 -0.84375,-0.50781 -1.29687,-0.69531 -0.45703,-0.19141 -0.92578,-0.33204 -1.41016,-0.42969 -0.48437,-0.0977 -0.97266,-0.14453 -1.46875,-0.14453 h -72.87109 c -0.4961,0 -0.98438,0.0469 -1.46875,0.14453 -0.48438,0.0976 -0.95313,0.23828 -1.41016,0.42969 -0.45312,0.1875 -0.88672,0.42187 -1.29687,0.69531 -0.41016,0.27344 -0.79297,0.58594 -1.14063,0.9375 -0.34765,0.35156 -0.66015,0.73047 -0.93359,1.14062 -0.27344,0.41407 -0.50781,0.84766 -0.69531,1.30469 -0.1875,0.45703 -0.33204,0.92969 -0.42579,1.41406 -0.0977,0.48438 -0.14453,0.97657 -0.14453,1.46875 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4844" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4854"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(143.38693,521.34911)"
+ id="g4852">
+ <g
+ id="g4850">
+ <path
+ d="M 5.875,-4.046875 H 2.8125 V 0 H 1.46875 V -12.015625 H 5.875 c 1.300781,0 2.265625,0.320313 2.890625,0.953125 0.625,0.636719 0.9375,1.609375 0.9375,2.921875 0,2.730469 -1.277344,4.09375 -3.828125,4.09375 z M 2.8125,-5.21875 h 3.03125 c 1.65625,0 2.484375,-0.972656 2.484375,-2.921875 0,-0.925781 -0.199219,-1.601563 -0.59375,-2.03125 -0.386719,-0.4375 -1.015625,-0.65625 -1.890625,-0.65625 H 2.8125 Z m 0,0"
+ id="path4848" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4862"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(153.67768,521.34911)"
+ id="g4860">
+ <g
+ id="g4858">
+ <path
+ d="M 0.4375,-8.671875 H 1.734375 L 3.90625,-1.125 h 0.578125 l 2.1875,-7.546875 H 7.96875 L 4.359375,3.859375 H 3.0625 L 4.1875,0 H 2.90625 Z m 0,0"
+ id="path4856" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4870"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(162.05952,521.34911)"
+ id="g4868">
+ <g
+ id="g4866">
+ <path
+ d="M 5.75,-7.546875 H 2.984375 v 4.140625 c 0,1 0.070313,1.65625 0.21875,1.96875 0.144531,0.3125 0.488281,0.46875 1.03125,0.46875 L 5.78125,-1.078125 5.875,0 C 5.09375,0.125 4.5,0.1875 4.09375,0.1875 3.195312,0.1875 2.570312,-0.03125 2.21875,-0.46875 1.875,-0.90625 1.703125,-1.742188 1.703125,-2.984375 v -4.5625 H 0.46875 v -1.125 h 1.234375 v -2.65625 h 1.28125 v 2.65625 H 5.75 Z m 0,0"
+ id="path4864" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4878"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(168.15067,521.34911)"
+ id="g4876">
+ <g
+ id="g4874">
+ <path
+ d="M 2.546875,0 H 1.25 v -12.46875 h 1.296875 v 4.28125 c 0.925781,-0.445312 1.816406,-0.671875 2.671875,-0.671875 1.164062,0 1.945312,0.3125 2.34375,0.9375 0.394531,0.625 0.59375,1.742187 0.59375,3.34375 V 0 H 6.859375 V -4.546875 C 6.859375,-5.753906 6.738281,-6.578125 6.5,-7.015625 6.257812,-7.460938 5.757812,-7.6875 5,-7.6875 c -0.730469,0 -1.4375,0.132812 -2.125,0.390625 l -0.328125,0.125 z m 0,0"
+ id="path4872" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4886"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(177.4696,521.34911)"
+ id="g4884">
+ <g
+ id="g4882">
+ <path
+ d="m 0.875,-4.359375 c 0,-1.582031 0.28125,-2.726563 0.84375,-3.4375 0.5625,-0.707031 1.515625,-1.0625 2.859375,-1.0625 1.351563,0 2.3125,0.355469 2.875,1.0625 0.5625,0.710937 0.84375,1.855469 0.84375,3.4375 C 8.296875,-2.773438 8.03125,-1.625 7.5,-0.90625 6.96875,-0.1875 5.992188,0.171875 4.578125,0.171875 c -1.40625,0 -2.375,-0.359375 -2.90625,-1.078125 C 1.140625,-1.625 0.875,-2.773438 0.875,-4.359375 Z M 2.203125,-4.375 c 0,1.261719 0.148437,2.148438 0.453125,2.65625 0.3125,0.511719 0.957031,0.765625 1.9375,0.765625 0.976562,0 1.617188,-0.25 1.921875,-0.75 C 6.816406,-2.210938 6.96875,-3.101562 6.96875,-4.375 6.96875,-5.644531 6.796875,-6.519531 6.453125,-7 6.117188,-7.476562 5.5,-7.71875 4.59375,-7.71875 3.6875,-7.71875 3.0625,-7.476562 2.71875,-7 2.375,-6.519531 2.203125,-5.644531 2.203125,-4.375 Z m 0,0"
+ id="path4880" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4894"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(186.63236,521.34911)"
+ id="g4892">
+ <g
+ id="g4890">
+ <path
+ d="M 2.546875,0 H 1.25 v -8.671875 h 1.28125 v 0.59375 c 0.9375,-0.519531 1.832031,-0.78125 2.6875,-0.78125 1.164062,0 1.945312,0.3125 2.34375,0.9375 0.394531,0.625 0.59375,1.742187 0.59375,3.34375 V 0 H 6.875 v -4.546875 c 0,-1.207031 -0.121094,-2.03125 -0.359375,-2.46875 C 6.273438,-7.460938 5.769531,-7.6875 5,-7.6875 c -0.375,0 -0.765625,0.058594 -1.171875,0.171875 -0.40625,0.105469 -0.726563,0.210937 -0.953125,0.3125 l -0.328125,0.15625 z m 0,0"
+ id="path4888" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4902"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(145.18979,545.60918)"
+ id="g4900">
+ <g
+ id="g4898">
+ <path
+ d="m 0.21875,-10.8125 v -1.203125 h 8.6875 V -10.8125 H 5.25 V 0 H 3.921875 v -10.8125 z m 0,0"
+ id="path4896" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4910"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(154.31784,545.60918)"
+ id="g4908">
+ <g
+ id="g4906">
+ <path
+ d="M 0.4375,-8.671875 H 1.734375 L 3.90625,-1.125 h 0.578125 l 2.1875,-7.546875 H 7.96875 L 4.359375,3.859375 H 3.0625 L 4.1875,0 H 2.90625 Z m 0,0"
+ id="path4904" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4918"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(162.69968,545.60918)"
+ id="g4916">
+ <g
+ id="g4914">
+ <path
+ d="M 1.25,3.859375 V -8.671875 H 2.53125 V -8.0625 c 0.882812,-0.53125 1.753906,-0.796875 2.609375,-0.796875 1.09375,0 1.890625,0.355469 2.390625,1.0625 0.5,0.699219 0.75,1.855469 0.75,3.46875 0,1.605469 -0.292969,2.757813 -0.875,3.453125 C 6.820312,-0.175781 5.851562,0.171875 4.5,0.171875 c -0.710938,0 -1.359375,-0.0625 -1.953125,-0.1875 v 3.875 z M 4.953125,-7.6875 c -0.355469,0 -0.730469,0.058594 -1.125,0.171875 C 3.429688,-7.398438 3.113281,-7.285156 2.875,-7.171875 L 2.546875,-7 v 5.859375 c 0.820313,0.125 1.445313,0.1875 1.875,0.1875 0.9375,0 1.59375,-0.265625 1.96875,-0.796875 0.382813,-0.53125 0.578125,-1.394531 0.578125,-2.59375 0,-1.207031 -0.171875,-2.066406 -0.515625,-2.578125 -0.34375,-0.507813 -0.84375,-0.765625 -1.5,-0.765625 z m 0,0"
+ id="path4912" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4926"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(171.84508,545.60918)"
+ id="g4924">
+ <g
+ id="g4922">
+ <path
+ d="m 7.15625,-1.078125 0.5,-0.046875 0.03125,1.015625 C 6.375,0.078125 5.25,0.171875 4.3125,0.171875 3.0625,0.171875 2.175781,-0.1875 1.65625,-0.90625 1.132812,-1.632812 0.875,-2.757812 0.875,-4.28125 c 0,-3.050781 1.207031,-4.578125 3.625,-4.578125 1.164062,0 2.035156,0.328125 2.609375,0.984375 0.582031,0.65625 0.875,1.683594 0.875,3.078125 l -0.0625,1 H 2.1875 c 0,0.960937 0.171875,1.671875 0.515625,2.140625 0.351563,0.460938 0.957031,0.6875 1.8125,0.6875 0.863281,0 1.742187,-0.035156 2.640625,-0.109375 z M 6.6875,-4.84375 c 0,-1.0625 -0.171875,-1.8125 -0.515625,-2.25 C 5.828125,-7.539062 5.269531,-7.765625 4.5,-7.765625 c -0.773438,0 -1.351562,0.234375 -1.734375,0.703125 -0.386719,0.460938 -0.585937,1.199219 -0.59375,2.21875 z m 0,0"
+ id="path4920" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4932"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(180.6087,545.60918)"
+ id="g4930">
+ <g
+ id="g4928" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4940"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(184.42651,545.60918)"
+ id="g4938">
+ <g
+ id="g4936">
+ <path
+ d="m 8.515625,0 h -7.3125 v -1.125 l 3.34375,-3.53125 c 0.582031,-0.601562 1.003906,-1.0625 1.265625,-1.375 0.269531,-0.3125 0.507812,-0.679688 0.71875,-1.109375 0.21875,-0.425781 0.328125,-0.851563 0.328125,-1.28125 0,-0.738281 -0.203125,-1.257813 -0.609375,-1.5625 -0.40625,-0.300781 -1.039062,-0.453125 -1.890625,-0.453125 -0.75,0 -1.589844,0.101562 -2.515625,0.296875 l -0.453125,0.09375 -0.109375,-1.109375 c 1.101562,-0.3125 2.238281,-0.46875 3.40625,-0.46875 1.164062,0 2.046875,0.246094 2.640625,0.734375 0.601563,0.492187 0.90625,1.265625 0.90625,2.328125 0,0.8125 -0.183594,1.523438 -0.546875,2.125 -0.355469,0.605469 -0.976562,1.328125 -1.859375,2.171875 L 2.78125,-1.15625 h 5.734375 z m 0,0"
+ id="path4934" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#00b091b271)"
+ id="g4944"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#306998"
+ d="m 125.32813,618.67969 v -43.44532 c 0,-0.52343 0.0508,-1.04687 0.15625,-1.55859 0.10156,-0.51562 0.25,-1.01562 0.45312,-1.5 0.19922,-0.48437 0.44531,-0.94531 0.73438,-1.38281 0.29296,-0.4375 0.62109,-0.83985 0.99218,-1.21094 0.3711,-0.37109 0.77344,-0.70312 1.20703,-0.99609 0.4375,-0.28907 0.89453,-0.53907 1.37891,-0.73828 0.48437,-0.19922 0.98437,-0.35157 1.49609,-0.45313 0.51172,-0.10547 1.03125,-0.15625 1.55469,-0.15625 h 72.875 c 0.52344,0 1.04297,0.0508 1.55859,0.15625 0.51172,0.10156 1.01172,0.25391 1.49219,0.45313 0.48438,0.19921 0.94531,0.44921 1.37891,0.73828 0.4375,0.29297 0.83984,0.625 1.20703,0.99609 0.37109,0.37109 0.70312,0.77344 0.99219,1.21094 0.29297,0.4375 0.53906,0.89844 0.73828,1.38281 0.19922,0.48438 0.35156,0.98438 0.45312,1.5 0.10157,0.51172 0.15235,1.03516 0.15235,1.55859 v 43.44532 c 0,0.52343 -0.0508,1.04297 -0.15235,1.55859 -0.10156,0.51563 -0.2539,1.01563 -0.45312,1.5 -0.19922,0.48438 -0.44531,0.94531 -0.73828,1.38281 -0.28907,0.4375 -0.6211,0.83985 -0.99219,1.21094 -0.36719,0.37109 -0.76953,0.70313 -1.20703,0.99609 -0.4336,0.28907 -0.89453,0.53516 -1.37891,0.73829 -0.48047,0.19921 -0.98047,0.35156 -1.49219,0.45312 -0.51562,0.10547 -1.03515,0.15625 -1.55859,0.15625 h -72.875 c -0.52344,0 -1.04297,-0.0508 -1.55469,-0.15625 -0.51172,-0.10156 -1.01172,-0.25391 -1.49609,-0.45312 -0.48438,-0.20313 -0.94141,-0.44922 -1.37891,-0.73829 -0.43359,-0.29296 -0.83593,-0.625 -1.20703,-0.99609 -0.37109,-0.37109 -0.69922,-0.77344 -0.99218,-1.21094 -0.28907,-0.4375 -0.53516,-0.89843 -0.73438,-1.38281 -0.20312,-0.48437 -0.35156,-0.98437 -0.45312,-1.5 -0.10547,-0.51562 -0.15625,-1.03516 -0.15625,-1.55859 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4942" />
+ </g>
+ <g
+ clip-path="url(#be13ebcaaa)"
+ id="g4948"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#306998"
+ d="m 214.60547,575.23437 v 43.44141 c 0,0.55859 -0.0508,1.10547 -0.16016,1.65234 -0.10937,0.54297 -0.26953,1.07422 -0.48047,1.58594 -0.21093,0.51172 -0.47265,1 -0.77734,1.46094 -0.30859,0.46094 -0.66016,0.89062 -1.05078,1.28125 -0.39063,0.39453 -0.81641,0.74219 -1.27735,1.05078 -0.46093,0.30859 -0.94531,0.57031 -1.45703,0.78125 -0.51172,0.21484 -1.03906,0.375 -1.58203,0.48438 -0.54297,0.10546 -1.08984,0.16015 -1.64453,0.16015 h -72.87109 c -0.55469,0 -1.10547,-0.0547 -1.64844,-0.16015 -0.54297,-0.10938 -1.07031,-0.26954 -1.57813,-0.48438 -0.51171,-0.21094 -1,-0.47266 -1.46093,-0.78125 -0.46094,-0.30859 -0.88672,-0.65625 -1.27735,-1.05078 -0.39062,-0.39063 -0.73828,-0.82031 -1.04687,-1.28125 -0.30859,-0.46094 -0.56641,-0.94922 -0.78125,-1.46094 -0.21094,-0.51172 -0.37109,-1.04297 -0.47656,-1.58594 -0.10938,-0.54687 -0.16407,-1.09375 -0.16407,-1.65234 v -43.44141 c 0,-0.55468 0.0547,-1.10546 0.16407,-1.64843 0.10547,-0.54688 0.26562,-1.07422 0.47656,-1.58594 0.21484,-0.51563 0.47266,-1.00391 0.78125,-1.46484 0.30859,-0.46094 0.65625,-0.88672 1.04687,-1.28125 0.39063,-0.39063 0.81641,-0.74219 1.27735,-1.05079 0.46093,-0.30859 0.94922,-0.57031 1.46093,-0.78125 0.50782,-0.21484 1.03516,-0.375 1.57813,-0.48046 0.54297,-0.10938 1.09375,-0.16407 1.64844,-0.16407 h 72.87109 c 0.55469,0 1.10156,0.0547 1.64453,0.16407 0.54297,0.10937 1.07031,0.26953 1.58203,0.48046 0.51172,0.21094 1,0.47266 1.45703,0.78125 0.46094,0.3086 0.88672,0.66016 1.27735,1.05079 0.39453,0.39453 0.74219,0.82031 1.05078,1.28125 0.30469,0.46484 0.56641,0.94921 0.77734,1.46484 0.21094,0.51172 0.3711,1.03906 0.48047,1.58594 0.10938,0.54297 0.16016,1.09375 0.16016,1.64843 z m -88.81641,43.44141 c 0,0.49609 0.0469,0.98828 0.14453,1.47266 0.0937,0.48437 0.23829,0.95703 0.42579,1.41406 0.1875,0.45703 0.42187,0.89062 0.69531,1.30078 0.27344,0.41406 0.58594,0.79297 0.93359,1.14453 0.34766,0.34766 0.73047,0.66016 1.14063,0.9375 0.41015,0.27344 0.84375,0.50781 1.29687,0.69531 0.45703,0.19141 0.92578,0.33204 1.41016,0.42969 0.48437,0.0977 0.97265,0.14453 1.46875,0.14453 h 72.87109 c 0.49609,0 0.98438,-0.0469 1.46875,-0.14453 0.48438,-0.0976 0.95313,-0.23828 1.41016,-0.42969 0.45312,-0.1875 0.88672,-0.42187 1.29687,-0.69531 0.41016,-0.27734 0.78906,-0.58984 1.14063,-0.9375 0.34765,-0.35156 0.66015,-0.73047 0.93359,-1.14453 0.27344,-0.41016 0.50781,-0.84375 0.69531,-1.30078 0.1875,-0.45703 0.33203,-0.92969 0.42578,-1.41406 0.0977,-0.48438 0.14454,-0.97657 0.14454,-1.47266 v -43.44141 c 0,-0.49609 -0.0469,-0.98437 -0.14454,-1.46875 -0.0937,-0.48828 -0.23828,-0.95703 -0.42578,-1.41406 -0.1875,-0.45703 -0.42187,-0.89453 -0.69531,-1.30469 -0.27344,-0.41015 -0.58594,-0.79296 -0.93359,-1.14062 -0.35157,-0.35156 -0.73047,-0.66406 -1.14063,-0.9375 -0.41015,-0.27734 -0.84375,-0.50781 -1.29687,-0.69922 -0.45703,-0.1875 -0.92578,-0.33203 -1.41016,-0.42969 -0.48437,-0.0937 -0.97266,-0.14453 -1.46875,-0.14453 h -72.87109 c -0.4961,0 -0.98438,0.0508 -1.46875,0.14453 -0.48438,0.0977 -0.95313,0.24219 -1.41016,0.42969 -0.45312,0.19141 -0.88672,0.42188 -1.29687,0.69922 -0.41016,0.27344 -0.79297,0.58594 -1.14063,0.9375 -0.34765,0.34766 -0.66015,0.73047 -0.93359,1.14062 -0.27344,0.41016 -0.50781,0.84766 -0.69531,1.30469 -0.1875,0.45703 -0.33204,0.92578 -0.42579,1.41406 -0.0977,0.48438 -0.14453,0.97266 -0.14453,1.46875 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path4946" />
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4956"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(143.38693,591.17926)"
+ id="g4954">
+ <g
+ id="g4952">
+ <path
+ d="M 5.875,-4.046875 H 2.8125 V 0 H 1.46875 V -12.015625 H 5.875 c 1.300781,0 2.265625,0.320313 2.890625,0.953125 0.625,0.636719 0.9375,1.609375 0.9375,2.921875 0,2.730469 -1.277344,4.09375 -3.828125,4.09375 z M 2.8125,-5.21875 h 3.03125 c 1.65625,0 2.484375,-0.972656 2.484375,-2.921875 0,-0.925781 -0.199219,-1.601563 -0.59375,-2.03125 -0.386719,-0.4375 -1.015625,-0.65625 -1.890625,-0.65625 H 2.8125 Z m 0,0"
+ id="path4950" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4964"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(153.67768,591.17926)"
+ id="g4962">
+ <g
+ id="g4960">
+ <path
+ d="M 0.4375,-8.671875 H 1.734375 L 3.90625,-1.125 h 0.578125 l 2.1875,-7.546875 H 7.96875 L 4.359375,3.859375 H 3.0625 L 4.1875,0 H 2.90625 Z m 0,0"
+ id="path4958" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4972"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(162.05952,591.17926)"
+ id="g4970">
+ <g
+ id="g4968">
+ <path
+ d="M 5.75,-7.546875 H 2.984375 v 4.140625 c 0,1 0.070313,1.65625 0.21875,1.96875 0.144531,0.3125 0.488281,0.46875 1.03125,0.46875 L 5.78125,-1.078125 5.875,0 C 5.09375,0.125 4.5,0.1875 4.09375,0.1875 3.195312,0.1875 2.570312,-0.03125 2.21875,-0.46875 1.875,-0.90625 1.703125,-1.742188 1.703125,-2.984375 v -4.5625 H 0.46875 v -1.125 h 1.234375 v -2.65625 h 1.28125 v 2.65625 H 5.75 Z m 0,0"
+ id="path4966" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4980"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(168.15067,591.17926)"
+ id="g4978">
+ <g
+ id="g4976">
+ <path
+ d="M 2.546875,0 H 1.25 v -12.46875 h 1.296875 v 4.28125 c 0.925781,-0.445312 1.816406,-0.671875 2.671875,-0.671875 1.164062,0 1.945312,0.3125 2.34375,0.9375 0.394531,0.625 0.59375,1.742187 0.59375,3.34375 V 0 H 6.859375 V -4.546875 C 6.859375,-5.753906 6.738281,-6.578125 6.5,-7.015625 6.257812,-7.460938 5.757812,-7.6875 5,-7.6875 c -0.730469,0 -1.4375,0.132812 -2.125,0.390625 l -0.328125,0.125 z m 0,0"
+ id="path4974" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4988"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(177.4696,591.17926)"
+ id="g4986">
+ <g
+ id="g4984">
+ <path
+ d="m 0.875,-4.359375 c 0,-1.582031 0.28125,-2.726563 0.84375,-3.4375 0.5625,-0.707031 1.515625,-1.0625 2.859375,-1.0625 1.351563,0 2.3125,0.355469 2.875,1.0625 0.5625,0.710937 0.84375,1.855469 0.84375,3.4375 C 8.296875,-2.773438 8.03125,-1.625 7.5,-0.90625 6.96875,-0.1875 5.992188,0.171875 4.578125,0.171875 c -1.40625,0 -2.375,-0.359375 -2.90625,-1.078125 C 1.140625,-1.625 0.875,-2.773438 0.875,-4.359375 Z M 2.203125,-4.375 c 0,1.261719 0.148437,2.148438 0.453125,2.65625 0.3125,0.511719 0.957031,0.765625 1.9375,0.765625 0.976562,0 1.617188,-0.25 1.921875,-0.75 C 6.816406,-2.210938 6.96875,-3.101562 6.96875,-4.375 6.96875,-5.644531 6.796875,-6.519531 6.453125,-7 6.117188,-7.476562 5.5,-7.71875 4.59375,-7.71875 3.6875,-7.71875 3.0625,-7.476562 2.71875,-7 2.375,-6.519531 2.203125,-5.644531 2.203125,-4.375 Z m 0,0"
+ id="path4982" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g4996"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(186.63236,591.17926)"
+ id="g4994">
+ <g
+ id="g4992">
+ <path
+ d="M 2.546875,0 H 1.25 v -8.671875 h 1.28125 v 0.59375 c 0.9375,-0.519531 1.832031,-0.78125 2.6875,-0.78125 1.164062,0 1.945312,0.3125 2.34375,0.9375 0.394531,0.625 0.59375,1.742187 0.59375,3.34375 V 0 H 6.875 v -4.546875 c 0,-1.207031 -0.121094,-2.03125 -0.359375,-2.46875 C 6.273438,-7.460938 5.769531,-7.6875 5,-7.6875 c -0.375,0 -0.765625,0.058594 -1.171875,0.171875 -0.40625,0.105469 -0.726563,0.210937 -0.953125,0.3125 l -0.328125,0.15625 z m 0,0"
+ id="path4990" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g5004"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(145.18979,615.43933)"
+ id="g5002">
+ <g
+ id="g5000">
+ <path
+ d="m 0.21875,-10.8125 v -1.203125 h 8.6875 V -10.8125 H 5.25 V 0 H 3.921875 v -10.8125 z m 0,0"
+ id="path4998" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g5012"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(154.31784,615.43933)"
+ id="g5010">
+ <g
+ id="g5008">
+ <path
+ d="M 0.4375,-8.671875 H 1.734375 L 3.90625,-1.125 h 0.578125 l 2.1875,-7.546875 H 7.96875 L 4.359375,3.859375 H 3.0625 L 4.1875,0 H 2.90625 Z m 0,0"
+ id="path5006" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g5020"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(162.69968,615.43933)"
+ id="g5018">
+ <g
+ id="g5016">
+ <path
+ d="M 1.25,3.859375 V -8.671875 H 2.53125 V -8.0625 c 0.882812,-0.53125 1.753906,-0.796875 2.609375,-0.796875 1.09375,0 1.890625,0.355469 2.390625,1.0625 0.5,0.699219 0.75,1.855469 0.75,3.46875 0,1.605469 -0.292969,2.757813 -0.875,3.453125 C 6.820312,-0.175781 5.851562,0.171875 4.5,0.171875 c -0.710938,0 -1.359375,-0.0625 -1.953125,-0.1875 v 3.875 z M 4.953125,-7.6875 c -0.355469,0 -0.730469,0.058594 -1.125,0.171875 C 3.429688,-7.398438 3.113281,-7.285156 2.875,-7.171875 L 2.546875,-7 v 5.859375 c 0.820313,0.125 1.445313,0.1875 1.875,0.1875 0.9375,0 1.59375,-0.265625 1.96875,-0.796875 0.382813,-0.53125 0.578125,-1.394531 0.578125,-2.59375 0,-1.207031 -0.171875,-2.066406 -0.515625,-2.578125 -0.34375,-0.507813 -0.84375,-0.765625 -1.5,-0.765625 z m 0,0"
+ id="path5014" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g5028"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(171.84508,615.43933)"
+ id="g5026">
+ <g
+ id="g5024">
+ <path
+ d="m 7.15625,-1.078125 0.5,-0.046875 0.03125,1.015625 C 6.375,0.078125 5.25,0.171875 4.3125,0.171875 3.0625,0.171875 2.175781,-0.1875 1.65625,-0.90625 1.132812,-1.632812 0.875,-2.757812 0.875,-4.28125 c 0,-3.050781 1.207031,-4.578125 3.625,-4.578125 1.164062,0 2.035156,0.328125 2.609375,0.984375 0.582031,0.65625 0.875,1.683594 0.875,3.078125 l -0.0625,1 H 2.1875 c 0,0.960937 0.171875,1.671875 0.515625,2.140625 0.351563,0.460938 0.957031,0.6875 1.8125,0.6875 0.863281,0 1.742187,-0.035156 2.640625,-0.109375 z M 6.6875,-4.84375 c 0,-1.0625 -0.171875,-1.8125 -0.515625,-2.25 C 5.828125,-7.539062 5.269531,-7.765625 4.5,-7.765625 c -0.773438,0 -1.351562,0.234375 -1.734375,0.703125 -0.386719,0.460938 -0.585937,1.199219 -0.59375,2.21875 z m 0,0"
+ id="path5022" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g5034"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(180.6087,615.43933)"
+ id="g5032">
+ <g
+ id="g5030" />
+ </g>
+ </g>
+ <g
+ fill="#fefeff"
+ fill-opacity="1"
+ id="g5042"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ transform="translate(184.42651,615.43933)"
+ id="g5040">
+ <g
+ id="g5038">
+ <path
+ d="m 1.25,-11.15625 c 1.082031,-0.320312 2.242188,-0.484375 3.484375,-0.484375 1.25,0 2.148437,0.242187 2.703125,0.71875 0.5625,0.46875 0.84375,1.226563 0.84375,2.265625 0,0.53125 -0.074219,0.917969 -0.21875,1.15625 -0.148438,0.230469 -0.261719,0.414062 -0.34375,0.546875 -0.085938,0.125 -0.199219,0.246094 -0.34375,0.359375 -0.25,0.199219 -0.453125,0.335938 -0.609375,0.40625 l -0.1875,0.125 c 0.675781,0.25 1.175781,0.5625 1.5,0.9375 0.320313,0.375 0.484375,0.992188 0.484375,1.84375 0,1.167969 -0.304688,2.039062 -0.90625,2.609375 -0.59375,0.5625 -1.53125,0.84375 -2.8125,0.84375 -1.023438,0 -2.101562,-0.1171875 -3.234375,-0.34375 l -0.53125,-0.125 0.125,-1.09375 C 2.453125,-1.128906 3.617188,-1 4.703125,-1 6.359375,-1.019531 7.1875,-1.765625 7.1875,-3.234375 c 0,-1.375 -0.789062,-2.085937 -2.359375,-2.140625 h -2.3125 v -1.15625 h 2.3125 c 0.488281,0 0.957031,-0.191406 1.40625,-0.578125 0.445313,-0.382813 0.671875,-0.894531 0.671875,-1.53125 0,-0.632813 -0.183594,-1.09375 -0.546875,-1.375 -0.355469,-0.289063 -0.953125,-0.4375 -1.796875,-0.4375 -0.929688,0 -1.839844,0.08984 -2.734375,0.265625 L 1.375,-10.109375 Z m 0,0"
+ id="path5036" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#12ef88673f)"
+ id="g5046"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#000000"
+ d="m 293.44922,366.47266 15.07422,-14.98829 -15.07422,-15.01171 -3.37891,3.36328 9.27344,9.26562 h -56.76953 v 4.76563 h 56.76953 l -9.27344,9.23828 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path5044" />
+ </g>
+ <g
+ clip-path="url(#4425bd08fe)"
+ id="g5050"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#000000"
+ d="m 554.83203,366.47266 15.07422,-14.98829 -15.07422,-15.01171 -3.38281,3.36328 9.27344,9.26562 h -56.76954 v 4.76563 h 56.76954 l -9.27344,9.23828 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path5048" />
+ </g>
+ <g
+ clip-path="url(#29f410bb45)"
+ id="g5054"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#000000"
+ d="m 554.83203,542.04297 15.07422,-14.98438 -15.07422,-15.01562 -3.38281,3.36719 9.27344,9.26562 h -56.76954 v 4.76563 h 56.76954 l -9.27344,9.23828 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path5052" />
+ </g>
+ <g
+ clip-path="url(#8612924f50)"
+ id="g5058"
+ transform="translate(-69.242111,-250.64609)">
+ <path
+ fill="#000000"
+ d="m 287.44531,541.73437 15.07422,-14.98828 -15.07422,-15.01172 -3.3789,3.36329 9.26953,9.26562 h -56.76953 v 4.76953 h 56.76953 l -9.26953,9.23438 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path5056" />
+ </g>
+ <g
+ clip-path="url(#9616827f5c)"
+ id="g5068"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ clip-path="url(#6d6215aef9)"
+ id="g5066">
+ <g
+ clip-path="url(#506e24dd3d)"
+ id="g5064">
+ <g
+ clip-path="url(#85c10bb5f0)"
+ id="g5062">
+ <path
+ fill="#000000"
+ d="m 279.46094,488.74609 19.99609,-7.21093 -7.32031,-19.98047 -4.48438,1.625 4.48828,12.3125 -51.44921,-23.98828 -2.01563,4.32031 51.44922,23.98828 -12.30469,4.45312 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path5060" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#96382ab88a)"
+ id="g5078"
+ transform="translate(-69.242111,-250.64609)">
+ <g
+ clip-path="url(#8ee2f579d3)"
+ id="g5076">
+ <g
+ clip-path="url(#c24345751d)"
+ id="g5074">
+ <g
+ clip-path="url(#6c1dc82097)"
+ id="g5072">
+ <path
+ fill="#000000"
+ d="m 279.46094,565.48437 19.99609,7.21094 -7.32031,19.97656 -4.48438,-1.62109 4.48828,-12.31641 -51.44921,23.99219 -2.01563,-4.32031 51.44922,-23.99219 -12.30469,-4.44922 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path5070" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/sources/shiboken6/doc/images/icecream.png b/sources/shiboken6/doc/images/icecream.png
new file mode 100644
index 000000000..41d1a25fa
--- /dev/null
+++ b/sources/shiboken6/doc/images/icecream.png
Binary files differ
diff --git a/sources/shiboken6/doc/images/qtforpython-underthehood.png b/sources/shiboken6/doc/images/qtforpython-underthehood.png
new file mode 100644
index 000000000..295cefcf9
--- /dev/null
+++ b/sources/shiboken6/doc/images/qtforpython-underthehood.png
Binary files differ
diff --git a/sources/shiboken6/doc/images/qtforpython-underthehood.svg b/sources/shiboken6/doc/images/qtforpython-underthehood.svg
new file mode 100644
index 000000000..8924d9d4b
--- /dev/null
+++ b/sources/shiboken6/doc/images/qtforpython-underthehood.svg
@@ -0,0 +1,1502 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="972.87427"
+ zoomAndPan="magnify"
+ viewBox="0 0 729.6557 410.72465"
+ height="547.63287"
+ preserveAspectRatio="xMidYMid"
+ version="1.0"
+ id="svg684"
+ sodipodi:docname="qtforpython-underthehood.svg"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ inkscape:export-filename="qtforpython-underthehood.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview686"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ showgrid="false"
+ inkscape:zoom="0.80648148"
+ inkscape:cx="400.50517"
+ inkscape:cy="272.16992"
+ inkscape:window-width="2552"
+ inkscape:window-height="1432"
+ inkscape:window-x="1924"
+ inkscape:window-y="4"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg684" />
+ <defs
+ id="defs94">
+ <filter
+ x="0"
+ y="0"
+ width="1"
+ height="1"
+ id="941f55d5ad">
+ <feColorMatrix
+ values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"
+ color-interpolation-filters="sRGB"
+ id="feColorMatrix2" />
+ </filter>
+ <filter
+ x="0"
+ y="0"
+ width="1"
+ height="1"
+ id="7900779894">
+ <feColorMatrix
+ values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0.2126 0.7152 0.0722 0 0"
+ color-interpolation-filters="sRGB"
+ id="feColorMatrix5" />
+ </filter>
+ <clipPath
+ id="43b70e6d50">
+ <path
+ d="m 329.69531,337.88281 h 134.25 v 134.25 h -134.25 z m 0,0"
+ clip-rule="nonzero"
+ id="path10" />
+ </clipPath>
+ <clipPath
+ id="5e0498f898">
+ <path
+ d="m 418.84375,430.04687 h 78 v 78 h -78 z m 0,0"
+ clip-rule="nonzero"
+ id="path13" />
+ </clipPath>
+ <clipPath
+ id="ee2fc7472f">
+ <path
+ d="m 296.76953,430.04687 h 77.87109 v 78 h -77.87109 z m 0,0"
+ clip-rule="nonzero"
+ id="path16" />
+ </clipPath>
+ <clipPath
+ id="e49c99af70">
+ <path
+ d="m 418.84375,307.19531 h 78 v 77.8711 h -78 z m 0,0"
+ clip-rule="nonzero"
+ id="path19" />
+ </clipPath>
+ <clipPath
+ id="9f18cca9db">
+ <path
+ d="m 296.76953,307.19531 h 77.87109 v 77.8711 h -77.87109 z m 0,0"
+ clip-rule="nonzero"
+ id="path22" />
+ </clipPath>
+ <clipPath
+ id="9c58565a54">
+ <path
+ d="m 240.875,207.47656 h 111.52734 v 82.5 H 240.875 Z m 0,0"
+ clip-rule="nonzero"
+ id="path25" />
+ </clipPath>
+ <clipPath
+ id="9d28a89d3d">
+ <path
+ d="m 46.855469,529 h 73.500001 v 30 H 46.855469 Z m 0,0"
+ clip-rule="nonzero"
+ id="path28" />
+ </clipPath>
+ <clipPath
+ id="0baef73a1e">
+ <path
+ d="m 163.94922,224.44922 h 69.75 v 72 h -69.75 z m 0,0"
+ clip-rule="nonzero"
+ id="path31" />
+ </clipPath>
+ <clipPath
+ id="1f4a27800a">
+ <path
+ d="M 62.34375,227.08203 H 153 V 293 H 62.34375 Z m 0,0"
+ clip-rule="nonzero"
+ id="path34" />
+ </clipPath>
+ <mask
+ id="e94e818b4b">
+ <g
+ filter="url(#941f55d5ad)"
+ id="g42">
+ <g
+ filter="url(#7900779894)"
+ transform="matrix(0.196004,0,0,0.194118,62.344152,227.08093)"
+ id="g40">
+ <image
+ x="0"
+ y="0"
+ width="463"
+ xlink:href="data:image/png;base64,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"
+ height="340"
+ preserveAspectRatio="xMidYMid"
+ id="image38" />
+ </g>
+ </g>
+ </mask>
+ <mask
+ id="8f2a27f6f4">
+ <g
+ filter="url(#941f55d5ad)"
+ id="g51">
+ <g
+ filter="url(#7900779894)"
+ transform="matrix(0.198482,0,0,0.198482,536.61425,471.98102)"
+ id="g49">
+ <image
+ x="0"
+ y="0"
+ width="461"
+ xlink:href="data:image/png;base64,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"
+ height="461"
+ preserveAspectRatio="xMidYMid"
+ id="image47" />
+ </g>
+ </g>
+ </mask>
+ <clipPath
+ id="9cd47c7ee3">
+ <path
+ d="m 268,534 h 119 v 74 H 268 Z m 0,0"
+ clip-rule="nonzero"
+ id="path55" />
+ </clipPath>
+ <clipPath
+ id="69785d3302">
+ <path
+ d="m 284.80469,510.52344 111.6914,32.23828 -23.91797,82.86719 -111.6914,-32.23829 z m 0,0"
+ clip-rule="nonzero"
+ id="path58" />
+ </clipPath>
+ <clipPath
+ id="9c0953b9a2">
+ <path
+ d="m 372.87891,625.72656 -111.69141,-32.23437 23.91797,-82.8711 111.6914,32.23828 z m 0,0"
+ clip-rule="nonzero"
+ id="path61" />
+ </clipPath>
+ <clipPath
+ id="8e32f12866">
+ <path
+ d="m 372.87891,625.72656 -111.69141,-32.23437 23.91797,-82.8711 111.6914,32.23828 z m 0,0"
+ clip-rule="nonzero"
+ id="path64" />
+ </clipPath>
+ <clipPath
+ id="a3af3eb6b6">
+ <path
+ d="m 698.37109,329 h 48.75 v 135.9375 h -48.75 z m 0,0"
+ clip-rule="nonzero"
+ id="path67" />
+ </clipPath>
+ <clipPath
+ id="31f8f05393">
+ <path
+ d="m 508,316 h 77 v 50 h -77 z m 0,0"
+ clip-rule="nonzero"
+ id="path70" />
+ </clipPath>
+ <clipPath
+ id="41889181af">
+ <path
+ d="M 594.73828,339.63672 520.52344,380.56641 506.03516,354.29687 580.25,313.36719 Z m 0,0"
+ clip-rule="nonzero"
+ id="path73" />
+ </clipPath>
+ <clipPath
+ id="fe9d13e8b4">
+ <path
+ d="m 520.6875,380.47656 74.21484,-40.92969 -14.48828,-26.26953 -74.21094,40.92969 z m 0,0"
+ clip-rule="nonzero"
+ id="path76" />
+ </clipPath>
+ <clipPath
+ id="6c6e35ef02">
+ <path
+ d="m 520.6875,380.47656 74.21484,-40.92969 -14.48828,-26.26953 -74.21094,40.92969 z m 0,0"
+ clip-rule="nonzero"
+ id="path79" />
+ </clipPath>
+ <clipPath
+ id="9d2f7452d2">
+ <path
+ d="m 544,250 h 60.1875 v 43.51172 H 544 Z m 0,0"
+ clip-rule="nonzero"
+ id="path82" />
+ </clipPath>
+ <clipPath
+ id="5d999a0038">
+ <path
+ d="M 543.4375,219 H 560 v 8 h -16.5625 z m 0,0"
+ clip-rule="nonzero"
+ id="path85" />
+ </clipPath>
+ <clipPath
+ id="a4f0b4e13e">
+ <path
+ d="m 548,215.51172 h 47 V 249 h -47 z m 0,0"
+ clip-rule="nonzero"
+ id="path88" />
+ </clipPath>
+ <clipPath
+ id="0ea259bc34">
+ <path
+ d="m 595,215.51172 h 6 V 249 h -6 z m 0,0"
+ clip-rule="nonzero"
+ id="path91" />
+ </clipPath>
+ </defs>
+ <rect
+ style="fill:#ffffff;stroke:none;stroke-width:0.75"
+ id="rect1721"
+ width="728.9057"
+ height="409.97464"
+ x="0.375"
+ y="0.375" />
+ <path
+ fill="#41cb51"
+ d="m 353.33158,222.2777 c -10.36328,0 -18.79687,-8.4336 -18.79687,-18.79688 0,-10.36328 8.43359,-18.79297 18.79687,-18.79297 10.35938,0 18.79297,8.42969 18.79297,18.79297 0,10.36328 -8.43359,18.79688 -18.79297,18.79688 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path102" />
+ <g
+ clip-path="url(#43b70e6d50)"
+ id="g106"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#41cb51"
+ d="m 461.69141,394.18359 -14.32813,-2.33984 c -1.21484,-4.66797 -3.07422,-9.12891 -5.54687,-13.3125 l 8.37109,-11.92969 c 0.75,-1.07031 0.625,-2.51953 -0.29688,-3.4414 L 438.5,351.76953 c -0.92969,-0.93359 -2.40234,-1.05078 -3.46484,-0.28125 l -11.80469,8.48438 c -4.19141,-2.46485 -8.66016,-4.32032 -13.32422,-5.52735 l -2.51172,-14.33984 c -0.22656,-1.28516 -1.34375,-2.22266 -2.64844,-2.22266 h -16.10937 c -1.31641,0 -2.4375,0.95313 -2.65235,2.25391 l -2.33984,14.33984 c -4.60937,1.19922 -9.03516,3.03516 -13.19531,5.47656 l -11.86328,-8.47656 c -1.07032,-0.76172 -2.52735,-0.64062 -3.46094,0.28516 l -11.39063,11.39062 c -0.92187,0.91797 -1.05078,2.36719 -0.30078,3.4336 l 8.375,11.96484 c -2.46093,4.16406 -4.30859,8.60938 -5.51953,13.24609 l -14.34765,2.39063 c -1.29688,0.21484 -2.2461,1.33203 -2.2461,2.64453 v 16.11328 c 0,1.30078 0.9336,2.41406 2.21485,2.64063 l 14.35156,2.54687 c 1.20312,4.62891 3.04297,9.06641 5.49219,13.24219 l -8.48047,11.85156 c -0.76172,1.07031 -0.64063,2.53516 0.28515,3.46094 l 11.39063,11.39062 c 0.91797,0.91797 2.36719,1.04688 3.4375,0.30079 l 11.95703,-8.36719 c 4.14844,2.45312 8.58984,4.30078 13.24609,5.51953 l 2.39453,14.35937 c 0.21875,1.29297 1.33985,2.24219 2.65235,2.24219 h 16.10937 c 1.29688,0 2.41407,-0.93359 2.64063,-2.21484 l 2.54687,-14.35547 c 4.69141,-1.21484 9.17578,-3.07813 13.3711,-5.55469 l 11.9414,8.3711 c 1.07032,0.75 2.51953,0.625 3.44141,-0.29688 l 11.38281,-11.39062 c 0.9336,-0.92969 1.05078,-2.39844 0.28125,-3.46485 l -8.49219,-11.80469 c 2.46094,-4.1875 4.3125,-8.65234 5.51954,-13.3164 l 14.34375,-2.51563 c 1.28515,-0.22656 2.22265,-1.34375 2.22265,-2.64453 v -16.11328 c 0,-1.3125 -0.95312,-2.4375 -2.2539,-2.64844 z m -64.8711,43.04688 c -17.76953,0 -32.22265,-14.45703 -32.22265,-32.22266 0,-17.76562 14.45312,-32.21875 32.22265,-32.21875 17.76563,0 32.21875,14.45313 32.21875,32.21875 0,17.76563 -14.45312,32.22266 -32.21875,32.22266 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path104" />
+ </g>
+ <g
+ clip-path="url(#5e0498f898)"
+ id="g110"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#ffd43b"
+ d="m 473.52344,430.04687 c 0,30.17188 -24.50782,54.67969 -54.67969,54.67969 v 23.32031 c 43.08594,0 78,-34.91406 78,-78 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path108" />
+ </g>
+ <g
+ clip-path="url(#ee2fc7472f)"
+ id="g114"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#306998"
+ d="m 320.08984,430.04687 c 0,30.17188 24.50391,54.67969 54.67969,54.67969 v 23.32031 c -43.08594,0 -78,-34.91406 -78,-78 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path112" />
+ </g>
+ <g
+ clip-path="url(#e49c99af70)"
+ id="g118"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#306998"
+ d="m 473.52344,385.19531 c 0,-30.17187 -24.50782,-54.67969 -54.67969,-54.67969 v -23.32031 c 43.08594,0 78,34.91406 78,78 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path116" />
+ </g>
+ <g
+ clip-path="url(#9f18cca9db)"
+ id="g122"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#ffd43b"
+ d="m 320.08984,385.19531 c 0,-30.17187 24.50391,-54.67969 54.67969,-54.67969 v -23.32031 c -43.08594,0 -78,34.91406 -78,78 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path120" />
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g130"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(618.829,252.49077)"
+ id="g128">
+ <g
+ id="g126">
+ <path
+ d="m 10.484375,0.375 c -3.398437,0 -5.699219,-0.9375 -6.90625,-2.8125 -1.210937,-1.882812 -1.8125,-4.972656 -1.8125,-9.265625 0,-4.289063 0.609375,-7.347656 1.828125,-9.171875 1.21875,-1.820312 3.515625,-2.734375 6.890625,-2.734375 2.007813,0 4.222656,0.28125 6.640625,0.84375 L 17,-19.703125 C 14.957031,-20.066406 12.921875,-20.25 10.890625,-20.25 c -2.03125,0 -3.414063,0.605469 -4.140625,1.8125 -0.71875,1.210938 -1.078125,3.484375 -1.078125,6.828125 0,3.335937 0.347656,5.605469 1.046875,6.8125 0.695312,1.210937 2.0625,1.8125 4.09375,1.8125 2.039062,0 4.101562,-0.171875 6.1875,-0.515625 l 0.09375,3.125 c -2.324219,0.5 -4.527344,0.75 -6.609375,0.75 z m 0,0"
+ id="path124" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g138"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(636.53192,252.49077)"
+ id="g136">
+ <g
+ id="g134">
+ <path
+ d="m 11.1875,-7.21875 h -4.75 V 0 h -3.75 v -23.234375 h 8.5 c 5.269531,0 7.90625,2.601563 7.90625,7.796875 0,2.667969 -0.664062,4.703125 -1.984375,6.109375 -1.324219,1.40625 -3.296875,2.109375 -5.921875,2.109375 z m -4.75,-3.265625 h 4.71875 c 2.71875,0 4.078125,-1.648437 4.078125,-4.953125 0,-1.582031 -0.328125,-2.734375 -0.984375,-3.453125 -0.65625,-0.726563 -1.6875,-1.09375 -3.09375,-1.09375 H 6.4375 Z m 0,0"
+ id="path132" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g146"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(655.82879,252.49077)"
+ id="g144">
+ <g
+ id="g142">
+ <path
+ d="M 0.671875,-16.96875 H 4.3125 l 3.59375,13.8125 H 8.8125 l 3.609375,-13.8125 h 3.65625 L 9.640625,7.296875 H 6 L 8.046875,0 H 5.125 Z m 0,0"
+ id="path140" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g154"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(671.76817,252.49077)"
+ id="g152">
+ <g
+ id="g150">
+ <path
+ d="M 11.359375,-13.8125 H 6.6875 v 7.46875 c 0,1.375 0.097656,2.292969 0.296875,2.75 0.207031,0.449219 0.726563,0.671875 1.5625,0.671875 l 2.78125,-0.09375 L 11.5,-0.0625 C 9.988281,0.226562 8.835938,0.375 8.046875,0.375 c -1.929687,0 -3.25,-0.4375 -3.96875,-1.3125 -0.710937,-0.882812 -1.0625,-2.550781 -1.0625,-5 v -7.875 H 0.84375 v -3.15625 H 3.015625 V -21.875 H 6.6875 v 4.90625 h 4.671875 z m 0,0"
+ id="path148" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g162"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(683.16307,252.49077)"
+ id="g160">
+ <g
+ id="g158">
+ <path
+ d="M 5.9375,0 H 2.234375 V -24.015625 H 5.9375 v 7.9375 c 1.675781,-0.832031 3.222656,-1.25 4.640625,-1.25 2.257813,0 3.800781,0.640625 4.625,1.921875 0.832031,1.273438 1.25,3.375 1.25,6.3125 V 0 H 12.75 v -8.984375 c 0,-1.832031 -0.195312,-3.132813 -0.578125,-3.90625 -0.386719,-0.769531 -1.199219,-1.15625 -2.4375,-1.15625 -1.085937,0 -2.167969,0.183594 -3.25,0.546875 L 5.9375,-13.296875 Z m 0,0"
+ id="path156" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g170"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(700.9338,252.49077)"
+ id="g168">
+ <g
+ id="g166">
+ <path
+ d="m 3.171875,-15.125 c 1.164063,-1.46875 3.101563,-2.203125 5.8125,-2.203125 2.71875,0 4.65625,0.734375 5.8125,2.203125 1.164063,1.46875 1.75,3.671875 1.75,6.609375 0,2.9375 -0.570313,5.15625 -1.703125,6.65625 -1.125,1.492187 -3.078125,2.234375 -5.859375,2.234375 -2.78125,0 -4.742187,-0.742188 -5.875,-2.234375 -1.125,-1.5 -1.6875,-3.71875 -1.6875,-6.65625 0,-2.9375 0.582031,-5.140625 1.75,-6.609375 z M 5.9375,-4.109375 C 6.457031,-3.203125 7.472656,-2.75 8.984375,-2.75 c 1.519531,0 2.539063,-0.453125 3.0625,-1.359375 0.519531,-0.90625 0.78125,-2.382813 0.78125,-4.4375 0,-2.0625 -0.28125,-3.519531 -0.84375,-4.375 -0.554687,-0.863281 -1.554687,-1.296875 -3,-1.296875 -1.449219,0 -2.449219,0.433594 -3,1.296875 -0.554687,0.855469 -0.828125,2.3125 -0.828125,4.375 0,2.054687 0.257812,3.53125 0.78125,4.4375 z m 0,0"
+ id="path164" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g178"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(718.16191,252.49077)"
+ id="g176">
+ <g
+ id="g174">
+ <path
+ d="M 5.9375,0 H 2.234375 V -16.96875 H 5.90625 v 1.0625 c 1.644531,-0.945312 3.203125,-1.421875 4.671875,-1.421875 2.257813,0 3.800781,0.640625 4.625,1.921875 0.832031,1.273438 1.25,3.375 1.25,6.3125 V 0 H 12.78125 v -8.984375 c 0,-1.832031 -0.199219,-3.132813 -0.59375,-3.90625 -0.398438,-0.769531 -1.203125,-1.15625 -2.421875,-1.15625 -1.148437,0 -2.257813,0.230469 -3.328125,0.6875 l -0.5,0.203125 z m 0,0"
+ id="path172" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g186"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(618.829,286.99077)"
+ id="g184">
+ <g
+ id="g182">
+ <path
+ d="m 2.6875,0 v -23.234375 h 14.640625 v 3.28125 H 6.4375 v 6.59375 h 8.859375 v 3.25 H 6.4375 v 6.78125 H 17.328125 V 0 Z m 0,0"
+ id="path180" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g194"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(636.83714,286.99077)"
+ id="g192">
+ <g
+ id="g190">
+ <path
+ d="m 0.609375,-16.96875 h 3.9375 l 3.328125,5.875 3.359375,-5.875 H 15.15625 L 10.109375,-8.609375 15.15625,0 H 11.234375 L 7.875,-5.796875 4.546875,0 h -3.9375 L 5.53125,-8.515625 Z m 0,0"
+ id="path188" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g202"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(651.82693,286.99077)"
+ id="g200">
+ <g
+ id="g198">
+ <path
+ d="M 11.359375,-13.8125 H 6.6875 v 7.46875 c 0,1.375 0.097656,2.292969 0.296875,2.75 0.207031,0.449219 0.726563,0.671875 1.5625,0.671875 l 2.78125,-0.09375 L 11.5,-0.0625 C 9.988281,0.226562 8.835938,0.375 8.046875,0.375 c -1.929687,0 -3.25,-0.4375 -3.96875,-1.3125 -0.710937,-0.882812 -1.0625,-2.550781 -1.0625,-5 v -7.875 H 0.84375 v -3.15625 H 3.015625 V -21.875 H 6.6875 v 4.90625 h 4.671875 z m 0,0"
+ id="path196" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g210"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(663.22182,286.99077)"
+ id="g208">
+ <g
+ id="g206">
+ <path
+ d="m 14.3125,-3.046875 0.953125,-0.109375 0.0625,2.75 C 12.753906,0.113281 10.472656,0.375 8.484375,0.375 5.972656,0.375 4.164062,-0.3125 3.0625,-1.6875 1.96875,-3.070312 1.421875,-5.28125 1.421875,-8.3125 c 0,-6.007812 2.453125,-9.015625 7.359375,-9.015625 4.75,0 7.125,2.589844 7.125,7.765625 l -0.234375,2.640625 H 5.15625 c 0.019531,1.40625 0.320312,2.4375 0.90625,3.09375 0.59375,0.65625 1.691406,0.984375 3.296875,0.984375 1.601563,0 3.253906,-0.066406 4.953125,-0.203125 z m -2.03125,-6.71875 c 0,-1.675781 -0.265625,-2.847656 -0.796875,-3.515625 -0.53125,-0.664062 -1.433594,-1 -2.703125,-1 -1.261719,0 -2.183594,0.355469 -2.765625,1.0625 -0.574219,0.699219 -0.871094,1.851562 -0.890625,3.453125 z m 0,0"
+ id="path204" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g218"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(679.70382,286.99077)"
+ id="g216">
+ <g
+ id="g214">
+ <path
+ d="M 5.9375,0 H 2.234375 V -16.96875 H 5.90625 v 1.0625 c 1.644531,-0.945312 3.203125,-1.421875 4.671875,-1.421875 2.257813,0 3.800781,0.640625 4.625,1.921875 0.832031,1.273438 1.25,3.375 1.25,6.3125 V 0 H 12.78125 v -8.984375 c 0,-1.832031 -0.199219,-3.132813 -0.59375,-3.90625 -0.398438,-0.769531 -1.203125,-1.15625 -2.421875,-1.15625 -1.148437,0 -2.257813,0.230469 -3.328125,0.6875 l -0.5,0.203125 z m 0,0"
+ id="path212" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g226"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(697.47455,286.99077)"
+ id="g224">
+ <g
+ id="g222">
+ <path
+ d="m 14.015625,-13.46875 c -2.679687,-0.363281 -4.617187,-0.546875 -5.8125,-0.546875 -1.199219,0 -2.03125,0.148437 -2.5,0.4375 -0.460937,0.28125 -0.6875,0.730469 -0.6875,1.34375 0,0.605469 0.253906,1.03125 0.765625,1.28125 0.507812,0.25 1.707031,0.542969 3.59375,0.875 1.894531,0.324219 3.238281,0.835937 4.03125,1.53125 0.789062,0.699219 1.1875,1.945313 1.1875,3.734375 0,1.78125 -0.574219,3.09375 -1.71875,3.9375 -1.148438,0.8359375 -2.8125,1.25 -5,1.25 -1.386719,0 -3.132812,-0.195312 -5.234375,-0.578125 L 1.59375,-0.375 1.734375,-3.453125 c 2.707031,0.355469 4.660156,0.53125 5.859375,0.53125 1.195312,0 2.050781,-0.144531 2.5625,-0.4375 0.507812,-0.289063 0.765625,-0.773437 0.765625,-1.453125 0,-0.675781 -0.246094,-1.144531 -0.734375,-1.40625 C 9.707031,-6.476562 8.546875,-6.757812 6.703125,-7.0625 4.859375,-7.375 3.503906,-7.859375 2.640625,-8.515625 c -0.855469,-0.65625 -1.28125,-1.851563 -1.28125,-3.59375 0,-1.738281 0.59375,-3.035156 1.78125,-3.890625 1.1875,-0.863281 2.707031,-1.296875 4.5625,-1.296875 1.445313,0 3.222656,0.183594 5.328125,0.546875 l 1.046875,0.203125 z m 0,0"
+ id="path220" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g234"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(712.63391,286.99077)"
+ id="g232">
+ <g
+ id="g230">
+ <path
+ d="M 2.234375,0 V -16.96875 H 5.9375 V 0 Z m 0,-19.84375 V -23.75 H 5.9375 v 3.90625 z m 0,0"
+ id="path228" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g242"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(720.06086,286.99077)"
+ id="g240">
+ <g
+ id="g238">
+ <path
+ d="m 3.171875,-15.125 c 1.164063,-1.46875 3.101563,-2.203125 5.8125,-2.203125 2.71875,0 4.65625,0.734375 5.8125,2.203125 1.164063,1.46875 1.75,3.671875 1.75,6.609375 0,2.9375 -0.570313,5.15625 -1.703125,6.65625 -1.125,1.492187 -3.078125,2.234375 -5.859375,2.234375 -2.78125,0 -4.742187,-0.742188 -5.875,-2.234375 -1.125,-1.5 -1.6875,-3.71875 -1.6875,-6.65625 0,-2.9375 0.582031,-5.140625 1.75,-6.609375 z M 5.9375,-4.109375 C 6.457031,-3.203125 7.472656,-2.75 8.984375,-2.75 c 1.519531,0 2.539063,-0.453125 3.0625,-1.359375 0.519531,-0.90625 0.78125,-2.382813 0.78125,-4.4375 0,-2.0625 -0.28125,-3.519531 -0.84375,-4.375 -0.554687,-0.863281 -1.554687,-1.296875 -3,-1.296875 -1.449219,0 -2.449219,0.433594 -3,1.296875 -0.554687,0.855469 -0.828125,2.3125 -0.828125,4.375 0,2.054687 0.257812,3.53125 0.78125,4.4375 z m 0,0"
+ id="path236" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g250"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(737.28897,286.99077)"
+ id="g248">
+ <g
+ id="g246">
+ <path
+ d="M 5.9375,0 H 2.234375 V -16.96875 H 5.90625 v 1.0625 c 1.644531,-0.945312 3.203125,-1.421875 4.671875,-1.421875 2.257813,0 3.800781,0.640625 4.625,1.921875 0.832031,1.273438 1.25,3.375 1.25,6.3125 V 0 H 12.78125 v -8.984375 c 0,-1.832031 -0.199219,-3.132813 -0.59375,-3.90625 -0.398438,-0.769531 -1.203125,-1.15625 -2.421875,-1.15625 -1.148437,0 -2.257813,0.230469 -3.328125,0.6875 l -0.5,0.203125 z m 0,0"
+ id="path244" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#9c58565a54)"
+ id="g254"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#09102b"
+ d="m 321.85156,262.05469 c -0.89844,-1.01172 -1.60547,-1.91016 -2.41406,-2.70703 -2.69531,-2.64454 -5.30078,-5.39844 -8.1875,-7.82422 -3.11328,-2.61719 -7.58984,-1.91016 -10.45703,1.125 -0.71485,0.75 -1.97656,0.98437 -3.11328,1.51172 -0.48828,1.21093 0.67187,1.74609 1.39062,2.42578 6.50781,6.16797 11.5625,13.44922 15.94531,21.17187 1.67969,2.95313 2.80469,6.23047 4.07813,9.40235 0.99609,2.48828 1.125,2.84375 3.84766,2.625 4.85546,-0.39063 9.08593,-2.03907 12.14453,-6.20313 5.32812,-7.23437 11.07422,-14.17187 15.0664,-22.29687 0.64453,-1.32032 1.125,-2.72657 2.01563,-4.89844 -3.98438,0.71484 -7.26172,0.6875 -9.36719,3.84765 -1.28906,1.9375 -2.60547,3.85157 -4.38281,6.4961 -0.45703,-2.78125 -0.73828,-4.70313 -1.08203,-6.60547 -2.60547,-14.33203 -8.38672,-27.26563 -19.23438,-37.11719 -9.86719,-8.97656 -21.45703,-15.17969 -35.35156,-15.35156 -11.67188,-0.13672 -21.69531,4.42969 -30.45313,11.76562 -3.5039,2.94141 -6.47265,6.53516 -9.58593,9.92188 -0.8086,0.87891 -1.25,2.07422 -1.85938,3.13672 0.23438,0.22656 0.47266,0.45312 0.70703,0.67578 1.4336,-0.88672 2.92188,-1.69922 4.27735,-2.69531 0.84375,-0.625 1.49609,-1.51563 2.20312,-2.3125 9.07813,-10.24219 20.54297,-12.97657 33.53125,-10.1875 9.91797,2.1289 18.11719,7.46484 25.00391,14.77343 7.28125,7.70313 12.21875,16.77735 15.17578,26.94141 0.13672,0.44922 0.24609,0.91406 0.32031,1.375 0.0156,0.20703 -0.0937,0.43359 -0.21875,1.00391 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path252" />
+ </g>
+ <g
+ clip-path="url(#9d28a89d3d)"
+ id="g258"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#09102b"
+ d="m 46.824219,529.01953 v 29.27344 h 73.558591 v -29.27344 z m 28.085937,22.82422 c -0.01563,0 -0.01563,0 -0.01563,0 h -3.992187 c -0.0625,0 -0.125,-0.0469 -0.167969,-0.0937 L 67.273438,546.34766 63.78125,551.75 c -0.03125,0.0469 -0.09375,0.0937 -0.152344,0.0937 h -3.964844 c -0.07812,0 -0.136718,-0.0469 -0.167968,-0.10938 -0.03125,-0.0586 -0.03125,-0.13671 0.01563,-0.19531 l 5.519531,-8.41406 -5.003906,-7.71484 c -0.02734,-0.0586 -0.02734,-0.13672 0,-0.19532 0.03125,-0.0625 0.09375,-0.10937 0.167968,-0.10937 h 3.859376 c 0.0625,0 0.121093,0.0469 0.167968,0.0937 l 3.125,4.98828 3.050782,-4.98828 c 0.04687,-0.0469 0.105468,-0.0937 0.167968,-0.0937 h 3.828125 c 0.07422,0 0.136719,0.0469 0.167969,0.10937 0.02734,0.0586 0.02734,0.13672 0,0.19532 l -5.035156,7.83593 5.507812,8.25 c 0.02734,0.043 0.05859,0.0899 0.05859,0.15235 0,0.10156 -0.07422,0.19531 -0.183594,0.19531 z m 17.644532,-0.19922 c 0,0.10547 -0.09375,0.19922 -0.199219,0.19922 h -3.0625 c -0.109375,0 -0.183594,-0.0937 -0.183594,-0.19922 v -11.32031 l -2.882813,11.36719 c -0.01562,0.0898 -0.08984,0.15234 -0.183593,0.15234 h -3.1875 c -0.08984,0 -0.167969,-0.0625 -0.183594,-0.15234 l -2.851563,-11.36719 v 11.32031 c 0,0.10547 -0.08984,0.19531 -0.195312,0.19531 h -3.082031 c -0.105469,0 -0.183594,-0.0898 -0.183594,-0.19531 v -16.33984 c 0,-0.10547 0.07813,-0.19922 0.183594,-0.19922 H 81.5 c 0.08984,0 0.167969,0.0586 0.183594,0.15234 l 2.773437,10.45313 2.761719,-10.45313 c 0.01563,-0.0937 0.08984,-0.15234 0.183594,-0.15234 h 4.953125 c 0.105469,0 0.199219,0.0937 0.199219,0.19922 z m 14.882812,0 c 0,0.10547 -0.0742,0.19922 -0.18359,0.19922 H 95.726562 c -0.105468,0 -0.183593,-0.0937 -0.183593,-0.19922 v -16.20312 c 0,-0.10547 0.07813,-0.19922 0.183593,-0.19922 h 3.308594 c 0.105469,0 0.199219,0.0937 0.199219,0.19922 v 13.26953 h 8.019535 c 0.10937,0 0.18359,0.0742 0.18359,0.17968 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path256" />
+ </g>
+ <path
+ fill="#09102b"
+ d="m 10.753456,359.80895 h 58.707032 v 6.48437 H 10.753456 Z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path260" />
+ <path
+ fill="#09102b"
+ d="m 10.761268,287.53551 v 36.91406 h 58.70703 v -36.91406 z m 51.84766,32.34766 H 17.620643 c -0.835937,0 -1.523437,-0.6836 -1.523437,-1.51954 0,-0.85546 0.6875,-1.52343 1.523437,-1.52343 h 44.988285 c 0.82031,0 1.52343,0.66797 1.52343,1.52343 0,0.83594 -0.70312,1.51954 -1.52343,1.51954 z m 0,-10.65235 H 17.620643 c -0.835937,0 -1.523437,-0.68359 -1.523437,-1.51953 0,-0.85156 0.6875,-1.52344 1.523437,-1.52344 h 44.988285 c 0.82031,0 1.52343,0.67188 1.52343,1.52344 0,0.83594 -0.70312,1.51953 -1.52343,1.51953 z m 0,-10.64844 H 17.620643 c -0.835937,0 -1.523437,-0.6875 -1.523437,-1.52343 0,-0.85157 0.6875,-1.52344 1.523437,-1.52344 h 44.988285 c 0.82031,0 1.52343,0.67187 1.52343,1.52344 0,0.83593 -0.70312,1.52343 -1.52343,1.52343 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path262" />
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g270"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(126.27432,523.15898)"
+ id="g268">
+ <g
+ id="g266">
+ <path
+ d="m 4.6875,-23.234375 4.984375,9.15625 5.046875,-9.15625 H 18.6875 L 11.8125,-11.4375 18.6875,0 H 14.484375 L 9.5,-8.75 4.40625,0 H 0.4375 l 6.921875,-11.234375 -6.921875,-12 z m 0,0"
+ id="path264" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g278"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(144.65551,523.15898)"
+ id="g276">
+ <g
+ id="g274">
+ <path
+ d="m 2.6875,0 v -23.234375 h 6.546875 l 5.1875,18.140625 5.1875,-18.140625 H 26.1875 V 0 H 22.390625 V -19.0625 H 21.875 l -5.484375,18.109375 h -3.9375 l -5.5,-18.109375 H 6.4375 V 0 Z m 0,0"
+ id="path272" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g286"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(172.73611,523.15898)"
+ id="g284">
+ <g
+ id="g282">
+ <path
+ d="M 15.703125,0 H 2.6875 v -23.234375 h 3.75 v 19.875 h 9.265625 z m 0,0"
+ id="path280" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g294"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(126.27432,557.65898)"
+ id="g292">
+ <g
+ id="g290">
+ <path
+ d="m 0.4375,-19.875 v -3.359375 H 17.40625 V -19.875 H 10.859375 V 0 H 7.0625 v -19.875 z m 0,0"
+ id="path288" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g302"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(143.36677,557.65898)"
+ id="g300">
+ <g
+ id="g298">
+ <path
+ d="M 0.671875,-16.96875 H 4.3125 l 3.59375,13.8125 H 8.8125 l 3.609375,-13.8125 h 3.65625 L 9.640625,7.296875 H 6 L 8.046875,0 H 5.125 Z m 0,0"
+ id="path296" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g310"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(159.30615,557.65898)"
+ id="g308">
+ <g
+ id="g306">
+ <path
+ d="M 2.234375,7.296875 V -16.96875 H 5.90625 v 1.0625 c 1.5625,-0.945312 3.019531,-1.421875 4.375,-1.421875 2.238281,0 3.875,0.683594 4.90625,2.046875 1.039062,1.367188 1.5625,3.664062 1.5625,6.890625 0,3.21875 -0.59375,5.484375 -1.78125,6.796875 -1.179688,1.3125 -3.117188,1.96875 -5.8125,1.96875 -0.929688,0 -2,-0.105469 -3.21875,-0.3125 v 7.234375 z m 7.40625,-21.34375 c -1.0625,0 -2.132813,0.242187 -3.203125,0.71875 l -0.5,0.234375 v 10 c 0.90625,0.1875 1.898438,0.28125 2.984375,0.28125 1.539063,0 2.601563,-0.441406 3.1875,-1.328125 0.582031,-0.882813 0.875,-2.390625 0.875,-4.515625 0,-3.59375 -1.117187,-5.390625 -3.34375,-5.390625 z m 0,0"
+ id="path304" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g318"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(176.77166,557.65898)"
+ id="g316">
+ <g
+ id="g314">
+ <path
+ d="m 14.3125,-3.046875 0.953125,-0.109375 0.0625,2.75 C 12.753906,0.113281 10.472656,0.375 8.484375,0.375 5.972656,0.375 4.164062,-0.3125 3.0625,-1.6875 1.96875,-3.070312 1.421875,-5.28125 1.421875,-8.3125 c 0,-6.007812 2.453125,-9.015625 7.359375,-9.015625 4.75,0 7.125,2.589844 7.125,7.765625 l -0.234375,2.640625 H 5.15625 c 0.019531,1.40625 0.320312,2.4375 0.90625,3.09375 0.59375,0.65625 1.691406,0.984375 3.296875,0.984375 1.601563,0 3.253906,-0.066406 4.953125,-0.203125 z m -2.03125,-6.71875 c 0,-1.675781 -0.265625,-2.847656 -0.796875,-3.515625 -0.53125,-0.664062 -1.433594,-1 -2.703125,-1 -1.261719,0 -2.183594,0.355469 -2.765625,1.0625 -0.574219,0.699219 -0.871094,1.851562 -0.890625,3.453125 z m 0,0"
+ id="path312" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g326"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(193.25366,557.65898)"
+ id="g324">
+ <g
+ id="g322">
+ <path
+ d="m 14.015625,-13.46875 c -2.679687,-0.363281 -4.617187,-0.546875 -5.8125,-0.546875 -1.199219,0 -2.03125,0.148437 -2.5,0.4375 -0.460937,0.28125 -0.6875,0.730469 -0.6875,1.34375 0,0.605469 0.253906,1.03125 0.765625,1.28125 0.507812,0.25 1.707031,0.542969 3.59375,0.875 1.894531,0.324219 3.238281,0.835937 4.03125,1.53125 0.789062,0.699219 1.1875,1.945313 1.1875,3.734375 0,1.78125 -0.574219,3.09375 -1.71875,3.9375 -1.148438,0.8359375 -2.8125,1.25 -5,1.25 -1.386719,0 -3.132812,-0.195312 -5.234375,-0.578125 L 1.59375,-0.375 1.734375,-3.453125 c 2.707031,0.355469 4.660156,0.53125 5.859375,0.53125 1.195312,0 2.050781,-0.144531 2.5625,-0.4375 0.507812,-0.289063 0.765625,-0.773437 0.765625,-1.453125 0,-0.675781 -0.246094,-1.144531 -0.734375,-1.40625 C 9.707031,-6.476562 8.546875,-6.757812 6.703125,-7.0625 4.859375,-7.375 3.503906,-7.859375 2.640625,-8.515625 c -0.855469,-0.65625 -1.28125,-1.851563 -1.28125,-3.59375 0,-1.738281 0.59375,-3.035156 1.78125,-3.890625 1.1875,-0.863281 2.707031,-1.296875 4.5625,-1.296875 1.445313,0 3.222656,0.183594 5.328125,0.546875 l 1.046875,0.203125 z m 0,0"
+ id="path320" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g334"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(208.41301,557.65898)"
+ id="g332">
+ <g
+ id="g330">
+ <path
+ d="M 0.671875,-16.96875 H 4.3125 l 3.59375,13.8125 H 8.8125 l 3.609375,-13.8125 h 3.65625 L 9.640625,7.296875 H 6 L 8.046875,0 H 5.125 Z m 0,0"
+ id="path328" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g342"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(224.35239,557.65898)"
+ id="g340">
+ <g
+ id="g338">
+ <path
+ d="m 14.015625,-13.46875 c -2.679687,-0.363281 -4.617187,-0.546875 -5.8125,-0.546875 -1.199219,0 -2.03125,0.148437 -2.5,0.4375 -0.460937,0.28125 -0.6875,0.730469 -0.6875,1.34375 0,0.605469 0.253906,1.03125 0.765625,1.28125 0.507812,0.25 1.707031,0.542969 3.59375,0.875 1.894531,0.324219 3.238281,0.835937 4.03125,1.53125 0.789062,0.699219 1.1875,1.945313 1.1875,3.734375 0,1.78125 -0.574219,3.09375 -1.71875,3.9375 -1.148438,0.8359375 -2.8125,1.25 -5,1.25 -1.386719,0 -3.132812,-0.195312 -5.234375,-0.578125 L 1.59375,-0.375 1.734375,-3.453125 c 2.707031,0.355469 4.660156,0.53125 5.859375,0.53125 1.195312,0 2.050781,-0.144531 2.5625,-0.4375 0.507812,-0.289063 0.765625,-0.773437 0.765625,-1.453125 0,-0.675781 -0.246094,-1.144531 -0.734375,-1.40625 C 9.707031,-6.476562 8.546875,-6.757812 6.703125,-7.0625 4.859375,-7.375 3.503906,-7.859375 2.640625,-8.515625 c -0.855469,-0.65625 -1.28125,-1.851563 -1.28125,-3.59375 0,-1.738281 0.59375,-3.035156 1.78125,-3.890625 1.1875,-0.863281 2.707031,-1.296875 4.5625,-1.296875 1.445313,0 3.222656,0.183594 5.328125,0.546875 l 1.046875,0.203125 z m 0,0"
+ id="path336" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g350"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(239.51175,557.65898)"
+ id="g348">
+ <g
+ id="g346">
+ <path
+ d="M 11.359375,-13.8125 H 6.6875 v 7.46875 c 0,1.375 0.097656,2.292969 0.296875,2.75 0.207031,0.449219 0.726563,0.671875 1.5625,0.671875 l 2.78125,-0.09375 L 11.5,-0.0625 C 9.988281,0.226562 8.835938,0.375 8.046875,0.375 c -1.929687,0 -3.25,-0.4375 -3.96875,-1.3125 -0.710937,-0.882812 -1.0625,-2.550781 -1.0625,-5 v -7.875 H 0.84375 v -3.15625 H 3.015625 V -21.875 H 6.6875 v 4.90625 h 4.671875 z m 0,0"
+ id="path344" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g358"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(250.90664,557.65898)"
+ id="g356">
+ <g
+ id="g354">
+ <path
+ d="m 14.3125,-3.046875 0.953125,-0.109375 0.0625,2.75 C 12.753906,0.113281 10.472656,0.375 8.484375,0.375 5.972656,0.375 4.164062,-0.3125 3.0625,-1.6875 1.96875,-3.070312 1.421875,-5.28125 1.421875,-8.3125 c 0,-6.007812 2.453125,-9.015625 7.359375,-9.015625 4.75,0 7.125,2.589844 7.125,7.765625 l -0.234375,2.640625 H 5.15625 c 0.019531,1.40625 0.320312,2.4375 0.90625,3.09375 0.59375,0.65625 1.691406,0.984375 3.296875,0.984375 1.601563,0 3.253906,-0.066406 4.953125,-0.203125 z m -2.03125,-6.71875 c 0,-1.675781 -0.265625,-2.847656 -0.796875,-3.515625 -0.53125,-0.664062 -1.433594,-1 -2.703125,-1 -1.261719,0 -2.183594,0.355469 -2.765625,1.0625 -0.574219,0.699219 -0.871094,1.851562 -0.890625,3.453125 z m 0,0"
+ id="path352" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g366"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(267.38864,557.65898)"
+ id="g364">
+ <g
+ id="g362">
+ <path
+ d="M 5.9375,0 H 2.234375 V -16.96875 H 5.90625 v 1.0625 c 1.601562,-0.945312 3.070312,-1.421875 4.40625,-1.421875 1.96875,0 3.40625,0.554687 4.3125,1.65625 2.050781,-1.101563 4.09375,-1.65625 6.125,-1.65625 2.039062,0 3.476562,0.632813 4.3125,1.890625 0.84375,1.25 1.265625,3.367188 1.265625,6.34375 V 0 H 22.65625 v -8.984375 c 0,-1.832031 -0.1875,-3.132813 -0.5625,-3.90625 -0.367188,-0.769531 -1.136719,-1.15625 -2.3125,-1.15625 -1.023438,0 -2.121094,0.230469 -3.296875,0.6875 L 15.90625,-13.125 c 0.1875,0.449219 0.28125,1.898438 0.28125,4.34375 V 0 h -3.671875 v -8.71875 c 0,-2.007812 -0.183594,-3.398438 -0.546875,-4.171875 -0.355469,-0.769531 -1.148438,-1.15625 -2.375,-1.15625 -1.125,0 -2.179688,0.230469 -3.15625,0.6875 l -0.5,0.203125 z m 0,0"
+ id="path360" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g374"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(295.06227,557.65898)"
+ id="g372">
+ <g
+ id="g370">
+ <path
+ d="m 14.015625,-13.46875 c -2.679687,-0.363281 -4.617187,-0.546875 -5.8125,-0.546875 -1.199219,0 -2.03125,0.148437 -2.5,0.4375 -0.460937,0.28125 -0.6875,0.730469 -0.6875,1.34375 0,0.605469 0.253906,1.03125 0.765625,1.28125 0.507812,0.25 1.707031,0.542969 3.59375,0.875 1.894531,0.324219 3.238281,0.835937 4.03125,1.53125 0.789062,0.699219 1.1875,1.945313 1.1875,3.734375 0,1.78125 -0.574219,3.09375 -1.71875,3.9375 -1.148438,0.8359375 -2.8125,1.25 -5,1.25 -1.386719,0 -3.132812,-0.195312 -5.234375,-0.578125 L 1.59375,-0.375 1.734375,-3.453125 c 2.707031,0.355469 4.660156,0.53125 5.859375,0.53125 1.195312,0 2.050781,-0.144531 2.5625,-0.4375 0.507812,-0.289063 0.765625,-0.773437 0.765625,-1.453125 0,-0.675781 -0.246094,-1.144531 -0.734375,-1.40625 C 9.707031,-6.476562 8.546875,-6.757812 6.703125,-7.0625 4.859375,-7.375 3.503906,-7.859375 2.640625,-8.515625 c -0.855469,-0.65625 -1.28125,-1.851563 -1.28125,-3.59375 0,-1.738281 0.59375,-3.035156 1.78125,-3.890625 1.1875,-0.863281 2.707031,-1.296875 4.5625,-1.296875 1.445313,0 3.222656,0.183594 5.328125,0.546875 l 1.046875,0.203125 z m 0,0"
+ id="path368" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#0baef73a1e)"
+ id="g378"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#09102b"
+ d="m 230.94531,263.10547 h -1.21875 V 254.125 c 0,-0.36719 -0.0703,-0.72266 -0.21094,-1.0625 -0.13671,-0.33594 -0.33593,-0.63672 -0.59765,-0.89844 -0.25781,-0.25781 -0.55469,-0.45703 -0.89063,-0.59765 -0.33984,-0.14063 -0.6875,-0.21094 -1.05468,-0.21094 h -2.44922 v -10.71094 c 0.004,-0.31641 -0.10547,-0.58594 -0.32032,-0.8125 L 209.78516,225.0625 c -0.23047,-0.26172 -0.51954,-0.39453 -0.86329,-0.39844 h -35.35546 c -0.14844,0 -0.29688,0.0312 -0.4375,0.0898 -0.14063,0.0586 -0.26563,0.14062 -0.3711,0.25 -0.10937,0.10546 -0.1914,0.23046 -0.25,0.375 -0.0586,0.14062 -0.0859,0.28515 -0.0859,0.4414 v 25.55078 h -2.48828 c -0.36328,0 -0.71484,0.0703 -1.05468,0.21094 -0.33594,0.14063 -0.63282,0.34375 -0.89063,0.60156 -0.25781,0.26172 -0.45703,0.5586 -0.59766,0.89844 -0.14062,0.33984 -0.21093,0.69141 -0.21093,1.05859 v 12.70313 h -0.44141 c -0.36328,0 -0.71484,0.0703 -1.05078,0.21094 -0.33984,0.14062 -0.63672,0.34375 -0.89453,0.60156 -0.25781,0.26172 -0.45703,0.55859 -0.59766,0.89844 -0.13672,0.33984 -0.20703,0.6914 -0.20703,1.05859 0,0 0,0.10156 0,0.16016 l 3.17578,23.74218 c 0.0117,0.35938 0.0898,0.70313 0.23438,1.03125 0.14843,0.32422 0.34765,0.61329 0.60547,0.86329 0.25781,0.25 0.55078,0.4414 0.88281,0.57421 0.32812,0.13282 0.67187,0.19922 1.02734,0.19922 h 57.07813 c 0.35547,0 0.69922,-0.0664 1.02734,-0.19922 0.33203,-0.13281 0.625,-0.32421 0.87891,-0.57031 0.25781,-0.25 0.46093,-0.53515 0.60547,-0.86328 0.14453,-0.32422 0.22656,-0.66797 0.24218,-1.02344 l 3.95313,-27.5039 c 0.004,-0.0547 0.004,-0.10938 0,-0.16407 0,-0.36718 -0.0742,-0.71875 -0.21485,-1.05468 -0.14062,-0.33985 -0.33984,-0.63672 -0.59765,-0.89453 -0.25781,-0.25782 -0.55469,-0.45704 -0.89063,-0.59375 -0.33593,-0.14063 -0.6875,-0.21094 -1.05078,-0.21094 z m -61.48828,3.73828 V 254.125 c 0.004,-0.12109 0.0469,-0.22656 0.13281,-0.3125 0.082,-0.0859 0.1875,-0.12891 0.3086,-0.13281 h 2.48437 v 13.16406 z m 33.60938,-3.19141 -1.95704,3.19141 h -26.39453 v -39.87109 h 33.08594 v 13.67187 c 0.0117,0.30859 0.12109,0.56641 0.33984,0.78516 0.21485,0.21484 0.47657,0.32422 0.78125,0.33203 h 13.28907 v 21.34375 h -18.12891 c -0.42578,0 -0.75391,0.17969 -0.98047,0.54687 z m 21.45703,-0.54687 v -9.42578 h 2.48437 c 0.1211,0.004 0.22656,0.0469 0.3125,0.13281 0.082,0.0859 0.12891,0.19141 0.12891,0.3125 v 8.98047 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path376" />
+ </g>
+ <path
+ fill="#09102b"
+ d="m 138.5308,35.426124 h 17.95313 c 0.15234,0 0.29687,-0.0312 0.4375,-0.0898 0.14062,-0.0586 0.26562,-0.14062 0.375,-0.25 0.10546,-0.10547 0.1875,-0.23047 0.24609,-0.37109 0.0586,-0.14453 0.0898,-0.28907 0.0898,-0.44532 0,-0.15234 -0.0312,-0.29687 -0.0898,-0.4414 -0.0586,-0.14063 -0.14063,-0.26563 -0.24609,-0.3711 -0.10938,-0.10937 -0.23438,-0.1914 -0.375,-0.25 -0.14063,-0.0586 -0.28516,-0.0898 -0.4375,-0.0898 H 138.5308 c -0.15234,0 -0.29687,0.0312 -0.4375,0.0898 -0.14062,0.0586 -0.26562,0.14063 -0.37109,0.25 -0.10938,0.10547 -0.19141,0.23047 -0.25,0.3711 -0.0586,0.14453 -0.0859,0.28906 -0.0859,0.4414 0,0.15625 0.0273,0.30079 0.0859,0.44532 0.0586,0.14062 0.14062,0.26562 0.25,0.37109 0.10547,0.10938 0.23047,0.19141 0.37109,0.25 0.14063,0.0586 0.28516,0.0898 0.4375,0.0898 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path380" />
+ <path
+ fill="#09102b"
+ d="m 144.88236,56.051124 h -6.35156 c -0.15234,0 -0.29687,0.0274 -0.4375,0.0859 -0.14062,0.0586 -0.26562,0.14063 -0.37109,0.25 -0.10938,0.10938 -0.19141,0.23438 -0.25,0.375 -0.0586,0.14063 -0.0859,0.28906 -0.0859,0.44141 0,0.15234 0.0273,0.30078 0.0859,0.4414 0.0586,0.14063 0.14062,0.26563 0.25,0.375 0.10547,0.10938 0.23047,0.19141 0.37109,0.25 0.14063,0.0586 0.28516,0.0859 0.4375,0.0859 h 6.35156 c 0.15235,0 0.30078,-0.0273 0.44141,-0.0859 0.14062,-0.0586 0.26172,-0.14062 0.37109,-0.25 0.10547,-0.10937 0.19141,-0.23437 0.25,-0.375 0.0547,-0.14062 0.0859,-0.28906 0.0859,-0.4414 0,-0.15235 -0.0312,-0.30078 -0.0859,-0.44141 -0.0586,-0.14062 -0.14453,-0.26562 -0.25,-0.375 -0.10937,-0.10937 -0.23047,-0.1914 -0.37109,-0.25 -0.14063,-0.0586 -0.28906,-0.0859 -0.44141,-0.0859 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path382" />
+ <path
+ fill="#09102b"
+ d="m 158.89799,56.051124 h -8.54688 c -0.14843,0 -0.29687,0.0274 -0.4375,0.0859 -0.14062,0.0586 -0.26562,0.14063 -0.37109,0.25 -0.10938,0.10938 -0.19141,0.23438 -0.25,0.375 -0.0586,0.14063 -0.0859,0.28906 -0.0859,0.44141 0,0.15234 0.0273,0.30078 0.0859,0.4414 0.0586,0.14063 0.14062,0.26563 0.25,0.375 0.10547,0.10938 0.23047,0.19141 0.37109,0.25 0.14063,0.0586 0.28907,0.0859 0.4375,0.0859 h 8.54688 c 0.15234,0 0.29687,-0.0273 0.4375,-0.0859 0.14062,-0.0586 0.26562,-0.14062 0.375,-0.25 0.10547,-0.10937 0.1875,-0.23437 0.24609,-0.375 0.0586,-0.14062 0.0898,-0.28906 0.0898,-0.4414 0,-0.15235 -0.0312,-0.30078 -0.0898,-0.44141 -0.0586,-0.14062 -0.14062,-0.26562 -0.24609,-0.375 -0.10938,-0.10937 -0.23438,-0.1914 -0.375,-0.25 -0.14063,-0.0586 -0.28516,-0.0859 -0.4375,-0.0859 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path384" />
+ <path
+ fill="#09102b"
+ d="m 138.5308,40.613624 h 20.30078 c 0.15235,0 0.30078,-0.0273 0.44141,-0.0859 0.14062,-0.0586 0.26562,-0.14453 0.37109,-0.25 0.10938,-0.10938 0.19141,-0.23438 0.25,-0.375 0.0586,-0.14063 0.0859,-0.28907 0.0859,-0.44141 0,-0.15625 -0.0273,-0.30078 -0.0859,-0.44141 -0.0586,-0.14453 -0.14062,-0.26953 -0.25,-0.375 -0.10547,-0.10937 -0.23047,-0.1914 -0.37109,-0.25 -0.14063,-0.0586 -0.28906,-0.0898 -0.44141,-0.0898 H 138.5308 c -0.15234,0 -0.29687,0.0312 -0.4375,0.0898 -0.14062,0.0586 -0.26562,0.14063 -0.37109,0.25 -0.10938,0.10547 -0.19141,0.23047 -0.25,0.375 -0.0586,0.14063 -0.0859,0.28516 -0.0859,0.44141 0,0.15234 0.0273,0.30078 0.0859,0.44141 0.0586,0.14062 0.14062,0.26562 0.25,0.375 0.10547,0.10547 0.23047,0.1914 0.37109,0.25 0.14063,0.0586 0.28516,0.0859 0.4375,0.0859 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path386" />
+ <path
+ fill="#09102b"
+ d="M 166.35111,50.269874 H 138.5308 c -0.15234,0 -0.29687,0.0312 -0.4375,0.0898 -0.14062,0.0586 -0.26562,0.14062 -0.37109,0.25 -0.10938,0.10547 -0.19141,0.23047 -0.25,0.375 -0.0586,0.14062 -0.0859,0.28515 -0.0859,0.4414 0,0.15235 0.0273,0.29688 0.0859,0.44141 0.0586,0.14063 0.14062,0.26563 0.25,0.37109 0.10547,0.10938 0.23047,0.19532 0.37109,0.25391 0.14063,0.0586 0.28516,0.0859 0.4375,0.0859 h 27.82031 c 0.15235,0 0.29688,-0.0273 0.4375,-0.0859 0.14063,-0.0586 0.26563,-0.14453 0.3711,-0.25391 0.10937,-0.10546 0.1914,-0.23046 0.25,-0.37109 0.0586,-0.14453 0.0859,-0.28906 0.0859,-0.44141 0,-0.15625 -0.0273,-0.30078 -0.0859,-0.4414 -0.0586,-0.14453 -0.14063,-0.26953 -0.25,-0.375 -0.10547,-0.10938 -0.23047,-0.19141 -0.3711,-0.25 -0.14062,-0.0586 -0.28515,-0.0898 -0.4375,-0.0898 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path388" />
+ <path
+ fill="#09102b"
+ d="m 172.45268,44.351914 h -33.95704 c -0.15234,0 -0.30078,0.0312 -0.4414,0.0898 -0.14063,0.0586 -0.26172,0.14062 -0.3711,0.25 -0.10937,0.10547 -0.1914,0.23047 -0.25,0.375 -0.0586,0.14062 -0.0859,0.28516 -0.0859,0.44141 0,0.15234 0.0273,0.30078 0.0859,0.4414 0.0586,0.14063 0.14063,0.26563 0.25,0.375 0.10938,0.10547 0.23047,0.19141 0.3711,0.25 0.14062,0.0586 0.28906,0.0859 0.4414,0.0859 h 33.95704 c 0.15234,0 0.29687,-0.0273 0.4375,-0.0859 0.14062,-0.0586 0.26562,-0.14453 0.375,-0.25 0.10546,-0.10937 0.1875,-0.23437 0.24609,-0.375 0.0586,-0.14062 0.0898,-0.28906 0.0898,-0.4414 0,-0.15625 -0.0312,-0.30079 -0.0898,-0.44141 -0.0586,-0.14453 -0.14063,-0.26953 -0.24609,-0.375 -0.10938,-0.10938 -0.23438,-0.19141 -0.375,-0.25 -0.14063,-0.0586 -0.28516,-0.0898 -0.4375,-0.0898 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path390" />
+ <g
+ clip-path="url(#1f4a27800a)"
+ id="g398"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ mask="url(#e94e818b4b)"
+ id="g396">
+ <g
+ transform="matrix(0.196004,0,0,0.194118,62.344152,227.08093)"
+ id="g394">
+ <image
+ x="0"
+ y="0"
+ width="463"
+ xlink:href="data:image/png;base64,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"
+ height="340"
+ preserveAspectRatio="xMidYMid"
+ id="image392" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g406"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(62.344152,330.62669)"
+ id="g404">
+ <g
+ id="g402">
+ <path
+ d="M 11.78125,0.390625 C 8.039062,0.390625 5.4375,-0.613281 3.96875,-2.625 2.5,-4.632812 1.765625,-7.8125 1.765625,-12.15625 1.765625,-16.5 2.507812,-19.722656 4,-21.828125 5.5,-23.941406 8.09375,-25 11.78125,-25 c 3.6875,0 6.269531,1.046875 7.75,3.140625 1.488281,2.09375 2.234375,5.324219 2.234375,9.6875 0,2.875 -0.308594,5.199219 -0.921875,6.96875 -0.605469,1.773437 -1.601562,3.121094 -2.984375,4.046875 l 3.015625,4.859375 -3.703125,1.71875 -3.203125,-5.25 c -0.449219,0.144531 -1.179688,0.21875 -2.1875,0.21875 z M 7.109375,-5.1875 c 0.8125,1.398438 2.367187,2.09375 4.671875,2.09375 2.300781,0 3.851562,-0.6875 4.65625,-2.0625 0.800781,-1.375 1.203125,-3.703125 1.203125,-6.984375 0,-3.28125 -0.417969,-5.660156 -1.25,-7.140625 -0.824219,-1.488281 -2.359375,-2.234375 -4.609375,-2.234375 -2.25,0 -3.796875,0.746094 -4.640625,2.234375 -0.835937,1.480469 -1.25,3.851562 -1.25,7.109375 0,3.25 0.40625,5.578125 1.21875,6.984375 z m 0,0"
+ id="path400" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g414"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(85.1083,330.62669)"
+ id="g412">
+ <g
+ id="g410">
+ <path
+ d="M 12.03125,-14.625 H 7.078125 v 7.90625 c 0,1.460938 0.101563,2.429688 0.3125,2.90625 0.21875,0.480469 0.769531,0.71875 1.65625,0.71875 L 12,-3.203125 l 0.171875,3.125 c -1.605469,0.3125 -2.824219,0.46875 -3.65625,0.46875 -2.042969,0 -3.4375,-0.4609375 -4.1875,-1.390625 -0.75,-0.9375 -1.125,-2.695312 -1.125,-5.28125 V -14.625 h -2.3125 v -3.328125 h 2.3125 v -5.21875 h 3.875 v 5.21875 h 4.953125 z m 0,0"
+ id="path408" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g420"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(97.172393,330.62669)"
+ id="g418">
+ <g
+ id="g416" />
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g428"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(104.28144,330.62669)"
+ id="g426">
+ <g
+ id="g424">
+ <path
+ d="m 17.453125,0 v -10.640625 h -10.625 V 0 H 2.84375 V -24.609375 H 6.828125 V -14.125 h 10.625 v -10.484375 h 4.03125 V 0 Z m 0,0"
+ id="path422" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g436"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(127.7637,330.62669)"
+ id="g434">
+ <g
+ id="g432">
+ <path
+ d="m 15.15625,-3.234375 1.015625,-0.109375 0.0625,2.90625 c -2.730469,0.550781 -5.148437,0.828125 -7.25,0.828125 -2.65625,0 -4.570313,-0.726563 -5.734375,-2.1875 -1.15625,-1.457031 -1.734375,-3.789063 -1.734375,-7 0,-6.375 2.59375,-9.5625 7.78125,-9.5625 5.03125,0 7.546875,2.746094 7.546875,8.234375 l -0.25,2.796875 H 5.453125 c 0.03125,1.492187 0.351563,2.585937 0.96875,3.28125 0.625,0.6875 1.785156,1.03125 3.484375,1.03125 1.707031,0 3.457031,-0.070313 5.25,-0.21875 z M 13,-10.34375 c 0,-1.769531 -0.28125,-3.007812 -0.84375,-3.71875 -0.5625,-0.707031 -1.515625,-1.0625 -2.859375,-1.0625 -1.335937,0 -2.308594,0.375 -2.921875,1.125 -0.617188,0.742188 -0.933594,1.960938 -0.953125,3.65625 z m 0,0"
+ id="path430" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g444"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(145.21372,330.62669)"
+ id="g442">
+ <g
+ id="g440">
+ <path
+ d="m 15.65625,-12.421875 v 8.1875 c 0.03125,0.523437 0.171875,0.914063 0.421875,1.171875 0.25,0.25 0.640625,0.40625 1.171875,0.46875 l -0.109375,2.984375 c -2.0625,0 -3.65625,-0.4414062 -4.78125,-1.328125 -1.917969,0.8867188 -3.84375,1.328125 -5.78125,1.328125 -3.574219,0 -5.359375,-1.898437 -5.359375,-5.703125 0,-1.820312 0.484375,-3.140625 1.453125,-3.953125 0.96875,-0.8125 2.460937,-1.300781 4.484375,-1.46875 l 4.625,-0.40625 v -1.28125 c 0,-0.957031 -0.210938,-1.628906 -0.625,-2.015625 -0.417969,-0.382812 -1.039062,-0.578125 -1.859375,-0.578125 -1.53125,0 -3.445313,0.09375 -5.734375,0.28125 l -1.15625,0.07813 -0.140625,-2.765625 c 2.601563,-0.625 5,-0.9375 7.1875,-0.9375 2.195313,0 3.78125,0.476563 4.75,1.421875 0.96875,0.949219 1.453125,2.453125 1.453125,4.515625 z M 7.609375,-7.96875 c -1.648437,0.136719 -2.46875,1.03125 -2.46875,2.6875 0,1.65625 0.726563,2.484375 2.1875,2.484375 1.195313,0 2.46875,-0.191406 3.8125,-0.578125 L 11.78125,-3.59375 V -8.375 Z m 0,0"
+ id="path438" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g452"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(162.62784,330.62669)"
+ id="g450">
+ <g
+ id="g448">
+ <path
+ d="M 17.03125,-25.4375 V 0 h -3.890625 v -0.9375 c -1.742187,0.8867188 -3.34375,1.328125 -4.8125,1.328125 -2.34375,0 -4.0625,-0.703125 -5.15625,-2.109375 -1.085937,-1.414062 -1.625,-3.785156 -1.625,-7.109375 0,-3.332031 0.601563,-5.753906 1.8125,-7.265625 1.207031,-1.507812 3.09375,-2.265625 5.65625,-2.265625 0.863281,0 2.226563,0.15625 4.09375,0.46875 V -25.4375 Z M 12.5,-3.734375 l 0.609375,-0.25 V -14.625 c -1.4375,-0.238281 -2.765625,-0.359375 -3.984375,-0.359375 -2.417969,0 -3.625,2.015625 -3.625,6.046875 0,2.199219 0.28125,3.726562 0.84375,4.578125 0.5625,0.84375 1.453125,1.265625 2.671875,1.265625 1.21875,0 2.378906,-0.210938 3.484375,-0.640625 z m 0,0"
+ id="path446" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g460"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(181.22687,330.62669)"
+ id="g458">
+ <g
+ id="g456">
+ <path
+ d="m 15.15625,-3.234375 1.015625,-0.109375 0.0625,2.90625 c -2.730469,0.550781 -5.148437,0.828125 -7.25,0.828125 -2.65625,0 -4.570313,-0.726563 -5.734375,-2.1875 -1.15625,-1.457031 -1.734375,-3.789063 -1.734375,-7 0,-6.375 2.59375,-9.5625 7.78125,-9.5625 5.03125,0 7.546875,2.746094 7.546875,8.234375 l -0.25,2.796875 H 5.453125 c 0.03125,1.492187 0.351563,2.585937 0.96875,3.28125 0.625,0.6875 1.785156,1.03125 3.484375,1.03125 1.707031,0 3.457031,-0.070313 5.25,-0.21875 z M 13,-10.34375 c 0,-1.769531 -0.28125,-3.007812 -0.84375,-3.71875 -0.5625,-0.707031 -1.515625,-1.0625 -2.859375,-1.0625 -1.335937,0 -2.308594,0.375 -2.921875,1.125 -0.617188,0.742188 -0.933594,1.960938 -0.953125,3.65625 z m 0,0"
+ id="path454" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g468"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(198.6769,330.62669)"
+ id="g466">
+ <g
+ id="g464">
+ <path
+ d="M 2.375,0 V -17.953125 H 6.25 v 2.140625 c 2.03125,-1.3125 4.066406,-2.160156 6.109375,-2.546875 v 3.921875 c -2.0625,0.40625 -3.824219,0.933594 -5.28125,1.578125 L 6.28125,-12.53125 V 0 Z m 0,0"
+ id="path462" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g476"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(210.84872,330.62669)"
+ id="g474">
+ <g
+ id="g472">
+ <path
+ d="m 14.828125,-14.265625 c -2.824219,-0.375 -4.871094,-0.5625 -6.140625,-0.5625 -1.261719,0 -2.140625,0.152344 -2.640625,0.453125 -0.492187,0.292969 -0.734375,0.761719 -0.734375,1.40625 0,0.648438 0.269531,1.105469 0.8125,1.375 0.539062,0.261719 1.8125,0.5625 3.8125,0.90625 2,0.34375 3.414062,0.890625 4.25,1.640625 0.84375,0.742187 1.265625,2.058594 1.265625,3.953125 0,1.886719 -0.609375,3.273438 -1.828125,4.15625 -1.210938,0.8867188 -2.976562,1.328125 -5.296875,1.328125 -1.460937,0 -3.304687,-0.203125 -5.53125,-0.609375 L 1.6875,-0.390625 1.828125,-3.65625 c 2.875,0.375 4.945313,0.5625 6.21875,0.5625 1.269531,0 2.171875,-0.148438 2.703125,-0.453125 0.539062,-0.3125 0.8125,-0.828125 0.8125,-1.546875 0,-0.71875 -0.261719,-1.210938 -0.78125,-1.484375 -0.511719,-0.28125 -1.742188,-0.582031 -3.6875,-0.90625 -1.949219,-0.320313 -3.382812,-0.832031 -4.296875,-1.53125 -0.90625,-0.695313 -1.359375,-1.96875 -1.359375,-3.8125 0,-1.84375 0.625,-3.21875 1.875,-4.125 1.257812,-0.90625 2.875,-1.359375 4.84375,-1.359375 1.53125,0 3.410156,0.1875 5.640625,0.5625 l 1.109375,0.21875 z m 0,0"
+ id="path470" />
+ </g>
+ </g>
+ </g>
+ <g
+ mask="url(#8f2a27f6f4)"
+ id="g482"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="matrix(0.198482,0,0,0.198482,536.61425,471.98102)"
+ id="g480">
+ <image
+ x="0"
+ y="0"
+ width="461"
+ xlink:href="data:image/png;base64,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"
+ height="461"
+ preserveAspectRatio="xMidYMid"
+ id="image478" />
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g490"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(633.94891,514.05933)"
+ id="g488">
+ <g
+ id="g486">
+ <path
+ d="M 0.8125,-23.234375 H 4.78125 L 8.109375,-3.25 H 8.8125 l 4.421875,-19.921875 h 4.40625 L 22.046875,-3.25 h 0.75 L 26.125,-23.234375 h 3.96875 L 25.515625,0 H 19.4375 l -4,-18.625 L 11.46875,0 H 5.359375 Z m 0,0"
+ id="path484" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g498"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(664.09827,514.05933)"
+ id="g496">
+ <g
+ id="g494">
+ <path
+ d="M 5.9375,0 H 2.234375 V -24.015625 H 5.9375 v 7.9375 c 1.675781,-0.832031 3.222656,-1.25 4.640625,-1.25 2.257813,0 3.800781,0.640625 4.625,1.921875 0.832031,1.273438 1.25,3.375 1.25,6.3125 V 0 H 12.75 v -8.984375 c 0,-1.832031 -0.195312,-3.132813 -0.578125,-3.90625 -0.386719,-0.769531 -1.199219,-1.15625 -2.4375,-1.15625 -1.085937,0 -2.167969,0.183594 -3.25,0.546875 L 5.9375,-13.296875 Z m 0,0"
+ id="path492" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g506"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(681.869,514.05933)"
+ id="g504">
+ <g
+ id="g502">
+ <path
+ d="m 14.3125,-3.046875 0.953125,-0.109375 0.0625,2.75 C 12.753906,0.113281 10.472656,0.375 8.484375,0.375 5.972656,0.375 4.164062,-0.3125 3.0625,-1.6875 1.96875,-3.070312 1.421875,-5.28125 1.421875,-8.3125 c 0,-6.007812 2.453125,-9.015625 7.359375,-9.015625 4.75,0 7.125,2.589844 7.125,7.765625 l -0.234375,2.640625 H 5.15625 c 0.019531,1.40625 0.320312,2.4375 0.90625,3.09375 0.59375,0.65625 1.691406,0.984375 3.296875,0.984375 1.601563,0 3.253906,-0.066406 4.953125,-0.203125 z m -2.03125,-6.71875 c 0,-1.675781 -0.265625,-2.847656 -0.796875,-3.515625 -0.53125,-0.664062 -1.433594,-1 -2.703125,-1 -1.261719,0 -2.183594,0.355469 -2.765625,1.0625 -0.574219,0.699219 -0.871094,1.851562 -0.890625,3.453125 z m 0,0"
+ id="path500" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g514"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(698.351,514.05933)"
+ id="g512">
+ <g
+ id="g510">
+ <path
+ d="m 14.3125,-3.046875 0.953125,-0.109375 0.0625,2.75 C 12.753906,0.113281 10.472656,0.375 8.484375,0.375 5.972656,0.375 4.164062,-0.3125 3.0625,-1.6875 1.96875,-3.070312 1.421875,-5.28125 1.421875,-8.3125 c 0,-6.007812 2.453125,-9.015625 7.359375,-9.015625 4.75,0 7.125,2.589844 7.125,7.765625 l -0.234375,2.640625 H 5.15625 c 0.019531,1.40625 0.320312,2.4375 0.90625,3.09375 0.59375,0.65625 1.691406,0.984375 3.296875,0.984375 1.601563,0 3.253906,-0.066406 4.953125,-0.203125 z m -2.03125,-6.71875 c 0,-1.675781 -0.265625,-2.847656 -0.796875,-3.515625 -0.53125,-0.664062 -1.433594,-1 -2.703125,-1 -1.261719,0 -2.183594,0.355469 -2.765625,1.0625 -0.574219,0.699219 -0.871094,1.851562 -0.890625,3.453125 z m 0,0"
+ id="path508" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g522"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(714.833,514.05933)"
+ id="g520">
+ <g
+ id="g518">
+ <path
+ d="M 2.4375,0 V -24.015625 H 6.140625 V 0 Z m 0,0"
+ id="path516" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g530"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(633.94891,548.55933)"
+ id="g528">
+ <g
+ id="g526">
+ <path
+ d="m 11.1875,-7.21875 h -4.75 V 0 h -3.75 v -23.234375 h 8.5 c 5.269531,0 7.90625,2.601563 7.90625,7.796875 0,2.667969 -0.664062,4.703125 -1.984375,6.109375 -1.324219,1.40625 -3.296875,2.109375 -5.921875,2.109375 z m -4.75,-3.265625 h 4.71875 c 2.71875,0 4.078125,-1.648437 4.078125,-4.953125 0,-1.582031 -0.328125,-2.734375 -0.984375,-3.453125 -0.65625,-0.726563 -1.6875,-1.09375 -3.09375,-1.09375 H 6.4375 Z m 0,0"
+ id="path524" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g538"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(653.24578,548.55933)"
+ id="g536">
+ <g
+ id="g534">
+ <path
+ d="M 14.796875,-11.734375 V -4 c 0.01953,0.5 0.144531,0.871094 0.375,1.109375 0.238281,0.230469 0.609375,0.382813 1.109375,0.453125 L 16.1875,0.375 c -1.949219,0 -3.453125,-0.4140625 -4.515625,-1.25 -1.8125,0.8359375 -3.636719,1.25 -5.46875,1.25 -3.367187,0 -5.046875,-1.796875 -5.046875,-5.390625 0,-1.71875 0.457031,-2.960937 1.375,-3.734375 0.914062,-0.769531 2.320312,-1.234375 4.21875,-1.390625 l 4.375,-0.375 v -1.21875 c 0,-0.90625 -0.199219,-1.535156 -0.59375,-1.890625 -0.398438,-0.363281 -0.980469,-0.546875 -1.75,-0.546875 -1.449219,0 -3.257812,0.08984 -5.421875,0.265625 l -1.09375,0.0625 -0.125,-2.609375 c 2.457031,-0.582031 4.722656,-0.875 6.796875,-0.875 2.070312,0 3.566406,0.449219 4.484375,1.34375 0.914063,0.886719 1.375,2.304687 1.375,4.25 z M 7.1875,-7.53125 c -1.5625,0.136719 -2.34375,0.984375 -2.34375,2.546875 0,1.5625 0.691406,2.34375 2.078125,2.34375 1.125,0 2.320313,-0.179687 3.59375,-0.546875 L 11.125,-3.390625 V -7.90625 Z m 0,0"
+ id="path532" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g546"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(669.69387,548.55933)"
+ id="g544">
+ <g
+ id="g542">
+ <path
+ d="m 8.578125,-17.328125 c 1.195313,0 2.613281,0.15625 4.25,0.46875 l 0.84375,0.171875 -0.140625,2.921875 c -1.78125,-0.1875 -3.105469,-0.28125 -3.96875,-0.28125 -1.71875,0 -2.875,0.386719 -3.46875,1.15625 -0.585938,0.773437 -0.875,2.21875 -0.875,4.34375 0,2.125 0.28125,3.59375 0.84375,4.40625 0.570312,0.8125 1.75,1.21875 3.53125,1.21875 L 13.5625,-3.1875 13.671875,-0.234375 C 11.390625,0.171875 9.671875,0.375 8.515625,0.375 5.929688,0.375 4.113281,-0.316406 3.0625,-1.703125 2.019531,-3.097656 1.5,-5.378906 1.5,-8.546875 c 0,-3.164063 0.550781,-5.421875 1.65625,-6.765625 1.101562,-1.34375 2.910156,-2.015625 5.421875,-2.015625 z m 0,0"
+ id="path540" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g554"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(683.93754,548.55933)"
+ id="g552">
+ <g
+ id="g550">
+ <path
+ d="M 5.9375,0 H 2.234375 V -24.015625 H 5.9375 v 13.875 l 2.109375,-0.203125 4,-6.625 H 16.1875 L 11.296875,-9.015625 16.453125,0 H 12.28125 L 8.140625,-7.15625 5.9375,-6.921875 Z m 0,0"
+ id="path548" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g562"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(700.11432,548.55933)"
+ id="g560">
+ <g
+ id="g558">
+ <path
+ d="M 14.796875,-11.734375 V -4 c 0.01953,0.5 0.144531,0.871094 0.375,1.109375 0.238281,0.230469 0.609375,0.382813 1.109375,0.453125 L 16.1875,0.375 c -1.949219,0 -3.453125,-0.4140625 -4.515625,-1.25 -1.8125,0.8359375 -3.636719,1.25 -5.46875,1.25 -3.367187,0 -5.046875,-1.796875 -5.046875,-5.390625 0,-1.71875 0.457031,-2.960937 1.375,-3.734375 0.914062,-0.769531 2.320312,-1.234375 4.21875,-1.390625 l 4.375,-0.375 v -1.21875 c 0,-0.90625 -0.199219,-1.535156 -0.59375,-1.890625 -0.398438,-0.363281 -0.980469,-0.546875 -1.75,-0.546875 -1.449219,0 -3.257812,0.08984 -5.421875,0.265625 l -1.09375,0.0625 -0.125,-2.609375 c 2.457031,-0.582031 4.722656,-0.875 6.796875,-0.875 2.070312,0 3.566406,0.449219 4.484375,1.34375 0.914063,0.886719 1.375,2.304687 1.375,4.25 z M 7.1875,-7.53125 c -1.5625,0.136719 -2.34375,0.984375 -2.34375,2.546875 0,1.5625 0.691406,2.34375 2.078125,2.34375 1.125,0 2.320313,-0.179687 3.59375,-0.546875 L 11.125,-3.390625 V -7.90625 Z m 0,0"
+ id="path556" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g570"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(716.56241,548.55933)"
+ id="g568">
+ <g
+ id="g566">
+ <path
+ d="m 17.0625,2.3125 c 0,3.707031 -2.683594,5.5625 -8.046875,5.5625 C 6.441406,7.875 4.53125,7.519531 3.28125,6.8125 2.039062,6.113281 1.421875,4.835938 1.421875,2.984375 1.421875,2.148438 1.625,1.429688 2.03125,0.828125 2.4375,0.234375 3.09375,-0.414062 4,-1.125 3.257812,-1.613281 2.890625,-2.4375 2.890625,-3.59375 c 0,-0.457031 0.300781,-1.191406 0.90625,-2.203125 L 4.109375,-6.3125 C 2.472656,-7.28125 1.65625,-8.972656 1.65625,-11.390625 c 0,-2.039063 0.609375,-3.535156 1.828125,-4.484375 1.226563,-0.945312 2.882813,-1.421875 4.96875,-1.421875 0.988281,0 1.96875,0.109375 2.9375,0.328125 L 11.90625,-16.859375 17.171875,-17 v 2.984375 l -2.828125,-0.15625 c 0.613281,0.792969 0.921875,1.71875 0.921875,2.78125 0,2.210937 -0.5625,3.742187 -1.6875,4.59375 -1.117187,0.84375 -2.859375,1.265625 -5.234375,1.265625 -0.585938,0 -1.078125,-0.046875 -1.484375,-0.140625 C 6.535156,-4.898438 6.375,-4.300781 6.375,-3.875 c 0,0.417969 0.207031,0.703125 0.625,0.859375 0.414062,0.15625 1.429688,0.246094 3.046875,0.265625 2.6875,0.023438 4.523437,0.386719 5.515625,1.09375 1,0.699219 1.5,2.019531 1.5,3.96875 z M 5.046875,2.640625 c 0,0.789063 0.316406,1.351563 0.953125,1.6875 0.632812,0.34375 1.722656,0.515625 3.265625,0.515625 2.726563,0 4.09375,-0.777344 4.09375,-2.328125 0,-0.886719 -0.246094,-1.449219 -0.734375,-1.6875 C 12.144531,0.585938 11.179688,0.457031 9.734375,0.4375 L 6.40625,0.234375 C 5.914062,0.640625 5.566406,1.019531 5.359375,1.375 5.148438,1.726562 5.046875,2.148438 5.046875,2.640625 Z m 0.28125,-14.03125 c 0,1.03125 0.242187,1.792969 0.734375,2.28125 0.5,0.492187 1.300781,0.734375 2.40625,0.734375 1.113281,0 1.910156,-0.242188 2.390625,-0.734375 0.488281,-0.488281 0.734375,-1.25 0.734375,-2.28125 0,-1.039063 -0.25,-1.804687 -0.75,-2.296875 -0.492188,-0.488281 -1.289062,-0.734375 -2.390625,-0.734375 -2.085937,0 -3.125,1.011719 -3.125,3.03125 z m 0,0"
+ id="path564" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g578"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(733.62094,548.55933)"
+ id="g576">
+ <g
+ id="g574">
+ <path
+ d="m 14.3125,-3.046875 0.953125,-0.109375 0.0625,2.75 C 12.753906,0.113281 10.472656,0.375 8.484375,0.375 5.972656,0.375 4.164062,-0.3125 3.0625,-1.6875 1.96875,-3.070312 1.421875,-5.28125 1.421875,-8.3125 c 0,-6.007812 2.453125,-9.015625 7.359375,-9.015625 4.75,0 7.125,2.589844 7.125,7.765625 l -0.234375,2.640625 H 5.15625 c 0.019531,1.40625 0.320312,2.4375 0.90625,3.09375 0.59375,0.65625 1.691406,0.984375 3.296875,0.984375 1.601563,0 3.253906,-0.066406 4.953125,-0.203125 z m -2.03125,-6.71875 c 0,-1.675781 -0.265625,-2.847656 -0.796875,-3.515625 -0.53125,-0.664062 -1.433594,-1 -2.703125,-1 -1.261719,0 -2.183594,0.355469 -2.765625,1.0625 -0.574219,0.699219 -0.871094,1.851562 -0.890625,3.453125 z m 0,0"
+ id="path572" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g586"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(750.10294,548.55933)"
+ id="g584">
+ <g
+ id="g582">
+ <path
+ d="m 14.015625,-13.46875 c -2.679687,-0.363281 -4.617187,-0.546875 -5.8125,-0.546875 -1.199219,0 -2.03125,0.148437 -2.5,0.4375 -0.460937,0.28125 -0.6875,0.730469 -0.6875,1.34375 0,0.605469 0.253906,1.03125 0.765625,1.28125 0.507812,0.25 1.707031,0.542969 3.59375,0.875 1.894531,0.324219 3.238281,0.835937 4.03125,1.53125 0.789062,0.699219 1.1875,1.945313 1.1875,3.734375 0,1.78125 -0.574219,3.09375 -1.71875,3.9375 -1.148438,0.8359375 -2.8125,1.25 -5,1.25 -1.386719,0 -3.132812,-0.195312 -5.234375,-0.578125 L 1.59375,-0.375 1.734375,-3.453125 c 2.707031,0.355469 4.660156,0.53125 5.859375,0.53125 1.195312,0 2.050781,-0.144531 2.5625,-0.4375 0.507812,-0.289063 0.765625,-0.773437 0.765625,-1.453125 0,-0.675781 -0.246094,-1.144531 -0.734375,-1.40625 C 9.707031,-6.476562 8.546875,-6.757812 6.703125,-7.0625 4.859375,-7.375 3.503906,-7.859375 2.640625,-8.515625 c -0.855469,-0.65625 -1.28125,-1.851563 -1.28125,-3.59375 0,-1.738281 0.59375,-3.035156 1.78125,-3.890625 1.1875,-0.863281 2.707031,-1.296875 4.5625,-1.296875 1.445313,0 3.222656,0.183594 5.328125,0.546875 l 1.046875,0.203125 z m 0,0"
+ id="path580" />
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#9cd47c7ee3)"
+ id="g596"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ clip-path="url(#69785d3302)"
+ id="g594">
+ <g
+ clip-path="url(#9c0953b9a2)"
+ id="g592">
+ <g
+ clip-path="url(#8e32f12866)"
+ id="g590">
+ <path
+ fill="#09102b"
+ d="m 358.17187,562.08984 c -1.19531,0.76172 -2.16015,1.45703 -3.19921,2.02344 -3.46094,1.87891 -6.86329,3.89453 -10.45313,5.5 -3.87109,1.73047 -8.14062,-0.26953 -10.125,-4.14453 -0.5,-0.96484 -1.69141,-1.5625 -2.67578,-2.41797 -0.13672,-1.35937 1.17969,-1.5625 2.09375,-2.03906 8.29297,-4.31641 15.45703,-10.17188 22.07812,-16.66406 2.53516,-2.48047 4.60938,-5.44922 6.80079,-8.26563 1.71875,-2.21484 1.94921,-2.53516 4.60546,-1.53125 4.74219,1.79297 8.49219,4.66797 10.34375,9.73828 3.22657,8.80469 6.95704,17.42969 8.59375,26.74219 0.26172,1.51172 0.33594,3.0625 0.59375,5.5 -3.77343,-1.86719 -7.05859,-2.78516 -8.24609,-6.56641 -0.72656,-2.32031 -1.48828,-4.61718 -2.5,-7.78906 -1.25781,2.66406 -2.09766,4.50781 -2.99219,6.32031 -6.76172,13.64844 -16.28906,24.96875 -29.98828,31.73828 -12.46484,6.16797 -25.84765,9.05469 -39.78906,5.21875 -11.70703,-3.23437 -20.39844,-10.70703 -27.02734,-20.60156 -2.64844,-3.96875 -4.57422,-8.4375 -6.70313,-12.73828 -0.55469,-1.11328 -0.65234,-2.44141 -0.95312,-3.68359 0.30078,-0.15625 0.60156,-0.31641 0.90625,-0.47657 1.17578,1.30469 2.42578,2.55469 3.48828,3.94532 0.66406,0.87109 1.05859,1.94922 1.53515,2.95312 6.10547,12.90625 16.76953,18.96094 30.5625,19.90625 10.53516,0.72656 20.27344,-2.26562 29.27735,-7.62109 9.51172,-5.64063 17.07812,-13.32813 22.98047,-22.6836 0.26953,-0.41406 0.51171,-0.84765 0.71875,-1.28906 0.0781,-0.20312 0.0351,-0.46484 0.0742,-1.07422 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path588" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#a3af3eb6b6)"
+ id="g600"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#09102b"
+ d="m 704.36719,330.69531 c 1.40625,-2.07812 3.07422,-1.63672 4.66797,-1.07812 4.41406,1.53125 8.38281,3.79297 11.63281,7.23828 10.34375,10.98828 17.05859,23.99609 20.78125,38.50781 3.82031,14.875 2.98047,29.55469 -3.1211,43.75 -2.87109,6.67969 -6.11328,13.20703 -9.29687,20.03516 0.74219,-0.2461 1.6875,-0.47266 2.58203,-0.85938 6.08203,-2.59765 7.51172,-2.37109 12.3125,2.26953 1.07422,1.03516 1.95703,2.26563 3.19531,3.70703 -1.25,0.77735 -2.1289,1.35547 -3.04687,1.88672 -9.82422,5.69532 -19.75781,11.22266 -29.42188,17.19922 -2.34375,1.44531 -4.15234,1.31641 -6.14453,0.36719 -4.0039,-1.91797 -6.86328,-5.28906 -9.32812,-8.80078 -0.86328,-1.22656 -0.58203,-3.52344 -0.33594,-5.25781 1.86328,-12.69922 2.53906,-25.44922 1.51953,-38.23438 -0.32422,-3.98828 -1.25,-7.91797 -1.94922,-12.22656 1.26953,-0.47266 2.67969,0.3125 3.875,1.0664 5.60547,3.54297 10.27735,7.85157 11.26563,14.91797 0.46484,3.33985 0.95703,6.66797 1.39062,10.00782 0.19141,1.48437 0.23438,2.99218 0.375,4.83593 7.40625,-6.82031 14.4961,-36.78515 12.53906,-51.98437 -2.3789,-18.48047 -10.55859,-34.16406 -23.49218,-47.34766 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path598" />
+ </g>
+ <g
+ clip-path="url(#31f8f05393)"
+ id="g610"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ clip-path="url(#41889181af)"
+ id="g608">
+ <g
+ clip-path="url(#fe9d13e8b4)"
+ id="g606">
+ <g
+ clip-path="url(#6c6e35ef02)"
+ id="g604">
+ <path
+ fill="#09102b"
+ d="m 509.19922,356.76172 c -0.71094,1.38672 0.0273,2.15234 0.80469,2.83984 2.14062,1.92188 4.55078,3.38281 7.39453,4.10156 9.04687,2.27735 18.11718,1.99219 27.11328,-0.35156 9.22656,-2.40234 16.95703,-7.25781 22.86719,-14.80469 2.77734,-3.55078 5.36328,-7.2539 8.1289,-11.01953 0.0859,0.47657 0.2461,1.05469 0.30078,1.65235 0.39453,4.05468 0.94141,4.75781 4.89453,5.94922 0.88282,0.27343 1.8125,0.3789 2.96485,0.61328 0.0508,-0.90625 0.10547,-1.55469 0.11719,-2.20703 0.17968,-7.00391 0.23437,-14.01172 0.61328,-21.01172 0.0859,-1.69922 -0.52344,-2.63282 -1.62891,-3.42188 -2.23047,-1.58203 -4.91797,-2.11328 -7.55859,-2.39062 -0.92188,-0.0937 -2.08594,0.74609 -2.95703,1.39843 -6.35157,4.8125 -13.08594,9 -20.34375,12.28516 -2.26172,1.01953 -4.67579,1.70313 -7.22657,2.61719 0.1211,0.82422 0.96875,1.35156 1.73047,1.76562 3.59375,1.96094 7.32422,3.1836 11.46094,1.59766 1.95703,-0.75 3.91406,-1.48047 5.85547,-2.25 0.86719,-0.34375 1.69922,-0.77344 2.74219,-1.25 -1.50782,6.03516 -15.69532,18.84375 -24.54297,22.34766 -10.75782,4.26171 -21.71485,4.55859 -32.73047,1.53906 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path602" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ clip-path="url(#9d2f7452d2)"
+ id="g614"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#09102b"
+ d="m 547.03516,293.51172 h 54.54296 c 1.38282,0 2.51563,-1.12891 2.51563,-2.50781 v -40.83594 h -59.57422 v 40.83594 c 0,1.3789 1.13281,2.50781 2.51563,2.50781 z m 16.36328,-33.44531 h 21.8125 c 1.5,0 2.72656,1.22265 2.72656,2.71484 0,1.49219 -1.22656,2.71484 -2.72656,2.71484 h -21.8125 c -1.4961,0 -2.72266,-1.22265 -2.72266,-2.71484 0,-1.49219 1.22656,-2.71484 2.72266,-2.71484 z m 0,0"
+ fill-opacity="1"
+ fill-rule="evenodd"
+ id="path612" />
+ </g>
+ <g
+ clip-path="url(#5d999a0038)"
+ id="g618"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#09102b"
+ d="m 554.07812,219.76172 h 1.70313 c 1.91797,0 3.48047,1.55859 3.48047,3.47265 0,1.91016 -1.5625,3.46875 -3.48047,3.46875 h -8.76953 c -1.91797,0 -3.48047,-1.55859 -3.48047,-3.46875 0,-1.83984 1.44922,-3.35546 3.26562,-3.46484 v 1.73828 c -0.85546,0.10938 -1.52734,0.84375 -1.52734,1.72656 0,0.87891 0.67188,1.61719 1.52734,1.72266 v 0.004 h 0.0469 c 0.0547,0.008 0.10937,0.008 0.16797,0.008 h 8.76953 c 0.95703,0 1.74219,-0.78125 1.74219,-1.73438 0,-0.95703 -0.78516,-1.73828 -1.74219,-1.73828 h -1.70313 z m 0,0"
+ fill-opacity="1"
+ fill-rule="nonzero"
+ id="path616" />
+ </g>
+ <g
+ clip-path="url(#a4f0b4e13e)"
+ id="g622"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#09102b"
+ d="M 594.1875,248.43359 H 548.53516 V 228.4375 h 7.24609 c 2.875,0 5.21875,-2.33594 5.21875,-5.20313 0,-2.86718 -2.34375,-5.20703 -5.21875,-5.20703 h -3.44141 v 5.20313 h -3.80468 v -6.04297 c 0,-0.92188 0.73437,-1.67578 1.6289,-1.67578 h 42.39453 c 0.89844,0 1.62891,0.7539 1.62891,1.67578 z m -39.69922,-5.64062 h 33.75 v 1.73047 h -33.75 z m 0,-4.61719 h 33.75 v 1.73438 h -33.75 z m 8.23047,-14.98047 h 17.28906 v 1.73438 h -17.28906 z m 4.13281,-3.77734 h 9.01953 v 1.73437 h -9.01953 z m -12.36328,14.14453 h 33.75 v 1.73437 h -33.75 z m 0,0"
+ fill-opacity="1"
+ fill-rule="evenodd"
+ id="path620" />
+ </g>
+ <g
+ clip-path="url(#0ea259bc34)"
+ id="g626"
+ transform="translate(-43.488732,-201.52699)">
+ <path
+ fill="#09102b"
+ d="m 595.92969,248.43359 h 4.14843 V 217.1875 c 0,-0.92188 -0.73437,-1.67578 -1.63281,-1.67578 h -2.95312 c 0.27734,0.49609 0.4375,1.07031 0.4375,1.67578 z m 0,0"
+ fill-opacity="1"
+ fill-rule="evenodd"
+ id="path624" />
+ </g>
+ <g
+ fill="#ffffff"
+ fill-opacity="1"
+ id="g634"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(549.69852,280.96421)"
+ id="g632">
+ <g
+ id="g630">
+ <path
+ d="m 4.421875,0.109375 c -0.75,0 -1.414063,-0.1484375 -1.984375,-0.453125 -0.5625,-0.3125 -1.007812,-0.773438 -1.328125,-1.390625 -0.3125,-0.625 -0.46875,-1.394531 -0.46875,-2.3125 0,-0.90625 0.15625,-1.671875 0.46875,-2.296875 0.320313,-0.625 0.765625,-1.085938 1.328125,-1.390625 0.570312,-0.3125 1.234375,-0.46875 1.984375,-0.46875 0.78125,0 1.441406,0.152344 1.984375,0.453125 0.539062,0.304688 0.925781,0.765625 1.15625,1.390625 l -1.15625,0.71875 H 6.265625 c -0.179687,-0.425781 -0.417969,-0.726563 -0.71875,-0.90625 -0.292969,-0.1875 -0.667969,-0.28125 -1.125,-0.28125 -0.679687,0 -1.203125,0.226563 -1.578125,0.671875 -0.375,0.4375 -0.5625,1.140625 -0.5625,2.109375 0,0.96875 0.1875,1.679687 0.5625,2.125 0.375,0.4375 0.898438,0.65625 1.578125,0.65625 1.050781,0 1.691406,-0.507813 1.921875,-1.53125 h 0.140625 l 1.1875,0.609375 C 7.441406,-1.414062 7.0625,-0.835938 6.53125,-0.453125 6,-0.078125 5.296875,0.109375 4.421875,0.109375 Z m 0,0"
+ id="path628" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#ffffff"
+ fill-opacity="1"
+ id="g642"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(557.62495,280.96421)"
+ id="g640">
+ <g
+ id="g638">
+ <path
+ d="m 4.171875,-8.09375 c 0.582031,0 1.078125,0.109375 1.484375,0.328125 0.414062,0.210937 0.726562,0.507813 0.9375,0.890625 0.207031,0.375 0.3125,0.820312 0.3125,1.328125 0,0.5 -0.105469,0.945313 -0.3125,1.328125 -0.210938,0.375 -0.523438,0.671875 -0.9375,0.890625 -0.40625,0.210937 -0.902344,0.3125 -1.484375,0.3125 H 2.65625 V 0 H 1.046875 v -8.09375 z m -0.203125,3.8125 c 0.882812,0 1.328125,-0.421875 1.328125,-1.265625 0,-0.84375 -0.445313,-1.265625 -1.328125,-1.265625 h -1.3125 v 2.53125 z m 0,0"
+ id="path636" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#ffffff"
+ fill-opacity="1"
+ id="g650"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(565.00968,280.96421)"
+ id="g648">
+ <g
+ id="g646">
+ <path
+ d="M 1.34375,2.59375 C 1.082031,2.59375 0.847656,2.570312 0.640625,2.53125 0.429688,2.488281 0.257812,2.4375 0.125,2.375 L 0.359375,1.125 0.46875,1.09375 C 0.5625,1.144531 0.675781,1.179688 0.8125,1.203125 0.945312,1.234375 1.085938,1.25 1.234375,1.25 1.472656,1.25 1.675781,1.21875 1.84375,1.15625 2.007812,1.09375 2.148438,0.984375 2.265625,0.828125 2.378906,0.679688 2.476562,0.476562 2.5625,0.21875 L 0.125,-6.09375 H 1.734375 L 3.25,-1.859375 h 0.140625 l 1.46875,-4.234375 h 1.5625 L 3.96875,0.375 C 3.769531,0.90625 3.550781,1.328125 3.3125,1.640625 3.082031,1.960938 2.804688,2.203125 2.484375,2.359375 2.171875,2.515625 1.789062,2.59375 1.34375,2.59375 Z m 0,0"
+ id="path644" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#ffffff"
+ fill-opacity="1"
+ id="g658"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(571.55424,280.96421)"
+ id="g656">
+ <g
+ id="g654">
+ <path
+ d="m 4.203125,-1.453125 0.40625,1.125 C 4.441406,-0.179688 4.234375,-0.0703125 3.984375,0 3.734375,0.0703125 3.445312,0.109375 3.125,0.109375 c -0.65625,0 -1.15625,-0.1757812 -1.5,-0.53125 -0.34375,-0.363281 -0.515625,-0.882813 -0.515625,-1.5625 v -2.90625 H 0.1875 v -1.21875 h 0.921875 v -1.1875 l 1.53125,-0.25 v 1.4375 H 4.375 v 1.21875 H 2.640625 v 2.78125 c 0,0.3125 0.0625,0.539063 0.1875,0.671875 0.125,0.136719 0.304687,0.203125 0.546875,0.203125 0.269531,0 0.507812,-0.070313 0.71875,-0.21875 z m 0,0"
+ id="path652" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#ffffff"
+ fill-opacity="1"
+ id="g666"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(576.2913,280.96421)"
+ id="g664">
+ <g
+ id="g662">
+ <path
+ d="m 0.875,0 v -8.546875 h 1.53125 v 3.25 l 0.125,0.015625 c 0.195312,-0.300781 0.441406,-0.53125 0.734375,-0.6875 0.300781,-0.164062 0.660156,-0.25 1.078125,-0.25 1.34375,0 2.015625,0.765625 2.015625,2.296875 V 0 h -1.53125 v -3.734375 c 0,-0.414063 -0.085937,-0.71875 -0.25,-0.90625 -0.167969,-0.1875 -0.421875,-0.28125 -0.765625,-0.28125 -0.4375,0 -0.78125,0.148437 -1.03125,0.4375 -0.25,0.28125 -0.375,0.726563 -0.375,1.328125 V 0 Z m 0,0"
+ id="path660" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#ffffff"
+ fill-opacity="1"
+ id="g674"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(583.43283,280.96421)"
+ id="g672">
+ <g
+ id="g670">
+ <path
+ d="M 3.546875,0.109375 C 2.953125,0.109375 2.425781,-0.0078125 1.96875,-0.25 1.519531,-0.5 1.171875,-0.859375 0.921875,-1.328125 c -0.25,-0.476563 -0.375,-1.050781 -0.375,-1.71875 0,-0.664063 0.125,-1.238281 0.375,-1.71875 0.25,-0.476563 0.597656,-0.835937 1.046875,-1.078125 0.457031,-0.25 0.984375,-0.375 1.578125,-0.375 0.59375,0 1.113281,0.125 1.5625,0.375 0.457031,0.242188 0.8125,0.601562 1.0625,1.078125 0.25,0.480469 0.375,1.054687 0.375,1.71875 0,0.667969 -0.125,1.242187 -0.375,1.71875 -0.25,0.46875 -0.605469,0.828125 -1.0625,1.078125 -0.449219,0.2421875 -0.96875,0.359375 -1.5625,0.359375 z m 0,-1.296875 c 0.945313,0 1.421875,-0.617188 1.421875,-1.859375 0,-0.644531 -0.125,-1.117187 -0.375,-1.421875 -0.242188,-0.300781 -0.589844,-0.453125 -1.046875,-0.453125 -0.949219,0 -1.421875,0.625 -1.421875,1.875 0,1.242187 0.472656,1.859375 1.421875,1.859375 z m 0,0"
+ id="path668" />
+ </g>
+ </g>
+ </g>
+ <g
+ fill="#ffffff"
+ fill-opacity="1"
+ id="g682"
+ transform="translate(-43.488732,-201.52699)">
+ <g
+ transform="translate(590.51908,280.96421)"
+ id="g680">
+ <g
+ id="g678">
+ <path
+ d="m 0.875,0 v -6.09375 h 1.46875 v 0.890625 l 0.125,0.03125 c 0.375,-0.695313 0.988281,-1.046875 1.84375,-1.046875 0.707031,0 1.222656,0.195312 1.546875,0.578125 0.332031,0.386719 0.5,0.945313 0.5,1.671875 V 0 h -1.53125 v -3.78125 c 0,-0.40625 -0.085937,-0.695312 -0.25,-0.875 C 4.421875,-4.832031 4.164062,-4.921875 3.8125,-4.921875 3.363281,-4.921875 3.015625,-4.78125 2.765625,-4.5 2.523438,-4.21875 2.40625,-3.769531 2.40625,-3.15625 V 0 Z m 0,0"
+ id="path676" />
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/sources/shiboken6/doc/images/shibokenqtarch.png b/sources/shiboken6/doc/images/shibokenqtarch.png
new file mode 100644
index 000000000..c20ba4624
--- /dev/null
+++ b/sources/shiboken6/doc/images/shibokenqtarch.png
Binary files differ
diff --git a/sources/shiboken6/doc/images/shibokenqtarch.svg b/sources/shiboken6/doc/images/shibokenqtarch.svg
new file mode 100644
index 000000000..8f52b8db4
--- /dev/null
+++ b/sources/shiboken6/doc/images/shibokenqtarch.svg
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="275"
+ height="197.55103"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ version="1.0"
+ sodipodi:docname="shibokenqtarch.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="shibokenqtarch.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend"
+ style="overflow:visible">
+ <path
+ id="path3636"
+ style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.0948718"
+ inkscape:cx="130.07956"
+ inkscape:cy="99.051407"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="2552"
+ inkscape:window-height="1432"
+ inkscape:window-x="1924"
+ inkscape:window-y="4"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-maximized="0"
+ inkscape:showpageshadow="2"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid44"
+ originx="-44.999996"
+ originy="-12.44898" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-106.0768,-311.50489)">
+ <path
+ style="fill:#21be2b;fill-opacity:1;stroke:none;stroke-width:2.20567369;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 106.0768,322.72938 v 44.89796 h 262.2093 l 12.7907,-11.22449 V 311.50489 H 117.53514 Z"
+ id="path3715-5-6-7-9-8-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="fill:#17a81a;fill-opacity:1;stroke:none;stroke-width:1.57079244;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 251.99517,457.61034 v 51.44557 H 369.85231 L 381.0768,498.76679 V 447.32122 H 263.21966 Z"
+ id="path3715-5-6-7-9-6-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="fill:#53586b;fill-opacity:1;stroke:none;stroke-width:1.57079256;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 106.0768,457.61034 v 51.44557 h 117.85714 l 11.22449,-10.28912 V 447.32122 H 117.30129 Z"
+ id="path3715-5-6-7-9-6-7-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:16.6871px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.12245;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ x="120.87232"
+ y="334.88406"
+ id="text153"><tspan
+ sodipodi:role="line"
+ id="tspan151"
+ x="120.87232"
+ y="334.88406"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:16.6871px;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.12245;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">Qt for Python</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.7451px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:Titillium;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.318628"
+ x="121.09701"
+ y="354.01886"
+ id="text157"><tspan
+ sodipodi:role="line"
+ x="121.09701"
+ y="354.01886"
+ id="tspan159"
+ style="fill:#ffffff;fill-opacity:1;stroke-width:0.318628">Qt classes and functions exported to Python</tspan></text>
+ <path
+ style="fill:#53586b;fill-opacity:1;stroke:none;stroke-width:2.20567369;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 106.0768,391.19877 v 44.89796 h 262.2093 l 12.7907,-11.22449 V 379.97428 H 117.53514 Z"
+ id="path3715-5-6-7-9-8-7-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:16.6871px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.41718"
+ x="121.0225"
+ y="403.38095"
+ id="text153-2"><tspan
+ sodipodi:role="line"
+ id="tspan151-9"
+ x="121.0225"
+ y="403.38095"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:16.6871px;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke-width:0.41718">Shiboken</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.7451px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:Titillium;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.318628"
+ x="121.09701"
+ y="421.95245"
+ id="text157-1"><tspan
+ sodipodi:role="line"
+ x="121.09701"
+ y="421.95245"
+ id="tspan159-2"
+ style="fill:#ffffff;fill-opacity:1;stroke-width:0.318628">Generator that exposes C++ classes to Python</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:17.9592px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.318628"
+ x="123.35368"
+ y="482.61551"
+ id="text157-1-7"><tspan
+ sodipodi:role="line"
+ x="123.35368"
+ y="482.61551"
+ id="tspan159-2-0"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:17.9592px;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke-width:0.318628">CPython API</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:17.9592px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.41328"
+ x="271.38934"
+ y="483.42886"
+ id="text157-1-9"><tspan
+ sodipodi:role="line"
+ x="271.38934"
+ y="483.42886"
+ id="tspan159-2-3"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:17.9592px;font-family:Titillium;-inkscape-font-specification:'Titillium, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke-width:0.41328">Qt Libraries</tspan></text>
+ </g>
+</svg>
diff --git a/sources/shiboken6/doc/index.rst b/sources/shiboken6/doc/index.rst
new file mode 100644
index 000000000..68f96dded
--- /dev/null
+++ b/sources/shiboken6/doc/index.rst
@@ -0,0 +1,125 @@
+Shiboken
+********
+
+.. ifconfig:: output_format == 'html'
+
+ Shiboken is a fundamental piece on the `Qt for Python <../index.html>`__ project that serves two purposes:
+
+.. ifconfig:: output_format == 'qthelp'
+
+ Shiboken is a fundamental piece on the `Qt for Python <../pyside6/index.html>`__ project that serves two purposes:
+
+
+* Generator_: Extract information from C or C++ headers and generate CPython_ code that allow
+ to bring C or C++ projects to Python. This process uses a library called ApiExtractor_ which
+ internally uses Clang_.
+* Module_: An utility Python module that exposed new Python types, functions to handle pointers,
+ among other things, that is written in CPython_ and can use independently of the generator.
+
+.. _Generator: shibokengenerator.html
+.. _Module: shibokenmodule.html
+.. _CPython: https://github.com/python/cpython
+.. _Clang: https://clang.llvm.org/
+.. _ApiExtractor: typesystem.html
+
+Documentation
+=============
+
+.. grid:: 1 3 3 3
+ :gutter: 2
+
+ .. grid-item-card::
+ :class-item: text-center
+
+ Install and build from source.
+ +++
+ .. button-ref:: gettingstarted
+ :color: primary
+ :outline:
+ :expand:
+
+ Getting Started
+
+ .. grid-item-card::
+ :class-item: text-center
+
+ Binding generator executable.
+ +++
+ .. button-ref:: shibokengenerator
+ :color: primary
+ :outline:
+ :expand:
+
+ Shiboken Generator
+
+ .. grid-item-card::
+ :class-item: text-center
+
+ Python utility module.
+ +++
+ .. button-ref:: shibokenmodule
+ :color: primary
+ :outline:
+ :expand:
+
+ Shiboken Module
+
+ .. grid-item-card::
+ :class-item: text-center
+
+ Reference and functionallities.
+ +++
+ .. button-ref:: typesystem
+ :color: primary
+ :outline:
+ :expand:
+
+ Type System
+
+ .. grid-item-card::
+ :class-item: text-center
+
+ Using Shiboken.
+ +++
+ .. button-ref:: examples/index
+ :color: primary
+ :outline:
+ :expand:
+
+ Examples
+
+ .. grid-item-card::
+ :class-item: text-center
+
+ Generating Python stub files.
+ +++
+ .. button-ref:: shiboken-genpyi
+ :color: primary
+ :outline:
+ :expand:
+
+ shiboken6-genpyi
+
+ .. grid-item-card::
+ :class-item: text-center
+
+ Known issues and FAQ.
+ +++
+ .. button-ref:: considerations
+ :color: primary
+ :outline:
+ :expand:
+
+ Considerations
+
+.. toctree::
+ :hidden:
+ :glob:
+
+ gettingstarted.rst
+ shibokengenerator.rst
+ shibokenmodule.rst
+ typesystem.rst
+ examples/index.rst
+ shiboken-genpyi.rst
+ considerations.rst
diff --git a/sources/shiboken6/doc/scripts/patch_qhp.py b/sources/shiboken6/doc/scripts/patch_qhp.py
new file mode 100644
index 000000000..750789698
--- /dev/null
+++ b/sources/shiboken6/doc/scripts/patch_qhp.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import fileinput
+import re
+import sys
+from argparse import ArgumentParser, RawTextHelpFormatter
+
+
+DESC="""Qhp file updater
+
+Replaces virtual folder ids in .qhp files preparing for
+registering the documentation in Qt Assistant."""
+
+
+VIRTUAL_FOLDER_PATTERN = re.compile("(^.*virtualFolder.)doc(.*$)")
+# Strip "PySide6.QtModule." from index entries
+INDEX_CLASS_PATTERN = re.compile(r'^(\s*<keyword name=")PySide6\.[^.]+\.(.*\(class in .*)$')
+INDEX_METHOD_PATTERN = re.compile(r'^(\s+<keyword name=".* \()PySide6\.[^.]+\.(.*>)$')
+
+
+virtual_folder = ""
+strip_pyside_module = False
+
+
+def process_line(line):
+ global virtual_folder
+ match = VIRTUAL_FOLDER_PATTERN.match(line)
+ if match:
+ print(f"{match.group(1)}{virtual_folder}{match.group(2)}")
+ return
+ if strip_pyside_module:
+ match = INDEX_METHOD_PATTERN.match(line)
+ if match:
+ print(f"{match.group(1)}{match.group(2)}")
+ return
+ match = INDEX_CLASS_PATTERN.match(line)
+ if match:
+ print(f"{match.group(1)}{match.group(2)}")
+ return
+ sys.stdout.write(line)
+
+
+if __name__ == '__main__':
+ arg_parser = ArgumentParser(description=DESC,
+ formatter_class=RawTextHelpFormatter)
+ arg_parser.add_argument('-v', '--vfolder', type=str,
+ help='String to be injected into the Qhp file.')
+ arg_parser.add_argument("--pyside", "-p", action="store_true",
+ help="Strip the PySide module path off the index entries.")
+ arg_parser.add_argument("file", type=str, help='Qhp filename.')
+ options = arg_parser.parse_args()
+ virtual_folder = options.vfolder
+ strip_pyside_module = options.pyside
+
+ try:
+ with fileinput.input(options.file, inplace=True,
+ backup=".bak") as fh:
+ for line in fh:
+ process_line(line)
+ except Exception as e:
+ print(f"WARNING: patch_qhp.py failed: {e}", file=sys.stderr)
diff --git a/sources/shiboken6/doc/shiboken-genpyi.rst b/sources/shiboken6/doc/shiboken-genpyi.rst
new file mode 100644
index 000000000..44d0edb97
--- /dev/null
+++ b/sources/shiboken6/doc/shiboken-genpyi.rst
@@ -0,0 +1,32 @@
+.. _shiboken6-genpyi:
+
+shiboken6-genpyi
+================
+
+`shiboken6-genpyi` is a command line tool to generate Python stub files
+(.pyi) for any shiboken binding-based module (not just PySide). Stub
+files define signatures of all classes, methods (including overloads),
+constants and enums of a module. Signatures also contain type hints.
+This helps your module integrate with Python type checkers and IDEs.
+For example, if you use any function from your module, your IDE's
+function lookup feature will show you the function signature and its
+parameters and return value including types.
+
+
+Usage
+-----
+
+To generate stub files for a module, run the following command:
+
+.. code-block:: bash
+
+ shiboken6-genpyi <module_names> [OPTIONS]
+
+where `<module_names>` is a space-separated list of module names (the
+modules must be importable from the working directory) and where
+`[OPTIONS]` can be one of the following:
+
+* **--quiet**: Run the tool quietly without output to stdout.
+* **--outpath <output_dir>**: Specify the output directory for the
+ generated stub files. If not specified, the stub files are generated
+ in the location of the module binary.
diff --git a/sources/shiboken6/doc/shibokengenerator.rst b/sources/shiboken6/doc/shibokengenerator.rst
new file mode 100644
index 000000000..14340ab69
--- /dev/null
+++ b/sources/shiboken6/doc/shibokengenerator.rst
@@ -0,0 +1,393 @@
+.. _gen-overview:
+
+******************
+Generator Overview
+******************
+
+The following diagram summarizes Shiboken's role in the Qt for Python
+project.
+
+.. image:: images/qtforpython-underthehood.png
+
+An XML typesystem file is used to specify the types to be exposed to Python
+and to apply modifications to properly represent and manipulate the types in
+the Python World. For example, you can remove and add methods to certain types,
+and also modify the arguments of each method. These actions are inevitable to
+properly handle the data structures or types.
+
+The final outcome of this process is a set of wrappers written in CPython,
+which can be used as a module in your Python code.
+
+In a few words, the Generator is a utility that parses a collection of header and
+typesystem files, generating other files (code, documentation, etc.) as result.
+
+Creating new bindings
+=====================
+
+.. figure:: images/bindinggen-development.png
+ :scale: 80
+ :align: center
+
+ Creating new bindings
+
+Each module of the generator system has an specific role.
+
+1. Provide enough data about the classes and functions.
+2. Generate valid code, with modifications from typesystems and injected codes.
+3. Modify the API to expose the objects in a way that fits you target language best.
+4. Insert customizations where handwritten code is needed.
+
+.. figure:: images/shibokenqtarch.png
+ :scale: 80
+ :align: center
+
+ Runtime architecture
+
+The newly created binding will run on top of Shiboken which takes
+care of interfacing Python and the underlying C++ library.
+
+Handwritten inputs
+==================
+
+Creating new bindings involves creating several pieces of "code": the header,
+the typesystem and, in most cases, the injected code.
+
+**header** A header with ``#include`` directives listing all the headers of the
+ desired classes. This header is not referenced by the generated code.
+ Alternatively, it is possible to pass a list of the headers of the
+ desired classes directly on the command line. In this case,
+ the command line option ``--use-global-header`` should be passed as
+ well to prevent the headers from being suppressed in the generated
+ code.
+
+::ref:`typesystem`: XML files that provides the developer with a tool to customize the
+ way that the generators will see the classes and functions. For
+ example, functions can be renamed, have its signature changed and
+ many other actions.
+::ref:`inject code <codeinjectionsemantics>`: allows the developer to insert
+ handwritten code where the generated code is not suitable or
+ needs some customization.
+
+.. _command-line:
+
+Command line options
+********************
+
+Usage
+-----
+
+::
+
+ shiboken [options] header-file(s) typesystem-file
+
+
+Options
+-------
+
+``--disable-verbose-error-messages``
+ Disable verbose error messages. Turn the CPython code hard to debug but saves a few kilobytes
+ in the generated binding.
+
+.. _parent-heuristic:
+
+``--enable-parent-ctor-heuristic``
+ This flag enable an useful heuristic which can save a lot of work related to object ownership when
+ writing the typesystem.
+ For more info, check :ref:`ownership-parent-heuristics`.
+
+.. _pyside-extensions:
+
+``--enable-pyside-extensions``
+ Enable pyside extensions like support for signal/slots. Use this if you are creating a binding based
+ on PySide.
+
+.. _return-heuristic:
+
+``--enable-return-value-heuristic``
+ Enable heuristics to detect parent relationship on return values.
+ For more info, check :ref:`return-value-heuristics`.
+
+.. _avoid-protected-hack:
+
+``--avoid-protected-hack``
+ Avoid the use of the '#define protected public' hack.
+
+.. _use-isnull-as-nb-bool:
+
+``--use-isnull-as-nb-bool``
+ If a class has an isNull() const method, it will be used to
+ compute the value of boolean casts (see :ref:`bool-cast`).
+ The legacy option ``--use-isnull-as-nb_nonzero`` has the
+ same effect, but should not be used any more.
+
+``--lean-headers``
+ Forward declare classes in module headers instead of including their class
+ headers where possible.
+
+.. _use-operator-bool-as-nb-bool:
+
+``--use-operator-bool-as-nb-bool``
+ If a class has an operator bool, it will be used to compute
+ the value of boolean casts (see :ref:`bool-cast`).
+ The legacy option ``--use-operator-bool-as-nb_nonzero`` has the
+ same effect, but should not be used any more.
+
+.. _no-implicit-conversions:
+
+``--no-implicit-conversions``
+ Do not generate implicit_conversions for function arguments.
+
+.. _api-version:
+
+``--api-version=<version>``
+ Specify the supported api version used to generate the bindings.
+
+.. _documentation-only:
+
+``--documentation-only``
+ Do not generate any code, just the documentation.
+
+.. _drop-type-entries:
+
+``--drop-type-entries="<TypeEntry0>[;TypeEntry1;...]"``
+ Semicolon separated list of type system entries (classes, namespaces,
+ global functions and enums) to be dropped from generation. Values are
+ fully qualified Python type names ('Module.Class'), but the module can
+ be omitted ('Class').
+
+.. _conditional_keywords:
+
+``-keywords=keyword1[,keyword2,...]``
+ A comma-separated list of keywords for conditional typesystem parsing
+ (see :ref:`conditional_processing`).
+
+``--use-global-header``
+ Use the global headers passed on the command line in generated code.
+
+.. _generation-set:
+
+``--generation-set``
+ Generator set to be used (e.g. qtdoc).
+
+.. _skip-deprecated:
+
+``--skip-deprecated``
+ Skip deprecated functions.
+
+.. _diff:
+
+``--diff``
+ Print a diff of wrapper files.
+
+.. _dryrun:
+
+``--dryrun``
+ Dry run, do not generate wrapper files.
+
+.. _--project-file:
+
+``--project-file=<file>``
+ Text file containing a description of the binding project.
+ Replaces and overrides command line arguments.
+
+.. _clang_option:
+
+``--clang-option=<option>``
+ Option to be passed to clang
+
+.. _clang_options:
+
+``--clang-options=<option1>[,<option2>,...]>``
+ Options to be passed to clang.
+ When '-' is passed as the first option in the list, none of the options
+ built into shiboken will be added, allowing for a complete replacement.
+
+``--compiler=<type>``
+ Emulated compiler type (g++, msvc, clang)
+
+``--compiler-path=<file>``
+ Path to the compiler for determining builtin include paths
+
+``--platform=<file>``
+ Emulated platform (windows, darwin, unix)
+
+.. _include-paths:
+
+``-I<path>, --include-paths=<path>[:<path>:...]``
+ Include paths used by the C++ parser.
+
+.. _system-include-paths:
+
+``-isystem<path>, --system-include-paths=<path>[:<path>:...]``
+ System include paths used by the C++ parser
+
+.. _framework-include-paths:
+
+``-F<path>, --framework-include-paths=<path>[:<path>:...]``
+ Framework include paths used by the C++ parser
+
+.. _force-process-system-include-paths:
+
+``--force-process-system-include-paths=<path>[:<path>:...]``
+ Include paths that are considered as system headers by the C++ parser,
+ but should still be processed to extract types
+
+.. _language-level:
+
+``--language-level=, -std=<level>``
+ C++ Language level (c++11..c++17, default=c++14)
+
+.. _typesystem-paths:
+
+``-T<path>, --typesystem-paths=<path>[:<path>:...]``
+ Paths used when searching for type system files.
+
+.. _output-directory:
+
+``--output-directory=[dir]``
+ The directory where the generated files will be written.
+
+.. _license-file=[license-file]:
+
+``--license-file=[license-file]``
+ File used for copyright headers of generated files.
+
+.. _no-suppress-warnings:
+
+``--no-suppress-warnings``
+ Show all warnings.
+
+``--log-unmatched``
+ Prints :ref:`suppress-warning` and :ref:`rejection` elements that were
+ not matched. This is useful for cleaning up old type system files.
+
+.. _silent:
+
+``--silent``
+ Avoid printing any message.
+
+.. _debug-level:
+
+``--debug-level=[sparse|medium|full]``
+ Set the debug level.
+
+.. _help:
+
+``--help``
+ Display this help and exit.
+
+``--print-builtin-types``
+ Print information about builtin types
+
+.. _version:
+
+``--version``
+ Output version information and exit.
+
+QtDocGenerator Options
+----------------------
+
+.. _doc-parser:
+
+``--doc-parser=<parser>``
+ The documentation parser used to interpret the documentation
+ input files (qdoc|doxygen).
+
+.. _documentation-code-snippets-dir:
+
+``--documentation-code-snippets-dir=<dir>``
+ Directory used to search code snippets used by the documentation.
+
+.. _documentation-data-dir:
+
+``--documentation-data-dir=<dir>``
+ Directory with XML files generated by documentation tool.
+
+.. _documentation-extra-sections-dir=<dir>:
+
+``--documentation-extra-sections-dir=<dir>``
+ Directory used to search for extra documentation sections.
+
+.. _library-source-dir:
+
+``--library-source-dir=<dir>``
+ Directory where library source code is located.
+
+.. _additional-documentation:
+
+``--additional-documentation=<file>``
+ List of additional XML files to be converted to .rst files
+ (for example, tutorials).
+
+``--inheritance-file=<file>``
+ Generate a JSON file containing the class inheritance.
+
+``--disable-inheritance-diagram``
+ Disable the generation of the inheritance diagram.
+
+.. _project-file:
+
+********************
+Binding Project File
+********************
+
+Instead of directing the Generator behavior via command line, the binding
+developer can write a text project file describing the same information, and
+avoid the hassle of a long stream of command line arguments.
+
+.. _project-file-structure:
+
+The project file structure
+==========================
+
+Here follows a comprehensive example of a generator project file.
+
+.. code-block:: ini
+
+ [generator-project]
+ generator-set = path/to/generator/CHOICE_GENERATOR
+ header-file = DIR/global.h" />
+ typesystem-file = DIR/typesystem_for_your_binding.xml
+ output-directory location="OUTPUTDIR" />
+ include-path = path/to/library/being/wrapped/headers/1
+ include-path = path/to/library/being/wrapped/headers/2
+ typesystem-path = path/to/directory/containing/type/system/files/1
+ typesystem-path = path/to/directory/containing/type/system/files/2
+ enable-parent-ctor-heuristic
+
+
+Project file tags
+=================
+
+The generator project file tags are in direct relation to the
+:ref:`command line arguments <command-line>`. All of the current command line
+options provided by |project| were already seen on the
+:ref:`project-file-structure`, for new command line options provided by
+additional generator modules (e.g.: qtdoc, Shiboken) could also be used in the
+generator project file following simple conversion rules.
+
+For tags without options, just write as an empty tag without any attributes.
+Example:
+
+.. code-block:: bash
+
+ --BOOLEAN-ARGUMENT
+
+becomes
+
+.. code-block:: ini
+
+ BOOLEAN-ARGUMENT
+
+and
+
+.. code-block:: bash
+
+ --VALUE-ARGUMENT=VALUE
+
+becomes
+
+.. code-block:: ini
+
+ VALUE-ARGUMENT = VALUE
+
diff --git a/sources/shiboken6/doc/shibokenmodule.rst b/sources/shiboken6/doc/shibokenmodule.rst
new file mode 100644
index 000000000..3bc4fa6ba
--- /dev/null
+++ b/sources/shiboken6/doc/shibokenmodule.rst
@@ -0,0 +1,147 @@
+.. module:: Shiboken
+
+.. |maya| unicode:: Maya U+2122
+
+.. _shiboken-module:
+
+Shiboken module
+***************
+
+Functions
+^^^^^^^^^
+
+.. container:: function_list
+
+ * def :meth:`isValid<shiboken.isValid>` (obj)
+ * def :meth:`wrapInstance<shiboken.wrapInstance>` (address, type)
+ * def :meth:`getCppPointer<shiboken.getCppPointer>` (obj)
+ * def :meth:`delete<shiboken.delete>` (obj)
+ * def :meth:`isOwnedByPython<shiboken.isOwnedByPython>` (obj)
+ * def :meth:`wasCreatedByPython<shiboken.wasCreatedByPython>` (obj)
+ * def :meth:`dump<shiboken.dump>` (obj)
+ * def :meth:`disassembleFrame<shiboken.disassembleFrame>` (marker)
+
+Detailed description
+^^^^^^^^^^^^^^^^^^^^
+
+This Python module can be used to access internal information related to our
+binding technology. Access to this internal information is required to e.g.:
+integrate PySide with Qt based programs that offer Python scripting like |maya|
+or just for debug purposes.
+
+Some function description refer to "Shiboken based objects", wich means
+Python objects instances of any Python Type created using Shiboken.
+
+To import the module:
+
+.. code-block:: python
+
+ from shiboken6 import Shiboken
+
+.. function:: isValid(obj)
+
+ Given a Python object, returns True if the object methods can be called
+ without an exception being thrown. A Python wrapper becomes invalid when
+ the underlying C++ object is destroyed or unreachable.
+
+.. function:: wrapInstance(address, type)
+
+ Creates a Python wrapper for a C++ object instantiated at a given memory
+ address - the returned object type will be the same given by the user.
+
+ The type must be a Shiboken type, the C++ object will not be
+ destroyed when the returned Python object reach zero references.
+
+ If the address is invalid or doesn't point to a C++ object of given type
+ the behavior is undefined.
+
+.. function:: getCppPointer(obj)
+
+ Returns a tuple of longs that contain the memory addresses of the
+ C++ instances wrapped by the given object.
+
+.. function:: delete(obj)
+
+ Deletes the C++ object wrapped by the given Python object.
+
+.. function:: isOwnedByPython(obj)
+
+ Given a Python object, returns True if Python is responsible for deleting
+ the underlying C++ object, False otherwise.
+
+ If the object was not a Shiboken based object, a TypeError is
+ thrown.
+
+.. function:: wasCreatedByPython(obj)
+
+ Returns true if the given Python object was created by Python.
+
+.. function:: dump(obj)
+
+ Returns a string with implementation-defined information about the
+ object.
+ This method should be used **only** for debug purposes by developers
+ creating their own bindings as no guarantee is provided that
+ the string format will be the same across different versions.
+
+ If the object is not a Shiboken based object, a message is printed.
+
+.. function:: disassembleFrame(label)
+
+ Prints the current executing Python frame to stdout and flushes.
+ The disassembly is decorated by some label. Example:
+
+ .. code-block:: python
+
+ lambda: 42
+
+ is shown from inside C++ as
+
+ .. code-block:: c
+
+ <label> BEGIN
+ 1 0 LOAD_CONST 1 (42)
+ 2 RETURN_VALUE
+ <label> END
+
+ When you want to set a breakpoint at the `disassembleFrame` function
+ and you use it from C++, you use the pure function name.
+
+ When you want to use it from Python, you can insert it into your Python
+ code and then maybe instead set a breakpoint at `SbkShibokenModule_disassembleFrame`
+ which is the generated wrapper.
+
+ `label` is a simple string in C++. In Python, you can use any object;
+ internally the `str` function is called with it.
+
+ This method should be used **only** for debug purposes by developers.
+
+ .. function:: dumpTypeGraph(file_name)
+
+ Dumps the inheritance graph of the types existing in libshiboken
+ to ``.dot`` file for use with `Graphviz <https://graphviz.org/>`_.
+
+.. function:: dumpWrapperMap()
+
+ 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)
+ :param size: int
+ :param writeable: int
+
+ Represents a chunk of memory by address and size and implements the ``buffer`` protocol.
+ It can be constructed from a ``buffer``, a Shiboken based object, a memory address
+ or another VoidPtr instance.
+
+ .. py:method:: toBytes()
+
+ :rtype: bytes
+
+ Returns the contents as ``bytes``.
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
new file mode 100644
index 000000000..26f929801
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem.rst
@@ -0,0 +1,68 @@
+Type System Reference
+=====================
+
+The typesystem is used by a binding generator or any other software using the APIExtractor library
+to map a C++ library API onto a higher level language.
+
+The typesystem specification is a handwritten XML document listing the types
+that will be available in the generated target language API; types that are not
+declared in the specification will be ignored along with everything depending on
+them. In addition, it is possible to manipulate and modify types and functions.
+It is even possible to use the typesystem specification to inject arbitrary
+code into the source files, such as an extra member function.
+
+Below there is a complete reference guide to the various nodes (XML tags) of the typesystem.
+For usage examples, take a look at the typesystem files used to generate PySide6. These files
+can be found in the PySide6/<QT_MODULE_NAME> directory of the PySide6 package.
+
+Define types
+------------
+
+.. toctree::
+ :maxdepth: 1
+
+ typesystem_specifying_types.rst
+ typesystem_builtin_types.rst
+
+Code generation
+---------------
+
+.. toctree::
+ :maxdepth: 1
+
+ typesystem_codegeneration.rst
+
+Modifying types
+---------------
+
+.. toctree::
+ :maxdepth: 1
+
+ typesystem_arguments.rst
+ typesystem_codeinjection.rst
+ typesystem_converters.rst
+ typesystem_containers.rst
+ typesystem_templates.rst
+ typesystem_modify_function.rst
+ typesystem_manipulating_objects.rst
+ typesystem_conversionrule.rst
+ typesystem_documentation.rst
+ typesystem_variables.rst
+
+Object ownership
+----------------
+
+.. toctree::
+ :maxdepth: 1
+
+ typesystem_ownership.rst
+
+Extra options and Python caveats
+--------------------------------
+
+.. toctree::
+ :maxdepth: 1
+
+ typesystem_solving_compilation.rst
+ typesystem_specialfunctions.rst
+ typediscovery.rst
diff --git a/sources/shiboken6/doc/typesystem_arguments.rst b/sources/shiboken6/doc/typesystem_arguments.rst
new file mode 100644
index 000000000..d950b6c32
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_arguments.rst
@@ -0,0 +1,229 @@
+.. _modifying-arguments:
+
+Modifying Arguments
+-------------------
+
+.. _conversionrule-on-arguments:
+
+conversion-rule
+^^^^^^^^^^^^^^^
+
+The ``conversion-rule`` node allows you to write customized code to convert
+the given argument between the target language and C++.
+It is then a child of the :ref:`modify-argument` node:
+
+.. code-block:: xml
+
+ <modify-argument index="2">
+ <!-- for the second argument of the function -->
+ <conversion-rule class="target | native">
+ // the code
+ </conversion-rule>
+ </modify-argument>
+
+The ``class`` attribute accepts one of the following values to define the
+conversion direction to be either ``target-to-native`` or ``native-to-target``:
+
+* ``native``: Defines the conversion direction to be ``target-to-native``.
+ It is similar to the existing ``<target-to-native>`` element.
+ See :ref:`Conversion Rule Tag <conversion-rule-tag>` for more information.
+
+* ``target``: Defines the conversion direction to be ``native-to-target``.
+ It is similar to the existing ``<native-to-target>`` element.
+ See :ref:`Conversion Rule Tag <conversion-rule-tag>` for more information.
+
+This node is typically used in combination with the :ref:`replace-type` and
+:ref:`remove-argument` nodes. The given code is used instead of the generator's
+conversion code.
+
+Writing %N in the code (where N is a number), will insert the name of the
+nth argument. Alternatively, %in and %out which will be replaced with the
+name of the conversion's input and output variable, respectively. Note the
+output variable must be declared explicitly, for example:
+
+.. code-block:: xml
+
+ <conversion-rule class="native">
+ bool %out = (bool) %in;
+ </conversion-rule>
+
+.. note::
+
+ You can also use the ``conversion-rule`` node to specify
+ :ref:`a conversion code which will be used instead of the generator's conversion code everywhere for a given type <conversion-rule-tag>`.
+
+.. _remove-argument:
+
+remove-argument
+^^^^^^^^^^^^^^^
+
+The ``remove-argument`` node removes the given argument from the function's
+signature, and it is a child of the :ref:`modify-argument` node.
+
+.. code-block:: xml
+
+ <modify-argument>
+ <remove-argument />
+ </modify-argument>
+
+.. _rename-to:
+
+rename to
+^^^^^^^^^
+
+The ``rename to`` node is used to rename a argument and use this new name in
+the generated code, and it is a child of the :ref:`modify-argument` node.
+
+.. code-block:: xml
+
+ <modify-argument>
+ <rename to='...' />
+ </modify-argument>
+
+.. warning:: This tag is deprecated, use the ``rename`` attribute from :ref:`modify-argument` tag instead.
+
+.. _remove-default-expression:
+
+remove-default-expression
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``remove-default-expression`` node disables the use of the default expression
+for the given argument, and it is a child of the :ref:`modify-argument` node.
+
+.. code-block:: xml
+
+ <modify-argument...>
+ <remove-default-expression />
+ </modify-argument>
+
+.. _replace-default-expression:
+
+replace-default-expression
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``replace-default-expression`` node replaces the specified argument with the
+expression specified by the ``with`` attribute, and it is a child of the
+:ref:`modify-argument` node.
+
+.. code-block:: xml
+
+ <modify-argument>
+ <replace-default-expression with="..." />
+ </modify-argument>
+
+.. _replace-type:
+
+replace-type
+^^^^^^^^^^^^
+
+The ``replace-type`` node replaces the type of the given argument to the one
+specified by the ``modified-type`` attribute, and it is a child of the
+:ref:`modify-argument` node.
+
+.. code-block:: xml
+
+ <modify-argument>
+ <replace-type modified-type="..." />
+ </modify-argument>
+
+If the new type is a class, the ``modified-type`` attribute must be set to
+the fully qualified name (including name of the package as well as the class
+name).
+
+.. _define-ownership:
+
+define-ownership
+^^^^^^^^^^^^^^^^
+
+The ``define-ownership`` tag indicates that the function changes the ownership
+rules of the argument object, and it is a child of the
+:ref:`modify-argument` node.
+The ``class`` attribute specifies the class of
+function where to inject the ownership altering code
+(see :ref:`codegenerationterminology`). The ``owner`` attribute
+specifies the new ownership of the object. It accepts the following values:
+
+* target: the target language will assume full ownership of the object.
+ The native resources will be deleted when the target language
+ object is finalized.
+* c++: The native code assumes full ownership of the object. The target
+ language object will not be garbage collected.
+* default: The object will get default ownership, depending on how it
+ was created.
+
+.. code-block:: xml
+
+ <modify-argument>
+ <define-ownership class="target | native"
+ owner="target | c++ | default" />
+ </modify-argument>
+
+.. _reference-count:
+
+reference-count
+^^^^^^^^^^^^^^^
+
+The ``reference-count`` tag dictates how an argument should be handled by the
+target language reference counting system (if there is any), it also indicates
+the kind of relationship the class owning the function being modified has with
+the argument. It is a child of the :ref:`modify-argument` node.
+For instance, in a model/view relation a view receiving a model
+as argument for a **setModel** method should increment the model's reference
+counting, since the model should be kept alive as much as the view lives.
+Remember that out hypothetical view could not become parent of the model,
+since the said model could be used by other views as well.
+The ``action`` attribute specifies what should be done to the argument
+reference counting when the modified method is called. It accepts the
+following values:
+
+* add: increments the argument reference counter.
+* add-all: increments the reference counter for each item in a collection.
+* remove: decrements the argument reference counter.
+* set: will assign the argument to the variable containing the reference.
+* ignore: does nothing with the argument reference counter
+ (sounds worthless, but could be used in situations
+ where the reference counter increase is mandatory
+ by default).
+
+.. code-block:: xml
+
+ <modify-argument>
+ <reference-count action="add|add-all|remove|set|ignore" variable-name="..." />
+ </modify-argument>
+
+
+The variable-name attribute specifies the name used for the variable that
+holds the reference(s).
+
+.. _replace-value:
+
+replace-value
+^^^^^^^^^^^^^
+
+The ``replace-value`` attribute lets you replace the return statement of a
+function with a fixed string. This attribute can only be used for the
+argument at ``index`` 0, which is always the function's return value.
+
+.. code-block:: xml
+
+ <modify-argument index="0" replace-value="this"/>
+
+.. _parent:
+
+parent
+^^^^^^
+
+The ``parent`` node lets you define the argument parent which will
+take ownership of argument and will destroy the C++ child object when the
+parent is destroyed (see :ref:`ownership-parent`).
+It is a child of the :ref:`modify-argument` node.
+
+.. code-block:: xml
+
+ <modify-argument index="1">
+ <parent index="this" action="add | remove" />
+ </modify-argument>
+
+In the ``index`` argument you must specify the parent argument. The action
+*add* creates a parent link between objects, while *remove* will undo the
+parentage relationship.
diff --git a/sources/shiboken6/doc/typesystem_builtin_types.rst b/sources/shiboken6/doc/typesystem_builtin_types.rst
new file mode 100644
index 000000000..dea253930
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_builtin_types.rst
@@ -0,0 +1,58 @@
+.. _builtin-types:
+
+Built-in Types
+--------------
+
+.. _primitive-cpp-types:
+
+Primitive C++ Types
+^^^^^^^^^^^^^^^^^^^
+
+Shiboken knows the C++ primitive types like int and float and gathers
+information about typedefs like `int32_t` and `size_t` at runtime while
+parsing C++ headers. Function overloads using these types will be
+automatically generated. To suppress a primitive type, use the
+:ref:`rejection` tag.
+
+In principle, there is no need to specify them in the typesystem
+file using the :ref:`primitive-type` tag.
+
+However, specifying a type means that the type name is used for
+matching signatures of functions for :ref:`modification <modify-function>`.
+So, it might make sense to specify architecture-dependent types like `size_t`
+to avoid having to spell out the resolved type, which might differ depending
+on platform.
+
+`std::string`, `std::wstring` and their associated view types
+`std::string_view`, `std::wstring_view` are also supported.
+
+
+.. _builtin-cpp-container-types:
+
+C++ Container Types
+^^^^^^^^^^^^^^^^^^^
+
+The C++ containers ``std::list``\, ``std::vector``\,
+``std::pair``\, ``std::map``\, ``std::span`` and ``std::unordered_map`` are
+built-in.
+To specify :ref:`opaque-containers`, use the :ref:`opaque-container` element.
+:ref:`container-type` can still be specified to modify the built-in behavior.
+For this case, a number of pre-defined conversion templates
+are provided (see :ref:`predefined_templates`).
+
+.. _cpython-types:
+
+CPython Types
+^^^^^^^^^^^^^
+
+Python types like `str` match types like `PyUnicode` in the *Concrete Objects
+Layer* of CPython. They have check functions like `PyUnicode_Check()`, which
+Shiboken generates into the code checking the function arguments.
+
+These types occur as parameters when :ref:`adding functions <add-function>`
+or :ref:`modifying types <replace-type>`, as type on `add-conversion`
+within a :ref:`conversion-rule` or as target language API types on
+:ref:`primitive-type`.
+
+They are built into Shiboken as :ref:`custom types <custom-type>` along
+with their check functions.
diff --git a/sources/shiboken6/doc/typesystem_codegeneration.rst b/sources/shiboken6/doc/typesystem_codegeneration.rst
new file mode 100644
index 000000000..fb41e28e1
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_codegeneration.rst
@@ -0,0 +1,37 @@
+.. _codegenerationterminology:
+
+***************************
+Code Generation Terminology
+***************************
+
+Types of generated code
+=======================
+
+
+**Python Wrapper**
+ The code that exports the C++ wrapped class to Python. **Python wrapper**
+ refers to all the code needed to export a C++ class to Python, and
+ **Python method/function wrapper** means the specific function that calls
+ the C++ method/function on behalf of Python. This code is invoked from
+ the Python side.
+
+**C++ Wrapper**
+ This term refers to a generated C++ class that extends a class from the
+ wrapped library. It is generated only when a wrapped C++ class is
+ polymorphic, i.e. it has or inherits any virtual methods.
+ The **C++ Wrapper** overrides the virtual methods of the wrapped C++ class
+ with code that allows for overriding the method with a Python implementation.
+ It checks whether a corresponding method in the Python instance exists and
+ calls it. This code is invoked from the C++ side.
+
+
+Specifying a target for modifications
+=====================================
+
+In the typesystem files, the ``class`` attribute is used to which class a
+modification is applied (see :ref:`codeinjectionsemantics`,
+:ref:`objectownership`).
+The value **Target** means the modification is applied to the
+**Python Wrapper**. The value **Native** means the modification is applied to
+the **C++ Wrapper**.
+
diff --git a/sources/shiboken6/doc/typesystem_codeinjection.rst b/sources/shiboken6/doc/typesystem_codeinjection.rst
new file mode 100644
index 000000000..03d5f4b16
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_codeinjection.rst
@@ -0,0 +1,397 @@
+.. _codeinjectionsemantics:
+
+************************
+Code Injection Semantics
+************************
+
+:std:doc:`API Extractor <shibokengenerator>` provides the
+:ref:`inject-code <inject-code>` tag
+allowing the user to put custom written code to on specific locations of the generated code.
+Yet this is only part of what is needed to generate proper binding code, where the custom code
+should be written to depends upon the technology used on the generated binding code.
+
+This is the ``inject-code`` tag options that matters to |project|.
+
+.. code-block:: xml
+
+ <inject-code class="native | target" position="beginning | end">
+ // custom code
+ </inject-code>
+
+
+inject-code tag
+===============
+
+The following table describes the semantics of :ref:`inject-code` tag as used on
+|project|. The ``class`` attribute specifies whether to code is injected
+into the **C++ Wrapper** or the **Python Wrapper** (see
+:ref:`codegenerationterminology`).
+The ``position`` attribute specifies the location of the custom code in the
+function.
+
+
++---------------+------+-----------+--------------------------------------------------------------+
+|Parent Tag |Class |Position |Meaning |
++===============+======+===========+==============================================================+
+|value-type, |native|beginning |Write to the beginning of a class wrapper ``.cpp`` file, right|
+|object-type | | |after the ``#include`` clauses. A common use would be to write|
+| | | |prototypes for custom functions whose definitions are put on a|
+| | | |``native/end`` code injection. |
+| | +-----------+--------------------------------------------------------------+
+| | |end |Write to the end of a class wrapper ``.cpp`` file. Could be |
+| | | |used to write custom/helper functions definitions for |
+| | | |prototypes declared on ``native/beginning``. |
+| +------+-----------+--------------------------------------------------------------+
+| |target|beginning |Put custom code on the beginning of the wrapper initializer |
+| | | |function (``init_CLASS(PyObject *module)``). This could be |
+| | | |used to manipulate the ``PyCLASS_Type`` structure before |
+| | | |registering it on Python. |
+| | +-----------+--------------------------------------------------------------+
+| | |end |Write the given custom code at the end of the class wrapper |
+| | | |initializer function (``init_CLASS(PyObject *module)``). The |
+| | | |code here will be executed after all the wrapped class |
+| | | |components have been initialized. |
++---------------+------+-----------+--------------------------------------------------------------+
+|modify-function|native|beginning |Code here is put on the virtual method override of a C++ |
+| | | |wrapper class (the one responsible for passing C++ calls to a |
+| | | |Python override, if there is any), right after the C++ |
+| | | |arguments have been converted but before the Python call. |
+| | +-----------+--------------------------------------------------------------+
+| | |end |This code injection is put in a virtual method override on the|
+| | | |C++ wrapper class, after the call to Python and before |
+| | | |dereferencing the Python method and tuple of arguments. |
+| +------+-----------+--------------------------------------------------------------+
+| |target|beginning |This code is injected on the Python method wrapper |
+| | | |(``PyCLASS_METHOD(...)``), right after the decisor have found |
+| | | |which signature to call and also after the conversion of the |
+| | | |arguments to be used, but before the actual call. |
+| | +-----------+--------------------------------------------------------------+
+| | |end |This code is injected on the Python method wrapper |
+| | | |(``PyCLASS_METHOD(...)``), right after the C++ method call, |
+| | | |but still inside the scope created by the overload for each |
+| | | |signature. |
+| +------+-----------+--------------------------------------------------------------+
+| |shell |declaration|Used only for virtual functions. This code is injected at the |
+| | | |top. |
+| | +-----------+--------------------------------------------------------------+
+| | |override |Used only for virtual functions. The code is injected before |
+| | | |the code calling the Python override. |
+| | +-----------+--------------------------------------------------------------+
+| | |beginning |Used only for virtual functions. The code is injected when the|
+| | | |function does not has a Python implementation, then the code |
+| | | |is inserted before c++ call |
+| | +-----------+--------------------------------------------------------------+
+| | |end |Same as above, but the code is inserted after c++ call |
++---------------+------+-----------+--------------------------------------------------------------+
+|typesystem |native|beginning |Write code to the beginning of the module ``.cpp`` file, right|
+| | | |after the ``#include`` clauses. This position has a similar |
+| | | |purpose as the ``native/beginning`` position on a wrapper |
+| | | |class ``.cpp`` file, namely write function prototypes, but not|
+| | | |restricted to this use. |
+| | +-----------+--------------------------------------------------------------+
+| | |end |Write code to the end of the module ``.cpp`` file. Usually |
+| | | |implementations for function prototypes inserted at the |
+| | | |beginning of the file with a ``native/beginning`` code |
+| | | |injection. |
+| +------+-----------+--------------------------------------------------------------+
+| |target|beginning |Insert code at the start of the module initialization function|
+| | | |(``initMODULENAME()``), before the calling ``Py_InitModule``. |
+| | +-----------+--------------------------------------------------------------+
+| | |end |Insert code at the end of the module initialization function |
+| | | |(``initMODULENAME()``), but before the checking that emits a |
+| | | |fatal error in case of problems importing the module. |
+| | +-----------+--------------------------------------------------------------+
+| | |declaration|Insert code into module header. |
++---------------+------+-----------+--------------------------------------------------------------+
+
+
+Anatomy of Code Injection
+=========================
+
+To make things clear let's use a simplified example of generated wrapper code
+and the places where each kind of code injection goes.
+
+Below is the example C++ class for whom wrapper code will be generated.
+
+.. code-block:: c++
+
+ class InjectCode
+ {
+ public:
+ InjectCode();
+ double overloadedMethod(int arg);
+ double overloadedMethod(double arg);
+ virtual int virtualMethod(int arg);
+ };
+
+From the C++ class, |project| will generate a ``injectcode_wrapper.cpp`` file
+with the binding code. The next section will use a simplified version of the
+generated wrapper code with the injection spots marked with comments.
+
+There are a number of placeholders indicated by a percent sign ``%``, which
+will be expanded when inserting the code. For a list, see
+:ref:`typesystemvariables`.
+
+Noteworthy Cases
+----------------
+
+The type system description system gives the binding developer a lot of
+flexibility, which is power, which comes with responsibility. Some modifications
+to the wrapped API will not be complete without some code injection.
+
+
+Removing arguments and setting a default values for them
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A simple case is when a function have one argument removed, as when the C++
+method ``METHOD(ARG)`` is modified to be used from Python as ``METHOD()``;
+of course the binding developer must provide some guidelines to the generator
+on what to do to call it. The most common solution is to remove the argument and
+set a default value for it at the same time, so the original C++ method could be
+called without problems.
+
+Removing arguments and calling the method with your own hands
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the argument is removed and no default value is provided, the generator will
+not write any call to the method and expect the ``modify-function - target/beginning``
+code injection to call the original C++ method on its own terms. If even this
+custom code is not provided the generator will put an ``#error`` clause to
+prevent compilation of erroneous binding code.
+
+Calling the method with your own hands always!
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If your custom code to be injected contains a call to the wrapped C++ method,
+it surely means that you don't want the generator to write another call to the
+same method. As expected |project| will detect the user written call on the code
+injection and will not write its own call, but for this to work properly the
+binding developer must use the template variable ``%FUNCTION_NAME`` instead
+of writing the actual name of the wrapped method/function.
+
+In other words, use
+
+.. code-block:: xml
+
+ <inject-code class="target" position="beginning | end">
+ %CPPSELF.originalMethodName();
+ </inject-code>
+
+
+instead of
+
+
+.. code-block:: xml
+
+ <inject-code class="target" position="beginning | end">
+ %CPPSELF.%FUNCTION_NAME();
+ </inject-code>
+
+
+Code Injection for Functions/Methods
+====================================
+
+
+.. _codeinjecting_method_native:
+
+On The Native Side
+------------------
+
+Notice that this is only used when there is a C++ wrapper, i.e. the wrapped
+class is polymorphic.
+
+.. code-block:: c++
+
+ int InjectCodeWrapper::virtualMethod(int arg)
+ {
+ PyObject *method = BindingManager::instance().getOverride(this, "virtualMethod");
+ if (!py_override)
+ return this->InjectCode::virtualMethod(arg);
+
+ (... here C++ arguments are converted to Python ...)
+
+ // INJECT-CODE: <modify-function><inject-code class="native" position="beginning">
+ // Uses: pre method call custom code, modify the argument before the
+ // Python call.
+
+ (... Python method call goes in here ...)
+
+ // INJECT-CODE: <modify-function><inject-code class="native" position="end">
+ // Uses: post method call custom code, modify the result before delivering
+ // it to C++ caller.
+
+ (... Python method and argument tuple are dereferenced here ...)
+
+ return Shiboken::Converter<int>::toCpp(method_result);
+ }
+
+
+On The Target Side
+------------------
+
+All the overloads of a method from C++ are gathered together on a single Python
+method that uses an overload decisor to call the correct C++ method based on the
+arguments passed by the Python call. Each overloaded method signature has its
+own ``beginning`` and ``end`` code injections.
+
+.. code-block:: c++
+
+ static PyObject *PyInjectCode_overloadedMethod(PyObject *self, PyObject *arg)
+ {
+ PyObject* py_result{};
+ if (PyFloat_Check(arg)) {
+ double cpp_arg0 = Shiboken::Converter<double >::toCpp(arg);
+
+ // INJECT-CODE: <modify-function><inject-code class="target" position="beginning">
+ // Uses: pre method call custom code.
+
+ py_result = Shiboken::Converter<double >::toPython(
+ PyInjectCode_cptr(self)->InjectCode::overloadedMethod(cpp_arg0)
+ );
+
+ // INJECT-CODE: <modify-function><inject-code class="target" position="end">
+ // Uses: post method call custom code.
+
+ } else if (PyNumber_Check(arg)) {
+ (... other overload calling code ...)
+ } else goto PyInjectCode_overloadedMethod_TypeError;
+
+ if (PyErr_Occurred() || !py_result)
+ return {};
+
+ return py_result;
+
+ PyInjectCode_overloadedMethod_TypeError:
+ PyErr_SetString(PyExc_TypeError, "'overloadedMethod()' called with wrong parameters.");
+ return {};
+ }
+
+
+.. _codeinjecting_classes:
+
+Code Injection for Wrapped Classes
+==================================
+
+.. _codeinjecting_classes_native:
+
+On The Native Side
+------------------
+
+Those injections go in the body of the ``CLASSNAME_wrapper.cpp`` file for the
+wrapped class.
+
+.. code-block:: c++
+
+ // Start of ``CLASSNAME_wrapper.cpp``
+ #define protected public
+ // default includes
+ #include <shiboken.h>
+ (...)
+ #include "injectcode_wrapper.h"
+ using namespace Shiboken;
+
+ // INJECT-CODE: <value/object-type><inject-code class="native" position="beginning">
+ // Uses: prototype declarations
+
+ (... C++ wrapper virtual methods, if any ...)
+
+ (... Python wrapper code ...)
+
+ PyAPI_FUNC(void)
+ init_injectcode(PyObject *module)
+ {
+ (...)
+ }
+
+ (...)
+
+ // INJECT-CODE: <value/object-type><inject-code class="native" position="end">
+ // Uses: definition of functions prototyped at ``native/beginning``.
+
+ // End of ``CLASSNAME_wrapper.cpp``
+
+
+.. _codeinjecting_classes_target:
+
+On The Target Side
+------------------
+
+Code injections to the class Python initialization function.
+
+.. code-block:: c++
+
+ // Start of ``CLASSNAME_wrapper.cpp``
+
+ (...)
+
+ PyAPI_FUNC(void)
+ init_injectcode(PyObject *module)
+ {
+ // INJECT-CODE: <value/object-type><inject-code class="target" position="beginning">
+ // Uses: Alter something in the PyInjectCode_Type (tp_flags value for example)
+ // before registering it.
+
+ if (PyType_Ready(&PyInjectCode_Type) < 0)
+ return;
+
+ Py_INCREF(&PyInjectCode_Type);
+ PyModule_AddObject(module, "InjectCode",
+ ((PyObject*)&PyInjectCode_Type));
+
+ // INJECT-CODE: <value/object-type><inject-code class="target" position="end">
+ // Uses: do something right after the class is registered, like set some static
+ // variable injected on this same file elsewhere.
+ }
+
+ (...)
+
+ // End of ``CLASSNAME_wrapper.cpp``
+
+Code Injection for Modules
+==========================
+
+The C++ libraries are wrapped as Python modules, a collection of classes,
+functions, enums and namespaces. |project| creates wrapper files for all of
+them and also one extra ``MODULENAME_module_wrapper.cpp`` to register the whole
+module. Code injection xml tags who have the ``typesystem`` tag as parent will
+be put on this file.
+
+On The Native Side
+------------------
+
+This works exactly as the class wrapper code injections :ref:`codeinjecting_classes_native`.
+
+On The Target Side
+------------------
+
+This is very similar to class wrapper code injections :ref:`codeinjecting_classes_target`.
+Notice that the inject code at ``target/end`` is inserted before the check for errors
+to prevent bad custom code to pass unnoticed.
+
+.. code-block:: c++
+
+ // Start of ``MODULENAME_module_wrapper.cpp``
+
+ (...)
+ initMODULENAME()
+ {
+ // INJECT-CODE: <typesystem><inject-code class="target" position="beginning">
+ // Uses: do something before the module is created.
+
+ PyObject *module = Py_InitModule("MODULENAME", MODULENAME_methods);
+
+ (... initialization of wrapped classes, namespaces, functions and enums ...)
+
+ // INJECT-CODE: <typesystem><inject-code class="target" position="end">
+ // Uses: do something after the module is registered and initialized.
+
+ if (PyErr_Occurred())
+ Py_FatalError("can't initialize module sample");
+ }
+
+ (...)
+
+ // Start of ``MODULENAME_module_wrapper.cpp``
+
+In addition, code can be injected into the module header by specifying ``target``
+and ``declaration``. This is useful for type definitions.
diff --git a/sources/shiboken6/doc/typesystem_containers.rst b/sources/shiboken6/doc/typesystem_containers.rst
new file mode 100644
index 000000000..b5593e20f
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_containers.rst
@@ -0,0 +1,284 @@
+.. _opaque-containers:
+
+*****************
+Opaque Containers
+*****************
+
+Normally, Python containers such as ``list`` or ``dict`` are passed when
+calling C++ functions taking a corresponding C++ container (see
+:ref:`container-type`).
+
+This means that for each call, the entire Python container is converted to
+a C++ container, which can be inefficient when for example creating plots
+from lists of points.
+
+To work around this, special opaque containers can generated which wrap an
+underlying C++ container directly (currently implemented for ``list`` types).
+They implement the sequence protocol and can be passed to the function
+instead of a Python list. Manipulations like adding or removing elements
+can applied directly to them using the C++ container functions.
+
+This is achieved by specifying the name and the instantiated type
+in the ``opaque-containers`` attribute of :ref:`container-type`
+or using the :ref:`opaque-container` element for existing container types.
+
+A second use case are public fields of container types. In the normal case,
+they are converted to Python containers on read access. By a field modification,
+(see :ref:`modify-field`), it is possible to obtain an opaque container
+which avoids the conversion and allows for direct modification of elements.
+
+Getters returning references can also be modified to return opaque containers.
+This is done by modifying the return type to the name of the opaque container
+(see :ref:`replace-type`).
+
+The table below lists the functions supported for opaque sequence containers
+besides the sequence protocol (element access via index and ``len()``). Both
+the STL and the Qt naming convention (which resembles Python's) are supported:
+
++-------------------------------------------+-----------------------------------+
+|Function | Description |
++-------------------------------------------+-----------------------------------+
+| ``push_back(value)``, ``append(value)`` | Appends *value* to the sequence. |
++-------------------------------------------+-----------------------------------+
+| ``push_front(value)``, ``prepend(value)`` | Prepends *value* to the sequence. |
++-------------------------------------------+-----------------------------------+
+| ``clear()`` | Clears the sequence. |
++-------------------------------------------+-----------------------------------+
+| ``pop_back()``, ``removeLast()`` | Removes the last element. |
++-------------------------------------------+-----------------------------------+
+| ``pop_front()``, ``removeFirst()`` | Removes the first element. |
++-------------------------------------------+-----------------------------------+
+| ``reserve(size)`` | For containers that support it |
+| | (``std::vector``, ``QList``), |
+| | allocate memory for at least |
+| | ``size`` elements, preventing |
+| | reallocations. |
++-------------------------------------------+-----------------------------------+
+| ``capacity()`` | For containers that support it |
+| | (``std::vector``, ``QList``), |
+| | return the number of elements |
+| | that can be stored without |
+| | reallocation. |
++-------------------------------------------+-----------------------------------+
+| ``data()`` | For containers that support it |
+| | (``std::vector``, ``QList``), |
+| | return a buffer viewing the |
+| | memory. |
++-------------------------------------------+-----------------------------------+
+| ``constData()`` | For containers that support it |
+| | (``std::vector``, ``QList``), |
+| | return a read-only buffer viewing |
+| | the memory. |
++-------------------------------------------+-----------------------------------+
+
+
+.. note:: ``std::span``, being a non-owning container, is currently replaced by a
+ ``std::vector`` for argument passing. This means that an opaque container
+ wrapping a ``std::span`` obtained from a function will be converted
+ to a ``std::vector`` by sequence conversion when passed to a function
+ taking a ``std::span``.
+ Opaque containers wrapping a ``std::vector`` can be passed without conversion.
+ This is currently experimental and subject to change.
+
+Following is an example on creating an opaque container named ``IntVector``
+from `std::vector<int>`, and using it in Python.
+
+We will consider three separate use cases.
+
+**Case 1** - When a Python list is passed to C++ function
+``TestOpaqueContainer.getVectorSum(const std::vector<int>&)`` as an opaque container
+
+.. code-block:: c
+
+ class TestOpaqueContainer
+ {
+ public:
+ static int getVectorSum(const std::vector<int>& intVector)
+ {
+ return std::accumulate(intVector.begin(), intVector.end(), 0);
+ }
+ };
+
+**Case 2** - When we have a C++ class named ``TestOpaqueContainer`` with a ``std::vector<int>``
+public variable
+
+.. code-block:: c
+
+ class TestOpaqueContainer
+ {
+ public:
+ std::vector<int> intVector;
+
+ };
+
+**Case 3** - When we have a C++ class named ``TestOpaqueContainer`` with a ``std::vector<int>`` as
+private variable and the variable is returned by a reference through a getter.
+
+.. code-block:: c
+
+ class TestOpaqueContainer
+ {
+ public:
+ std::vector<int>& getIntVector()
+ {
+ return this->intVector;
+ }
+
+ private:
+ std::vector<int> intVector;
+
+ };
+
+.. note:: Cases 2 and 3 are generally considered to be bad class design in C++. However, the purpose
+ of these examples are rather to show the different possibilities with opaque containers in
+ Shiboken than the class design.
+
+In all the three cases, we want to use ``intVector`` in Python through an opaque-container. The
+first thing to do is to create the corresponding ``<container-type />`` attribute in the typesystem
+file, making Shiboken aware of the ``IntVector``.
+
+.. code-block:: xml
+
+ <container-type name="std::vector" type="vector" opaque-containers="int:IntVector">
+ <include file-name="vector" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist"/>
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer"/>
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </container-type>
+
+For the rest of the steps, we consider the three cases separately.
+
+**Case 1** - When a Python list is passed to a C++ function
+
+As the next step, we create a typesystem entry for the class ``TestOpaqueContainer``.
+
+.. code-block:: xml
+
+ <value-type name="TestOpaqueContainer" />
+
+In this case, the typesystem entry is simple and the function
+``getVectorSum(const std::vector<int>&)`` accepts ``IntVector`` as the parameter. This is
+because inherantly ``IntVector`` is the same as ``std::vector<int>``.
+
+Now, build the code to create the ``*_wrapper.cpp`` and ``*.so`` files which we import into Python.
+
+Verifying the usage in Python
+
+.. code-block:: bash
+
+ >>> vector = IntVector()
+ >>> vector.push_back(2)
+ >>> vector.push_back(3)
+ >>> len(vector)
+ 2
+ >>> TestOpaqueContainer.getVectorSum(vector)
+ vector sum is 5
+
+**Case 2** - When the variable is public
+
+We create a typesystem entry for the class ``TestOpaqueContainer``.
+
+.. code-block:: xml
+
+ <value-type name="TestOpaqueContainer">
+ <modify-field name="intVector" opaque-container="yes"/>
+ </value-type>
+
+In the ``<modify-field />`` notice the ``opaque-container="yes"``. Since the type
+of ``intVector`` is ``std::vector<int>``, it picks up the ``IntVector`` opaque
+container.
+
+Build the code to create the ``*_wrapper.cpp`` and ``*.so`` files which we import into Python.
+
+Verifying the usage in Python
+
+.. code-block:: bash
+
+ >>> test = TestOpaqueContainer()
+ >>> test
+ <Universe.TestOpaqueContainer object at 0x7fe17ef30c30>
+ >>> test.intVector.push_back(1)
+ >>> test.intVector.append(2)
+ >>> len(test.intVector)
+ 2
+ >>> test.intVector[1]
+ 2
+ >>> test.intVector.removeLast()
+ >>> len(test.intVector)
+ 1
+
+**Case 3** - When the variable is private and returned by reference through a getter
+
+Similar to the previous cases, we create a typesystem entry for the class ``TestOpaqueContainer``.
+
+.. code-block:: xml
+
+ <value-type name="TestOpaqueContainer">
+ <modify-function signature="getIntVector()">
+ <modify-argument index="return">
+ <replace-type modified-type="IntVector" />
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+In this case, we specify the name of the opaque container ``IntVector`` in the ``<replace-type />``
+field.
+
+Build the code to create the \*_wrapper.cpp and \*.so files which we import into Python.
+
+Verifying the usage in Python
+
+.. code-block:: bash
+
+ >>> test = TestOpaqueContainer()
+ >>> test
+ <Universe.TestOpaqueContainer object at 0x7f62b9094c30>
+ >>> vector = test.getIntVector()
+ >>> vector
+ <Universe.IntVector object at 0x7f62b91f7d00>
+ >>> vector.push_back(1)
+ >>> vector.push_back(2)
+ >>> len(vector)
+ 2
+ >>> vector[1]
+ 2
+ >>> vector.removeLast()
+ >>> len(vector)
+ 1
+
+In all the three cases, if we check out the corresponding wrapper class for the module, we will see
+the lines
+
+.. code-block:: c
+
+ static PyMethodDef IntVector_methods[] = {
+ {"push_back", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::push_back),METH_O, "push_back"},
+ {"append", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::push_back),METH_O, "append"},
+ {"clear", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::clear), METH_NOARGS, "clear"},
+ {"pop_back", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::pop_back), METH_NOARGS,
+ "pop_back"},
+ {"removeLast", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::pop_back), METH_NOARGS,
+ "removeLast"},
+ {nullptr, nullptr, 0, nullptr} // Sentinel
+ };
+
+This means, the above mentioned methods are available to be used in Python with the ``IntVector``
+opaque container.
+
+.. note:: `Plot example <https://doc.qt.io/qtforpython/examples/example_widgets_painting_plot.html>`_
+ demonstrates an example of using an opaque container `QPointList`, which wraps a C++
+ `QList<QPoint>`. The corresponding typesystem file where QPointList can be found `here
+ <https://code.qt.io/cgit/pyside/pyside-setup.git/tree/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml>`_
+
diff --git a/sources/shiboken6/doc/typesystem_conversionrule.rst b/sources/shiboken6/doc/typesystem_conversionrule.rst
new file mode 100644
index 000000000..9a8f51c18
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_conversionrule.rst
@@ -0,0 +1,133 @@
+.. _conversion-rule-tag:
+
+Conversion Rule Tag
+-------------------
+
+.. _conversion-rule:
+
+conversion-rule
+^^^^^^^^^^^^^^^
+
+The **conversion-rule** tag specifies how a **primitive-type**, a **container-type**,
+or a **value-type** may be converted to and from the native C++ language types to the
+target language types (see also :ref:`user-defined-type-conversion`).
+
+It is a child of the :ref:`container-type`, :ref:`primitive-type` or
+:ref:`value-type` and may contain :ref:`native-to-target` or
+:ref:`native-to-target` child nodes.
+
+.. code-block:: xml
+
+ <value-type>
+ <conversion-rule>
+ <native-to-target>
+ // Code to convert a native value to a target language object.
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type='TARGETTYPEA' check='TARGETTYPEA_CHECK(%in)'>
+ // Code to convert target language type object of type TARGETTYPEA
+ // to the C++ native type represented by the value/primitive/container-type.
+ </add-conversion>
+ <add-conversion type='TARGETTYPEB' check='TARGETTYPEB_CHECK(%in)'>
+ // Code to convert target language type object of type TARGETTYPEB
+ // to the C++ native type represented by the value/primitive/container-type.
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </value-type>
+
+The code can be inserted directly, via :ref:`add-conversion` (providing snippet
+functionality) or via :ref:`insert-template` (XML template,
+see :ref:`using-code-templates`).
+
+The example above show the structure of a complete conversion rule. Each of the
+child tags comprising the conversion rule are described in their own sections
+below.
+
+.. note::
+
+ You can also use the ``conversion-rule`` node to specify customized code
+ to convert a function argument between the target language and C++
+ (see :ref:`conversionrule-on-arguments`).
+
+.. _native-to-target:
+
+native-to-target
+^^^^^^^^^^^^^^^^
+
+The **native-to-target** tag tells how to convert a native C++ value to its
+target language equivalent. It is a child of the :ref:`conversion-rule` node.
+The text inside the tag is a C++ code the takes
+an input value an does what's needed to convert it to the output value.
+:ref:`insert-template` tags may be used to insert commonly repeating code.
+
+.. code-block:: xml
+
+ <conversion-rule>
+ <native-to-target>
+ // Code to convert a native value to a target language object.
+ </native-to-target>
+ </conversion-rule>
+
+Use the replace node to modify the template code.
+Notice that the generator must provide type system variables for the input
+and output values and types, namely **%in**, **%out**, **%INTYPE** and
+**%OUTTYPE**. In the case of container types, **%INTYPE** refers to the
+full container type (e.g. **"list<int>"**) and **%INTYPE_0**, **%INTYPE_1**,
+**%INTYPE_#**, should be replaced by the types used in the container template
+(e.g. **%INTYPE_0** correspondes to **"int"** for **"list<int>"**).
+
+The ``file`` and ``snippet`` attributes are also supported (see :ref:`inject-code` nodes).
+
+.. _target-to-native:
+
+target-to-native
+^^^^^^^^^^^^^^^^
+
+The **target-to-native** tag encloses at least one, but usually many, conversions
+from target language values to C++ native values. It is a child of the
+:ref:`conversion-rule` node and may have one or several :ref:`add-conversion`
+child nodes. The *optional* attribute ``replace`` tells if the target
+language to C++ conversions will be added to, or if they will replace the
+implicit conversions collected by *ApiExtractor*. The default
+value for it is *yes*.
+
+
+.. code-block:: xml
+
+ <conversion-rule>
+ <target-to-native replace='yes|no'>
+ // List of target to native conversions meant to replace or expand
+ // the already existing implicit conversions.
+ </target-to-native>
+ </conversion-rule>
+
+
+.. _add-conversion:
+
+add-conversion
+^^^^^^^^^^^^^^
+
+Each **add-conversion** tag adds a rule for conversion of a target language type,
+indicated by the ``type`` attribute, to the C++ native type represented by the
+**primitive-type**, a **container-type**, or **value-type**, to which the parent
+**conversion-rule** belongs.
+It is a child of the :ref:`target-to-native` node.
+
+.. code-block:: xml
+
+ <target-to-native>
+ <add-conversion type='TARGETTYPE' check='TARGETTYPECHECK(%in)'>
+ // Code to convert target language type object of type TARGETTYPE_A
+ // to the C++ native type represented by the value/primitive/container-type.
+ </add-conversion>
+ <target-to-native>
+
+The ``check`` attribute tells how a target value should be checked to see if it belongs to
+the type expected. This attribute is *optional*, for it can be derived from the ``type``
+attribute, but it isn't unusual that some special check is needed. The variables
+**%in**, **%out**, **%INTYPE**, **%INTYPE_#**, and **%OUTTYPE**, must be provided by
+the generator as in the ``native-to-target`` tag.
+
+The ``file`` and ``snippet`` attributes are also supported (see :ref:`inject-code` nodes).
+
diff --git a/sources/shiboken6/doc/typesystem_converters.rst b/sources/shiboken6/doc/typesystem_converters.rst
new file mode 100644
index 000000000..ab6fba930
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_converters.rst
@@ -0,0 +1,235 @@
+.. _user-defined-type-conversion:
+
+****************************
+User Defined Type Conversion
+****************************
+
+In the process of creating Python bindings of a C++ library, most of the C++
+classes will have wrappers representing them in Python land.
+But there may be other classes that are very simple and/or have a Python type
+as a direct counter part. (Example: a "Complex" class, that represents complex
+numbers, has a Python equivalent in the "complex" type.) Such classes, instead
+of getting a Python wrapper, normally have conversions rules, from Python to
+C++ and vice-versa.
+
+.. code-block:: c++
+
+ // C++ class
+ struct Complex {
+ Complex(double real, double imag);
+ double real() const;
+ double imag() const;
+ };
+
+ // Converting from C++ to Python using the CPython API:
+ PyObject* pyCpxObj = PyComplex_FromDoubles(complex.real(), complex.imag());
+
+ // Converting from Python to C++:
+ double real = PyComplex_RealAsDouble(pyCpxObj);
+ double imag = PyComplex_ImagAsDouble(pyCpxObj);
+ Complex cpx(real, imag);
+
+
+For the user defined conversion code to be inserted in the proper places,
+the :ref:`conversion-rule` tag must be used.
+
+.. code-block:: xml
+
+ <primitive-type name="Complex" target-lang-api-name="PyComplex">
+ <include file-name="complex.h" location="global"/>
+
+ <conversion-rule>
+
+ <native-to-target>
+ return PyComplex_FromDoubles(%in.real(), %in.imag());
+ </native-to-target>
+
+ <target-to-native>
+ <!-- The 'check' attribute can be derived from the 'type' attribute,
+ it is defined here to test the CHECKTYPE type system variable. -->
+ <add-conversion type="PyComplex" check="%CHECKTYPE[Complex](%in)">
+ double real = PyComplex_RealAsDouble(%in);
+ double imag = PyComplex_ImagAsDouble(%in);
+ %out = %OUTTYPE(real, imag);
+ </add-conversion>
+ </target-to-native>
+
+ </conversion-rule>
+
+ </primitive-type>
+
+
+The details will be given later, but the gist of it are the tags
+:ref:`native-to-target <native-to-target>`, which has only one conversion from C++ to Python, and
+:ref:`native-to-native <target-to-native>`, that may define the conversion of multiple Python types
+to C++'s "Complex" type.
+
+.. image:: images/converter.png
+ :height: 240px
+ :align: center
+
+|project| expects the code for :ref:`native-to-target <native-to-target>`, to directly return the
+Python result of the conversion, and the added conversions inside the
+:ref:`target-to-native <target-to-native>` must attribute the Python to C++ conversion result to
+the :ref:`%out <out>` variable.
+
+Expanding on the last example, if the binding developer want a Python 2-tuple
+of numbers to be accepted by wrapped C++ functions with "Complex" arguments,
+an :ref:`add-conversion <add-conversion>` tag and a custom check must be added.
+Here's how to do it:
+
+.. code-block:: xml
+
+ <!-- Code injection at module level. -->
+ <inject-code class="native" position="beginning">
+ static bool Check2TupleOfNumbers(PyObject* pyIn) {
+ if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2))
+ return false;
+ Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0));
+ if (!PyNumber_Check(pyReal))
+ return false;
+ Shiboken::AutoDecRef pyImag(PySequence_GetItem(pyIn, 1));
+ if (!PyNumber_Check(pyImag))
+ return false;
+ return true;
+ }
+ </inject-code>
+
+ <primitive-type name="Complex" target-lang-api-name="PyComplex">
+ <include file-name="complex.h" location="global"/>
+
+ <conversion-rule>
+
+ <native-to-target>
+ return PyComplex_FromDoubles(%in.real(), %in.imag());
+ </native-to-target>
+
+ <target-to-native>
+
+ <add-conversion type="PyComplex">
+ double real = PyComplex_RealAsDouble(%in);
+ double imag = PyComplex_ImagAsDouble(%in);
+ %out = %OUTTYPE(real, imag);
+ </add-conversion>
+
+ <add-conversion type="PySequence" check="Check2TupleOfNumbers(%in)">
+ Shiboken::AutoDecRef pyReal(PySequence_GetItem(%in, 0));
+ Shiboken::AutoDecRef pyImag(PySequence_GetItem(%in, 1));
+ double real = %CONVERTTOCPP[double](pyReal);
+ double imag = %CONVERTTOCPP[double](pyImag);
+ %out = %OUTTYPE(real, imag);
+ </add-conversion>
+
+ </target-to-native>
+
+ </conversion-rule>
+
+ </primitive-type>
+
+
+.. _container_conversions:
+
+Container Conversions
+=====================
+
+Converters for :ref:`container-type <container-type>` are pretty much the same as for other type,
+except that they make use of the type system variables
+:ref:`%INTYPE_# <intype_n>` and :ref:`%OUTTYPE_# <outtype_n>`.
+|project| combines the conversion code for containers with the conversion
+defined (or automatically generated) for the containers.
+
+.. code-block:: xml
+
+ <container-type name="std::map" type="map">
+ <include file-name="map" location="global"/>
+
+ <conversion-rule>
+
+ <native-to-target>
+ PyObject* %out = PyDict_New();
+ %INTYPE::const_iterator it = %in.begin();
+ for (; it != %in.end(); ++it) {
+ %INTYPE_0 key = it->first;
+ %INTYPE_1 value = it->second;
+ PyDict_SetItem(%out,
+ %CONVERTTOPYTHON[%INTYPE_0](key),
+ %CONVERTTOPYTHON[%INTYPE_1](value));
+ }
+ return %out;
+ </native-to-target>
+
+ <target-to-native>
+
+ <add-conversion type="PyDict">
+ PyObject* key;
+ PyObject* value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(%in, &amp;pos, &amp;key, &amp;value)) {
+ %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
+ %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
+ %out.insert(%OUTTYPE::value_type(cppKey, cppValue));
+ }
+ </add-conversion>
+
+ </target-to-native>
+ </conversion-rule>
+ </container-type>
+
+.. note:: The C++ containers ``std::list``\, ``std::vector``\,
+ ``std::pair``\, ``std::map``\, ``std::span`` and ``std::unordered_map`` are
+ built-in.
+ To specify :ref:`opaque-containers`, use the :ref:`opaque-container` element.
+ :ref:`container-type` can still be specified to modify the built-in behavior.
+ For this case, a number of pre-defined conversion templates
+ are provided (see :ref:`predefined_templates`).
+
+.. _variables_and_functions:
+
+Variables & Functions
+=====================
+
+
+.. _in:
+
+**%in**
+ Variable replaced by the C++ input variable.
+
+
+.. _out:
+
+**%out**
+ Variable replaced by the C++ output variable. Needed to convey the
+ result of a Python to C++ conversion.
+
+
+.. _intype:
+
+**%INTYPE**
+ Used in Python to C++ conversions. It is replaced by the name of type for
+ which the conversion is being defined. Don't use the type's name directly.
+
+
+.. _intype_n:
+
+**%INTYPE_#**
+ Replaced by the name of the #th type used in a container.
+
+
+.. _outtype:
+
+**%OUTTYPE**
+ Used in Python to C++ conversions. It is replaced by the name of type for
+ which the conversion is being defined. Don't use the type's name directly.
+
+
+.. _outtype_n:
+
+**%OUTTYPE_#**
+ Replaced by the name of the #th type used in a container.
+
+
+.. _checktype:
+
+**%CHECKTYPE[CPPTYPE]**
+ Replaced by a |project| type checking function for a Python variable.
+ The C++ type is indicated by ``CPPTYPE``.
diff --git a/sources/shiboken6/doc/typesystem_documentation.rst b/sources/shiboken6/doc/typesystem_documentation.rst
new file mode 100644
index 000000000..4e7d18b99
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_documentation.rst
@@ -0,0 +1,62 @@
+Manipulating Documentation
+--------------------------
+
+inject-documentation
+^^^^^^^^^^^^^^^^^^^^
+
+The inject-documentation node inserts the documentation into the generated
+documentation. This node is a child of the :ref:`object-type`,
+:ref:`value-type` and :ref:`modify-function` nodes.
+
+.. code-block:: xml
+
+ <value-type>
+ <inject-documentation mode="append | prepend | replace" format="native | target"
+ file="[file]" snippet="[label]">
+ // the documentation
+ </inject-code>
+ </value-type>
+
+The **mode** attribute default value is *replace*.
+
+The **format** attribute specifies when the documentation injection will
+occur and it accepts the following values:
+
+* native: Before XML<->Backend transformation occur, so the injected code *must* be a valid XML.
+* target: After XML<->Backend transformation occur, so the injected code *must* be a valid backend format.
+
+The optional ``file`` attribute specifies the file name
+(see :ref:`external-snippets`).
+
+The optional ``snippet`` attribute specifies the snippet label
+(see :ref:`external-snippets`).
+
+At the moment the only supported backend is Sphinx.
+
+If the injected documentation contains a Sphinx function directive, no
+directive will be auto-generated. This can be used to add parameter
+documentation to added functions.
+
+modify-documentation
+^^^^^^^^^^^^^^^^^^^^
+
+The modify-documentation node allows you to change the auto-generated
+documentation. . This node is a child of the :ref:`object-type`,
+:ref:`value-type` and :ref:`modify-function` nodes.
+API Extractor transforms XML's from `qdoc`_ (the Qt documentation
+tool) into .rst files to be processed later using `Sphinx`_. You can modify
+the XML before the transformation takes place.
+
+.. _`qdoc`: https://doc.qt.io/qt-6/qdoc-index.html
+
+.. _`Sphinx`: https://www.sphinx-doc.org/en/master
+
+.. code-block:: xml
+
+ <modify-documentation xpath="...">
+ <!-- new documentation -->
+ </modify-documentation>
+
+The **xpath** attribute is the `XPath`_ to the node that you want to modify.
+
+.. _`XPath`: https://www.w3.org/TR/1999/REC-xpath-19991116/
diff --git a/sources/shiboken6/doc/typesystem_manipulating_objects.rst b/sources/shiboken6/doc/typesystem_manipulating_objects.rst
new file mode 100644
index 000000000..e024cdf00
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_manipulating_objects.rst
@@ -0,0 +1,556 @@
+.. _manipulating-object-and-value-types:
+
+Manipulating Object and Value Types
+-----------------------------------
+
+.. _inject-code:
+
+inject-code
+^^^^^^^^^^^
+
+The ``inject-code`` node inserts the given code into the generated code for the
+given type or function, and it is a child of the :ref:`object-type`, :ref:`value-type`,
+:ref:`modify-function` and :ref:`add-function` nodes.
+It may contain :ref:`insert-template` child nodes.
+
+.. code-block:: xml
+
+ <inject-code class="native | target"
+ position="beginning | end" since="..."
+ file="[file]"
+ snippet="[label]"/>
+
+
+The ``class`` attribute specifies which module of the generated code that
+will be affected by the code injection
+(see :ref:`codegenerationterminology`). The ``class`` attribute accepts the
+following values:
+
+* ``native``: The c++ code
+* ``target``: The binding code
+
+If the ``position`` attribute is set to *beginning* (the default), the code
+is inserted at the beginning of the function. If it is set to *end*, the code
+is inserted at the end of the function.
+
+For a detailed description of how to above attributes interact,
+see :ref:`codeinjectionsemantics`.
+
+The optional ``file`` attribute specifies the file name
+(see :ref:`external-snippets`).
+
+The optional ``snippet`` attribute specifies the snippet label
+(see :ref:`external-snippets`).
+
+There are a number of placeholders which are replaced when injecting
+code (see :ref:`typesystemvariables`).
+
+There are severals ways to specify the code:
+
+Embedding Code into XML
+=======================
+
+The code can be embedded into XML (be careful to use the correct XML entities
+for characters like '<', '>', '&'):
+
+.. code-block:: xml
+
+ <value-type>
+ <inject-code class="native | target"
+ position="beginning | end" since="...">
+ // the code
+ </inject-code>
+ </value-type>
+
+
+Using a Template Specified in XML
+=================================
+
+It is possible to create code templates for reuse in XML
+(see :ref:`using-code-templates`). This allows for replacing of custom
+placeholders.
+
+.. code-block:: xml
+
+ <value-type>
+ <inject-code class="native | target" class="native | target">
+ <insert-template name="template_name"/>
+ </inject-code>
+ </value-type>
+
+
+.. _external-snippets:
+
+Using Snippets From External Files
+==================================
+
+Code or documentation snippets can also be retrieved from external
+files found in the typesystem search path (see :ref:`typesystem-paths`).
+
+.. code-block:: xml
+
+ <value-type>
+ <inject-code class="native | target"
+ position="beginning | end" since="..."
+ file="external_source.cpp"
+ snippet="label"/>
+ </value-type>
+
+
+In the external file ``external_source.cpp``, the code between annotations
+of the form:
+
+.. code-block:: c++
+
+ // @snippet label
+ ...
+ // @snippet label
+
+
+will be extracted.
+
+.. _modify-field:
+
+modify-field
+^^^^^^^^^^^^
+
+The ``modify-field`` node allows you to alter the access privileges for a given
+C++ field when mapping it onto the target language, and it is a child of an
+:ref:`object-type` or a :ref:`value-type` node.
+
+.. code-block:: xml
+
+ <object-type>
+ <modify-field name="..."
+ write="true | false"
+ read="true | false"
+ remove="true | false"
+ opaque-container = "yes | no"
+ snake-case="yes | no | both" />
+ </object-type>
+
+The ``name`` attribute is the name of the field, the *optional* ``write``
+and ``read`` attributes specify the field's access privileges in the target
+language API (both are set to true by default).
+
+The ``remove`` attribute is an *optional* boolean attribute, which can
+mark the field to be discarded on generation.
+
+The *optional* ``rename`` attribute can be used to change the name of the
+given field in the generated target language API.
+
+The *optional* ``opaque-container`` attribute specifies whether
+an opaque container should be returned on read access
+(see :ref:`opaque-containers`).
+
+The *optional* **snake-case** attribute allows for overriding the value
+specified on the class entry or **typesystem** element.
+
+.. _modify-function:
+
+modify-function
+^^^^^^^^^^^^^^^
+
+The ``modify-function`` node allows you to modify a given C++ function when
+mapping it onto the target language, and it is a child of a :ref:`function`,
+:ref:`namespace`, :ref:`object-type` or a :ref:`value-type` node.
+Use the :ref:`modify-argument` node to specify which argument the
+modification affects.
+
+.. code-block:: xml
+
+ <object-type>
+ <modify-function signature="..."
+ since="..."
+ remove="true | false"
+ access="public | private | protected"
+ allow-thread="true | auto | false"
+ exception-handling="no | auto-off | auto-on | yes"
+ final="true | false"
+ overload-number="number"
+ rename="..."
+ snake-case="yes | no | both"
+ deprecated = "true | false" />
+ </object-type>
+
+The ``signature`` attribute is a normalized C++ signature, excluding return
+values but including potential const declarations. It is not required
+when ``modify-function`` appears as a child of a :ref:`function` node to
+modify a global function.
+
+The ``since`` attribute specify the API version when this function was modified.
+
+The ``allow-thread`` attribute specifies whether a function should be wrapped
+into ``Py_BEGIN_ALLOW_THREADS`` and ``Py_END_ALLOW_THREADS``, that is,
+temporarily release the GIL (global interpreter lock). Doing so is required
+for any thread-related function (wait operations), functions that might call
+a virtual function (potentially reimplemented in Python), and recommended for
+lengthy I/O operations or similar. It has performance costs, though.
+The value ``auto`` means that it will be turned off for functions for which
+it is deemed to be safe, for example, simple getters.
+The attribute defaults to ``false``.
+
+The ``exception-handling`` attribute specifies whether to generate exception
+handling code (nest the function call into try / catch statements). It accepts
+the following values:
+
+* no, false: Do not generate exception handling code
+* auto-off: Generate exception handling code for functions
+ declaring a non-empty ``throw`` list
+* auto-on: Generate exception handling code unless function
+ declares ``noexcept``
+* yes, true: Always generate exception handling code
+
+The optional ``overload-number`` attribute specifies the position of the
+overload when checking arguments. Typically, when a number of overloads
+exists, as for in example in Qt:
+
+.. code-block:: c++
+
+ void QPainter::drawLine(QPointF, QPointF);
+ void QPainter::drawLine(QPoint, QPoint);
+
+they will be reordered such that the check for matching arguments for the
+one taking a ``QPoint`` is done first. This is to avoid a potentially
+costly implicit conversion from ``QPoint`` to ``QPointF`` when using the
+2nd overload. There are cases though in which this is not desired;
+most prominently when a class inherits from a container and overloads exist
+for both types as is the case for the ``QPolygon`` class:
+
+.. code-block:: c++
+
+ class QPolygon : public QList<QPoint> {};
+
+ void QPainter::drawPolygon(QPolygon);
+ void QPainter::drawPolygon(QList<QPoint>);
+
+By default, the overload taking a ``QList`` will be checked first, trying
+to avoid constructing a ``QPolygon`` from ``QList``. The type check for a
+list of points will succeed for a parameter of type ``QPolygon``, too,
+since it inherits ``QList``. This presents a problem since the sequence
+type check is costly due to it checking that each container element is a
+``QPoint``. It is thus preferable to check for the ``QPolygon`` overload
+first. This is achieved by specifying numbers as follows:
+
+.. code-block:: xml
+
+ <object-type name="QPainter">
+ <modify-function signature="drawPolygon(QPolygon)" overload-number="0"/>
+ <modify-function signature="drawPolygon(QList&lt;QPoint&gt;)" overload-number="1"/>
+ </object-type>
+
+Numbers should be given for all overloads; otherwise, the order will be in
+declaration order.
+
+The optional ``final`` attribute can be specified for virtual functions
+and disables generating the code for overriding the function in Python
+(native call). This is useful when the result type is not constructible.
+
+The ``remove`` attribute is an *optional* boolean attribute, which can
+mark the function to be discarded on generation.
+
+The *optional* ``rename`` attribute can be used to change the name of the
+given function in the generated target language API.
+
+The *optional* ``access`` attribute changes the access privileges of the
+given function in the generated target language API.
+
+The *optional* **snake-case** attribute allows for overriding the value
+specified on the class entry or **typesystem** element.
+
+The *optional* **deprecated** attribute allows for overriding deprecation
+as detected by the C++ attribute. It works in both ways.
+
+.. _add-function:
+
+add-function
+^^^^^^^^^^^^
+
+The ``add-function`` node allows you to add a given function onto the target
+language, and it is a child of an :ref:`object-type` or :ref:`value-type` nodes if the
+function is supposed to be a method, or :ref:`namespace` and :ref:`typesystem` if
+the function is supposed to be a function inside a namespace or a global function.
+It may contain :ref:`modify-argument` nodes.
+
+Typically when adding a function some code must be injected to provide the function
+logic. This can be done using the :ref:`inject-code` node.
+
+.. code-block:: xml
+
+ <object-type>
+ <add-function signature="..." return-type="..."
+ access="public | protected"
+ overload-number="number"
+ static="yes | no" classmethod="yes | no"
+ python-override ="yes | no"
+ since="..."/>
+ </object-type>
+
+The ``return-type`` attribute defaults to *void*, the ``access`` to *public* and the ``static`` one to *no*.
+
+The ``since`` attribute specifies the API version when this function was added.
+
+The ``classmethod`` attribute specifies whether the function should be a Python class method.
+It sets the METH_CLASS flag which means that ``PyTypeObject`` instead of an instance
+``PyObject`` is passed as self, which needs to be handled in injected code.
+
+For the *optional* attribute ``overload-number``, see :ref:`modify-function`.
+
+Note that the label "static" in Qt's class documentation almost always means that a Python
+``classmethod`` should be generated, because an object's class is always accessible from the
+static C++ code, while Python needs the explicit "self" parameter that ``classmethod``
+provides.
+
+In order to create keyword argument supporting function parameters, enclose the specific
+function parameter with a *@* in the `signature` field.
+
+.. code-block:: xml
+
+ <add-function signature="foo(int @parameter1@,float @parameter2@)">
+ ...
+ </add-function>
+
+With keyword arguments, ``add-function`` makes it easy to specify a default argument
+within the `signature` field
+
+.. code-block:: xml
+
+ <add-function signature="foo(int @parameter1@=1,float @parameter2@=2)">
+ ...
+ </add-function>
+
+See :ref:`sequence-protocol` for adding the respective functions.
+
+The *optional* attribute ``python-override`` indicates a special type
+of added function, a python-override that will be generated into
+the native wrapper (see :ref:`modifying-virtual-functions`).
+
+.. _declare-function:
+
+declare-function
+^^^^^^^^^^^^^^^^
+
+The ``declare-function`` node allows you to declare a function present in
+the type and it is a child of an :ref:`object-type` or :ref:`value-type` nodes
+if the function is supposed to be a method, or :ref:`namespace` and
+:ref:`typesystem` if the function is supposed to be a function inside a
+namespace or a global function. It may contain :ref:`modify-argument` nodes.
+
+.. code-block:: xml
+
+ <container-type>
+ <declare-function signature="..." return-type="..." since="..."
+ allow-thread="true | auto | false"
+ exception-handling="off | auto-off | auto-on | on"
+ overload-number="number"
+ snake-case="yes | no | both"/>
+ </container-type>
+
+The ``return-type`` attribute defaults to *void*.
+
+The ``since`` attribute specifies the API version when this function was
+added.
+
+For the *optional* attributes ``allow-thread``, ``exception-handling``,
+``overload-number`` and ``snake-case``, see :ref:`modify-function`.
+
+This is useful to make functions known to shiboken which its code parser
+does not detect. For example, in Qt 6, the ``append()`` function of the
+``QList<T>`` container takes an argument of ``parameter_type`` which is
+specialized to ``T`` for simple types and ``const T &`` for complex types
+by some template expression which the code parser cannot resolve.
+In that case, the function can be declared with a simple signature:
+
+.. code-block:: xml
+
+ <container-type name="QList">
+ <declare-function signature="append(T)"/>
+ </container-type>
+
+This tells shiboken a public function of that signature exists and
+bindings will be created in specializations of ``QList``.
+
+
+.. _add-pymethoddef:
+
+add-pymethoddef
+^^^^^^^^^^^^^^^
+
+The ``add-pymethoddef`` element allows you to add a free function to
+the ``PyMethodDef`` array of the type. No argument or result conversion
+is generated, allowing for variadic functions and more flexible
+arguments checking.
+
+.. code-block:: xml
+
+ <add-pymethoddef name="..." function="..." flags="..." doc="..."
+ signatures="..."/>
+
+The ``name`` attribute specifies the name.
+
+The ``function`` attribute specifies the implementation (a static function
+of type ``PyCFunction``).
+
+The ``flags`` attribute specifies the flags (typically ``METH_VARARGS``,
+see `Common Object Structures`_).
+
+The optional ``doc`` attribute specifies the documentation to be set to the
+``ml_doc`` field.
+
+The optional ``signatures`` attribute specifies a semicolon-separated list
+of signatures of the function.
+
+.. _Common Object Structures: https://docs.python.org/3/c-api/structures.html
+
+.. _property-declare:
+
+property
+^^^^^^^^
+
+The ``property`` element allows you to specify properties consisting of
+a type and getter and setter functions.
+
+It may appear as a child of a complex type such as :ref:`object-type` or
+:ref:`value-type`.
+
+If the PySide6 extension is not present, code will be generated using the
+``PyGetSetDef`` struct, similar to what is generated for fields.
+
+If the PySide6 extension is present, those properties complement the
+properties obtained from the ``Q_PROPERTY`` macro in Qt-based code.
+The properties will be handled in ``libpyside`` unless code generation
+is forced.
+
+.. code-block:: xml
+
+ <property name="..." type="..." get="..." set="..."
+ generate-getsetdef="yes | no" since="..."/>
+
+The ``name`` attribute specifies the name of the property, the ``type``
+attribute specifies the C++ type and the ``get`` attribute specifies the
+name of the accessor function.
+
+The optional ``set`` attribute specifies name of the setter function.
+
+The optional ``generate-getsetdef`` attribute specifies whether to generate
+code for if the PySide6 extension is present (indicating this property is not
+handled by libpyside). It defaults to *no*.
+
+The optional ``since`` attribute specifies the API version when this
+property appears.
+
+For a typical C++ class, like:
+
+.. code-block:: c++
+
+ class Test {
+ public:
+ int getValue() const;
+ void setValue();
+ };
+
+``value`` can then be specified to be a property:
+
+.. code-block:: xml
+
+ <value-type name="Test">
+ <property name="value" type="int" get="getValue" set="setValue"/>
+
+With that, a more pythonic style can be used:
+
+.. code-block:: python
+
+ test = Test()
+ test.value = 42
+
+For Qt classes (with the PySide6 extension present), additional setters
+and getters that do not appear as ``Q_PROPERTY``, can be specified to
+be properties:
+
+.. code-block:: xml
+
+ <object-type name="QMainWindow">
+ <property name="centralWidget" type="QWidget *"
+ get="centralWidget" set="setCentralWidget"/>
+
+in addition to the normal properties of ``QMainWindow`` defined for
+Qt Designer usage.
+
+.. note:: In the *Qt* coding style, the property name typically conflicts
+ with the getter name. It is recommended to exclude the getter from the
+ wrapper generation using the ``remove`` function modification.
+
+.. _configuration-element:
+
+configuration
+^^^^^^^^^^^^^
+
+The ``configuration`` element allows you to generate a preprocessor
+condition excluding a type depending on an expression into the module
+header. This is specifically tailored to the
+`Qt Feature system <https://doc.qt.io/qt-6/configure-options.html>`_ ,
+but may also be used for similar systems.
+
+It may appear as a child of a complex type such as :ref:`object-type` or
+:ref:`value-type`.
+
+.. code-block:: xml
+
+ <configuration condition="..."/>
+
+The ``condition`` attribute specifies the preprocessor condition.
+
+This is an alternative way of omitting classes depending on some
+configuration (see also option :ref:`drop-type-entries`) intended
+for building several configurations from one generated source tree,
+but still requires listing the correct source files in the
+``CMakeLists.txt`` file.
+
+.. _modifying-virtual-functions:
+
+Modifying virtual functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Some C++ virtual functions are unsuitable for Python bindings:
+
+.. code-block:: c
+
+ virtual void getInt(int *result) const;
+
+In that case, you would modify it to return the integer instead (or a tuple
+in case of several out-parameters):
+
+.. code-block:: c
+
+ virtual int getInt() const;
+
+For the binding itself, use the common argument modifications (removing
+arguments, modifying return types with injected code snippets) to modify the
+signature.
+
+To make it possible to reimplement the function in Python with the modified
+signature, add a ``python-override`` function with that signature, using an
+arbitrary name for disambiguation:
+
+.. code-block:: xml
+
+ <add-function signature="getIntPyOverride()"
+ return-type="int" python-override="true"/>
+
+This causes a static function performing the call into Python for the override
+to be generated into the native wrapper.
+
+In the existing virtual function, inject a code snippet at the ``shell`` /
+``override`` position which calls the newly added function. The first 2
+arguments are the `Global interpreter lock handle` (``Shiboken::GilState``) and
+the Python method determined by the override check (``PyObject *``). The
+snippet then converts the arguments and return values and returns after that:
+
+.. code-block:: xml
+
+ <modify-function signature="getInt(int*)const">
+ <inject-code class="shell" position="override">
+ *result = getIntPyOverride(gil, pyOverride.object());
+ return;
+ </inject-code>
+ </modify-function>
diff --git a/sources/shiboken6/doc/typesystem_modify_function.rst b/sources/shiboken6/doc/typesystem_modify_function.rst
new file mode 100644
index 000000000..54ac6412f
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_modify_function.rst
@@ -0,0 +1,44 @@
+.. _modifying-functions:
+
+Modifying Functions
+-------------------
+
+.. _modify-argument:
+
+modify-argument
+^^^^^^^^^^^^^^^
+
+Function modifications consist of a list of ``modify-argument`` nodes
+contained in :ref:`modify-function`, :ref:`add-function` or
+:ref:`declare-function` nodes. Use the :ref:`remove-argument`,
+:ref:`replace-default-expression`, :ref:`remove-default-expression`,
+:ref:`replace-type`, :ref:`reference-count` and :ref:`define-ownership`
+nodes to specify the details of the modification.
+
+.. code-block:: xml
+
+ <modify-function>
+ <modify-argument index="return | this | 1 ..." rename="..."
+ invalidate-after-use = "true | false" pyi-type="...">
+ // modifications
+ </modify-argument>
+ </modify-function>
+
+Set the ``index`` attribute to "1" for the first argument, "2" for the second
+one and so on. Alternatively, set it to "return" or "this" if you want to
+modify the function's return value or the object the function is called upon,
+respectively.
+
+The optional ``rename`` attribute is used to rename a argument and use this
+new name in the generated code. This attribute can be used to enable the usage
+of ``keyword arguments``.
+
+The optional ``pyi-type`` attribute specifies the type to appear in the
+signature strings and ``.pyi`` files. The type string is determined by
+checking this attribute value, the :ref:`replace-type` modification and
+the C++ type. The attribute can be used for example to enclose
+a pointer return value within ``Optional[]`` to indicate that ``None``
+can occur.
+
+For the optional ``invalidate-after-use`` attribute,
+see :ref:`invalidationafteruse` .
diff --git a/sources/shiboken6/doc/typesystem_ownership.rst b/sources/shiboken6/doc/typesystem_ownership.rst
new file mode 100644
index 000000000..a5440e49e
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_ownership.rst
@@ -0,0 +1,291 @@
+.. _objectownership:
+
+****************
+Object ownership
+****************
+
+One of the main things a binding developer should have in mind is
+how the C++ instances lives will cope with Python's reference count.
+The last thing you want is to crash a program due to a segfault
+when your C++ instance was deleted and the
+wrapper object tries to access the invalid memory there.
+
+In this section we'll show how |project| deals with object ownership
+and parentship, taking advantage of the information provided by the
+APIExtractor.
+
+Ownership basics
+================
+
+As any python binding, |project|-based bindings uses reference counting
+to handle the life of the wrapper object (the Python object that contains the
+C++ object, do not confuse with the *wrapped* C++ object).
+When a reference count reaches zero, the wrapper is deleted by Python garbage
+collector and tries to delete the wrapped instance, but sometimes the wrapped
+C++ object is already deleted, or maybe the C++ object should not be freed after
+the Python wrapper go out of scope and die, because C++ is already taking care of
+the wrapped instance.
+
+This is not a concern for value types specified by :ref:`value-type`, which can
+be freely created, copied and destroyed, however object types specified by
+:ref:`object-type` pointing to C++ instances with life cycle constraints
+may require attention.
+
+In order to handle this, you should tell the
+generator whether the instance's ownership belongs to the binding or
+to the C++ Library. When belonging to the binding, we are sure that the C++ object
+won't be deleted by C++ code and we can call the C++ destructor when the refcount
+reaches 0. Otherwise, instances owned by C++ code can be destroyed arbitrarily,
+without notifying the Python wrapper of its destruction.
+
+By default, objects created in Python have ownership. A relevant case are
+return values of virtual factory methods reimplemented in Python
+(C++ Wrapper Code) which pass the bindings code. Objects obtained from C++
+(for example, ``QGuiApplication::clipoard()``) do not have ownership.
+
+The :ref:`shiboken-module` module provides the ``dump()`` utility function,
+which prints the relevant information for an object.
+
+Invalidating objects
+====================
+
+To prevent segfaults and double frees, the wrapper objects are invalidated.
+An invalidated can't be passed as argument or have an attribute or method accessed.
+Trying to do this will raise RuntimeError.
+
+The following situations can invalidate an object:
+
+C++ taking ownership
+--------------------
+
+When an object is passed to a function or method that takes ownership of it, the wrapper
+is invalidated as we can't be sure of when the object is destroyed, unless it has a
+:ref:`virtual destructor <ownership-virt-method>` or the transfer is due to the special case
+of :ref:`parent ownership <ownership-parent>`.
+
+Besides being passed as argument, the called object can have its ownership changed, like
+the `setParent` method in Qt's `QObject`.
+
+Invalidate after use
+--------------------
+
+Objects marked with *invalidate-after-use* in the type system description always are
+virtual method arguments provided by a C++ originated call. They should be
+invalidated right after the Python function returns (see :ref:`invalidationafteruse`).
+
+.. _ownership-virt-method:
+
+Objects with virtual methods
+----------------------------
+
+A little bit of implementation details (see also :ref:`codegenerationterminology`):
+virtual methods are supported by creating a C++ class, the **shell**, that inherits
+from the class with virtual methods, the native one, and override those methods to check if
+any derived class in Python also override it.
+
+If the class has a virtual destructor (and C++ classes with virtual methods should have), this
+C++ instance invalidates the wrapper only when the overridden destructor is called.
+
+An instance of the **shell** is created when created in Python. However,
+when the object is created in C++, like in a factory method or a parameter
+to a virtual function like ``QObject::event(QEvent *)``, the wrapped object
+is a C++ instance of the native class, not the **shell** one, and we cannot
+know when it is destroyed.
+
+.. _ownership-parent:
+
+Parent-child relationship
+=========================
+
+One special type of ownership is the parent-child relationship.
+Being a child of an object means that when the object's parent dies,
+the C++ instance also dies, so the Python references will be invalidated.
+Qt's QObject system, for example, implements this behavior, but this is valid
+for any C++ library with similar behavior.
+
+.. _ownership-parent-heuristics:
+
+Parentship heuristics
+---------------------
+
+As the parent-child relationship is very common, |project| tries to automatically
+infer what methods falls into the parent-child scheme, adding the extra
+directives related to ownership.
+
+This heuristic will be triggered when generating code for a method and:
+
+* The function is a constructor.
+* The argument name is `parent`.
+* The argument type is a pointer to an object.
+
+When triggered, the heuristic will set the argument named "parent"
+as the parent of the object being created by the constructor.
+
+The main focus of this process was to remove a lot of hand written code from
+type system when binding Qt libraries. For Qt, this heuristic works in all cases,
+but be aware that it might not when binding your own libraries.
+
+To activate this heuristic, use the :ref:`--enable-parent-ctor-heuristic <parent-heuristic>`
+command line switch.
+
+.. _return-value-heuristics:
+
+Return value heuristics
+-----------------------
+
+When enabled, object returned as pointer in C++ will become child of the object on which the method
+was called.
+
+To activate this heuristic, use the command line switch
+:ref:`--enable-return-value-heuristic <return-heuristic>`.
+
+To disable this heuristic for specific cases, specify ``default`` as
+ownership:
+
+.. code-block:: xml
+
+ <modify-argument index="0">
+ <define-ownership class="target" owner="default" />
+ </modify-argument>
+
+Common pitfalls
+===============
+
+Not saving unowned objects references
+-------------------------------------
+
+Sometimes when you pass an instance as argument to a method and the receiving
+instance will need that object to live indefinitely, but will not take ownership
+of the argument instance. In this case, you should hold a reference to the argument
+instance.
+
+For example, let's say that you have a renderer class that will use a source class
+in a setSource method but will not take ownership of it. The following code is wrong,
+because when `render` is called the `Source` object created during the call to `setSource`
+is already destroyed.
+
+.. code-block:: python
+
+ renderer.setModel(Source())
+ renderer.render()
+
+To solve this, you should hold a reference to the source object, like in
+
+.. code-block:: python
+
+ source = Source()
+ renderer.setSource(source)
+ renderer.render()
+
+
+Ownership Management in the Typesystem
+======================================
+
+Python Wrapper Code
+-------------------
+
+For this code, the ``class`` attribute takes the value ``target``
+(see :ref:`codegenerationterminology`).
+
+Ownership transfer from C++ to target
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When an object currently owned by C++ has its ownership transferred
+back to the target language, the binding can know for sure when the object will be deleted and
+tie the C++ instance existence to the wrapper, calling the C++ destructor normally when the
+wrapper is deleted.
+
+.. code-block:: xml
+
+ <modify-argument index="1">
+ <define-ownership class="target" owner="target" />
+ </modify-argument>
+
+A typical use case would be returning an object allocated in C++, for
+example from ``clone()`` or other factory methods.
+
+Ownership transfer from target to C++
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the opposite direction, when an object ownership is transferred from the target language
+to C++, the native code takes full control of the object life and you don't
+know when that object will be deleted, rendering the wrapper object invalid,
+unless you're wrapping an object with a virtual destructor,
+so you can override it and be notified of its destruction.
+
+By default it's safer to just render the wrapper
+object invalid and raise some error if the user tries to access
+one of this objects members or pass it as argument to some function, to avoid unpleasant segfaults.
+Also you should avoid calling the C++ destructor when deleting the wrapper.
+
+.. code-block:: xml
+
+ <modify-argument index="1">
+ <define-ownership class="target" owner="c++" />
+ </modify-argument>
+
+Use cases would be an returning a member object by pointer
+or passing an object by pointer into a function where the class
+takes ownership, for example
+``QNetworkAccessManager::setCookieJar(QNetworkCookieJar *)``.
+
+Parent-child relationship
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+One special type of relationship is the parent-child. When an object is called
+the parent of another object (the child), the former is in charge of deleting its
+child when deleted and the target language can trust that the child will be alive
+as long as the parent is, unless some other method can take the C++ ownership away from the parent.
+
+One of the main uses of this scheme is Qt's object system, with ownership among QObject-derived
+classes, creating "trees" of instances.
+
+.. code-block:: xml
+
+ <modify-argument index="this">
+ <parent index="1" action="add"/>
+ </modify-argument>
+
+In this example, the instance with the method that is being invoked (indicated by 'index="this"' on
+modify-argument) will be marked as a child
+of the first argument using the `parent` tag. To remove ownership, just use "remove" in the action attribute. **Removing
+parentship also transfers the ownership back to python.**
+
+See `Object Trees and Object Ownership in Qt`_.
+
+.. _`Object Trees and Object Ownership in Qt`: https://doc.qt.io/qt-6/objecttrees.html
+
+C++ Wrapper Code
+----------------
+
+For this code, the ``class`` attribute takes the value ``native``. The
+modifications affect code called from within C++, typically when calling
+virtual C++ methods reimplemented in Python
+(see :ref:`codegenerationterminology`).
+
+Return values of virtual functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ownership of C++ objects returned by pointer should be set to ``c++`` to
+prevent them from being deleted by Python, since objects created
+in Python have ownership by default.
+
+Ownership transfers specified for other arguments do not have any effect.
+
+.. _invalidationafteruse:
+
+Invalidation after use
+^^^^^^^^^^^^^^^^^^^^^^
+
+Sometimes an object is created in C++ and passed as a virtual method call
+argument and destroyed after the call returned
+(see :ref:`ownership-virt-method`).
+In this case, you should use the ``invalidate-after-use`` attribute in the
+:ref:`modify-argument` tag to mark the wrapper as invalid right after the
+virtual method returns.
+
+.. code-block:: xml
+
+ <modify-argument index="2" invalidate-after-use="yes"/>
+
+In this example the second argument will be invalidated after this method call.
diff --git a/sources/shiboken6/doc/typesystem_solving_compilation.rst b/sources/shiboken6/doc/typesystem_solving_compilation.rst
new file mode 100644
index 000000000..705c2cd26
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_solving_compilation.rst
@@ -0,0 +1,80 @@
+Solving compilation problems
+----------------------------
+
+.. _suppress-warning:
+
+suppress-warning
+^^^^^^^^^^^^^^^^
+
+The generator will generate several warnings which may be irrelevant to the
+user. The ``suppress-warning`` node suppresses the specified warning, and it is
+a child of the :ref:`typesystem` node.
+
+.. code-block:: xml
+
+ <typesystem>
+ <suppress-warning text="..." />
+ </typesystem>
+
+The **text** attribute is the warning text to suppress, and may contain the *
+wildcard (use "" to escape regular expression matching if the warning contain
+a regular "*").
+
+.. _extra-includes:
+
+extra-includes
+^^^^^^^^^^^^^^
+
+The ``extra-includes`` node contains declarations of additional include files,
+and it can be a child of the :ref:`namespace`, :ref:`value-type`,
+:ref:`object-type` and :ref:`typesystem` and nodes.
+
+The generator automatically tries to read the global header for each type but
+sometimes it is required to include extra files in the generated C++ code to
+make sure that the code compiles. These files must be listed using include
+nodes within the extra-include node:
+
+.. code-block:: xml
+
+ <value-type>
+ <extra-includes>
+ <include file-name="..." location="global | local"/>
+ </extra-includes>
+ </value-type>
+
+The **file-name** attribute is the file to include, such as "QStringList".
+The **location** attribute is where the file is located: *global* means that
+the file is located in $INCLUDEPATH and will be included using #include <...>,
+*local* means that the file is in a local directory and will be included
+using #include "...".
+
+When specified as a child of the :ref:`typesystem` node, the include
+directives are added to the module source file which contains
+the type converter and registration code. It can be used to specify
+additional includes required for the converter code snippets.
+
+.. _include-element:
+
+include
+^^^^^^^
+
+The ``include`` node specifies the name and location of a file that must be
+included, and it is a child of the :ref:`namespace`, :ref:`value-type`,
+:ref:`object-type` or :ref:`extra-includes` node.
+
+The generator automatically tries to read the global header for each type. Use
+the include node to override this behavior, providing an alternative file. The
+include node can also be used to specify extra include files.
+
+.. code-block:: xml
+
+ <value-type>
+ <include file-name="..."
+ location="global | local"/>
+ </value-type>
+
+The **file-name** attribute is the file to include, such as "QStringList".
+The **location** attribute is where the file is located: *global* means that
+the file is located in $INCLUDEPATH and will be included using #include <...>,
+*local* means that the file is in a local directory and will be included
+using #include "...".
diff --git a/sources/shiboken6/doc/typesystem_specialfunctions.rst b/sources/shiboken6/doc/typesystem_specialfunctions.rst
new file mode 100644
index 000000000..78a6ff489
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_specialfunctions.rst
@@ -0,0 +1,54 @@
+.. _special-functions:
+
+Special functions
+-----------------
+
+.. _sequence-protocol:
+
+Sequence Protocol
+^^^^^^^^^^^^^^^^^
+
+Support for the sequence protocol is achieved adding functions with special
+names, this is done using the :ref:`add-function` tag.
+
+The special function names are:
+
+============= =============================================== ==================== ===================
+Function name Parameters Return type CPython equivalent
+============= =============================================== ==================== ===================
+__len__ PyObject* self Py_ssize_t PySequence_Size
+__getitem__ PyObject* self, Py_ssize_t _i PyObject* PySequence_GetItem
+__setitem__ PyObject* self, Py_ssize_t _i, PyObject* _value int PySequence_SetItem
+__contains__ PyObject* self, PyObject* _value int PySequence_Contains
+__concat__ PyObject* self, PyObject* _other PyObject* PySequence_Concat
+============= =============================================== ==================== ===================
+
+You just need to inform the function name to the :ref:`add-function` tag, without any
+parameter or return type information, when you do it, |project| will create a C
+function with parameters and return type defined by the table above.
+
+The function needs to follow the same semantics of the *CPython equivalent*
+function, the only way to do it is using the
+:ref:`inject-code <codeinjectionsemantics>` tag.
+
+A concrete example how to add sequence protocol support to a class can be found
+on shiboken tests, more precisely in the definition of the Str class in
+``tests/samplebinding/typesystem_sample.xml``.
+
+.. _bool-cast:
+
+Bool Cast
+^^^^^^^^^
+
+Implementing bool casts enables using values which have a concept of validity
+in boolean expressions. In C++, this is commonly implemented as
+``operator bool() const``. In Qt, relevant classes have a
+``bool isNull() const`` function.
+
+In Python, the function ``__bool__`` is used for this. shiboken can generate
+this functions depending on the command line options
+:ref:`--use-operator-bool-as-nb-bool <use-operator-bool-as-nb-bool>`
+and :ref:`--use-isnull-as-nb-bool <use-isnull-as-nb-bool>`,
+which can be overridden by specifying the boolean attributes
+**isNull** or **operator-bool** on the :ref:`value-type` or :ref:`object-type`
+elements in typesystem XML.
diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst
new file mode 100644
index 000000000..e979c4ee2
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_specifying_types.rst
@@ -0,0 +1,890 @@
+Specifying Types
+----------------
+
+Including Snippets
+^^^^^^^^^^^^^^^^^^
+
+There might be repetitive XML code, for example function modifications that
+need to be done on classes that are not related by type inheritance.
+It is possible to split out such snippets and include them via an entity reference.
+
+.. code-block:: xml
+
+ <typesystem>
+ <object-type name="A">
+ &common_function_modifications;
+ </object-type>
+ <object-type name="B">
+ &common_function_modifications;
+ </object-type>
+ </typesystem>
+
+The entity name is interpreted as file name (with suffix **xml**) appended and resolved
+in the type system paths passed as command line argument.
+
+Note that this is not a standard externally parsed entity due to the limitations
+of the underlying parser.
+
+.. _typesystem:
+
+typesystem
+^^^^^^^^^^
+
+This is the root node containing all the type system information.
+It may contain :ref:`add-function`, :ref:`container-type`,
+:ref:`custom-type`, :ref:`enum-type`, :ref:`extra-includes`, :ref:`function`,
+:ref:`load-typesystem`, :ref:`namespace`, :ref:`object-type`,
+:ref:`opaque-container`,
+:ref:`primitive-type`, :ref:`rejection`, :ref:`smart-pointer-type`,
+:ref:`suppress-warning`, :ref:`template`, :ref:`system_include`,
+:ref:`typedef-type` or :ref:`value-type` child nodes.
+
+It can have a number of attributes, described below.
+
+.. code-block:: xml
+
+ <typesystem package="..."
+ submodule-of="..."
+ allow-thread="..."
+ exception-handling="..."
+ snake-case="yes | no | both"
+ namespace-begin="..."
+ namespace-end="..." >
+ </typesystem>
+
+The **package** attribute is a string describing the package to be used,
+e.g. "QtCore".
+
+The *optional* **submodule-of** attribute specifies the name of a module to
+which the module is added as a sub-module. This requires adapting the
+installation directory of the module accordingly.
+
+The *optional* attributes **allow-thread** and **exception-handling**
+specify the default handling for the corresponding function modification
+(see :ref:`modify-function`).
+
+The *optional* **snake-case** attribute specifies whether function
+and field names will be automatically changed to the snake case
+style that is common in Python (for example, ``snakeCase`` will be
+changed to ``snake_case``).
+
+The value ``both`` means that the function or field will be exposed
+under both its original name and the snake case version. There are
+limitations to this though:
+
+- When overriding a virtual function of a C++ class in Python,
+ the snake case name must be used.
+
+- When static and non-static overloads of a class member function
+ exist (as is the case for example for ``QFileInfo::exists()``),
+ the snake case name must be used.
+
+The *optional* **namespace-begin** and **namespace-end** attributes will be
+generated around the forward declarations in the module header. This is
+intended for libraries which can optionally use inline namespaces
+to allow for linking several versions of them together.
+For example, for *Qt*, one would specify ``QT_BEGIN_NAMESPACE``,
+``QT_END_NAMESPACE``, respectively.
+
+.. _load-typesystem:
+
+load-typesystem
+^^^^^^^^^^^^^^^
+
+The ``load-typesystem`` node specifies which type systems to load when mapping
+multiple libraries to another language or basing one library on another, and
+it is a child of the :ref:`typesystem` node.
+
+.. code-block:: xml
+
+ <typesystem>
+ <load-typesystem name="..." generate="yes | no" />
+ </typesystem>
+
+The **name** attribute is the filename of the typesystem to load, the
+**generate** attribute specifies whether code should be generated or not. The
+later must be specified when basing one library on another, making the generator
+able to understand inheritance hierarchies, primitive mapping, parameter types
+in functions, etc.
+
+Most libraries will be based on both the QtCore and QtGui modules, in which
+case code generation for these libraries will be disabled.
+
+.. _rejection:
+
+rejection
+^^^^^^^^^
+
+The ``rejection`` node rejects the given class, or the specified function
+or field, and it is a child of the :ref:`typesystem` node.
+
+.. code-block:: xml
+
+ <typesystem>
+ <rejection class="..."
+ function-name="..."
+ argument-type="..."
+ field-name="..." />
+ </typesystem>
+
+The **class** attribute is the C++ class name of the class to reject. Use
+the *optional* **function-name**, **argument-type**, or **field-name**
+attributes to reject a particular function, function with arguments of a
+particular type, or a field. Note that the **field-name** and
+**function-name**/**argument-type** cannot be specified at the same time.
+To remove all occurrences of a given field or function, set the class
+attribute to \*.
+
+.. _primitive-type:
+
+primitive-type
+^^^^^^^^^^^^^^
+
+The ``primitive-type`` node describes how a primitive type is mapped from C++ to
+the target language, and is a child of the :ref:`typesystem` node. It may
+contain :ref:`conversion-rule` child nodes. Note that most primitives are
+already specified in the QtCore typesystem (see :ref:`primitive-cpp-types`).
+
+.. code-block:: xml
+
+ <typesystem>
+ <primitive-type name="..."
+ since="..."
+ until="..."
+ target-lang-api-name="..."
+ default-constructor="..."
+ preferred-conversion="yes | no"
+ view-on="..." />
+ </typesystem>
+
+The **name** attribute is the name of the primitive in C++.
+
+The optional **target-lang-api-name** attribute is the name of the
+primitive type in the target language, defaulting to the **name** attribute.
+
+The *optional* **since** value is used to specify the API version in which
+the type was introduced.
+
+Similarly, the *optional* **until** value can be used to specify the API
+version in which the type will be obsoleted.
+
+If the *optional* **preferred-conversion** attribute is set to *no*, it
+indicates that this version of the primitive type is not the preferred C++
+equivalent of the target language type. For example, in Python both "qint64"
+and "long long" become "long" but we should prefer the "qint64" version. For
+this reason we mark "long long" with preferred-conversion="no".
+
+The *optional* **default-constructor** specifies the minimal constructor
+call to build one value of the primitive-type. This is not needed when the
+primitive-type may be built with a default constructor (the one without
+arguments).
+
+The *optional* **preferred-conversion** attribute tells how to build a default
+instance of the primitive type. It should be a constructor call capable of
+creating a instance of the primitive type. Example: a class "Foo" could have
+a **preferred-conversion** value set to "Foo()". Usually this attribute is
+used only for classes declared as primitive types and not for primitive C++
+types, but that depends on the application using *ApiExtractor*.
+
+The *optional* **view-on** attribute specifies that the type is a view
+class like std::string_view or QStringView which has a constructor
+accepting another type like std::string or QString. Since typically
+no values can be assigned to view classes, no target-to-native conversion
+can be generated for them. Instead, an instance of the viewed class should
+be instantiated and passed to functions using the view class
+for argument types.
+
+See :ref:`predefined_templates` for built-in templates for standard type
+conversion rules.
+
+.. _namespace:
+
+namespace-type
+^^^^^^^^^^^^^^
+
+The ``namespace-type`` node maps the given C++ namespace to the target
+language, and it is a child of the :ref:`typesystem` node or other
+``namespace-type`` nodes. It may contain :ref:`add-function`,
+:ref:`declare-function`, :ref:`enum-type`, :ref:`extra-includes`,
+:ref:`include-element`, :ref:`modify-function`, ``namespace-type``,
+:ref:`object-type`, :ref:`smart-pointer-type`, :ref:`typedef-type` or :ref:`value-type`
+child nodes.
+
+.. code-block:: xml
+
+ <typesystem>
+ <namespace-type name="..."
+ visible="true | auto | false"
+ generate="yes | no"
+ generate-using="yes | no"
+ package="..."
+ since="..."
+ extends = "..."
+ files = "..."
+ revision="..." />
+ </typesystem>
+
+The **name** attribute is the name of the namespace, e.g., "Qt".
+
+The *optional* **visible** attribute is used specify whether the
+namespace is visible in the target language name. Its default value is
+**auto**. It means that normal namespaces are visible, but inline namespaces
+(as introduced in C++ 11) will not be visible.
+
+The detection of inline namespaces requires shiboken to be built
+using LLVM 9.0.
+
+The *optional* **generate** is a legacy attribute. Specifying
+**no** is equivalent to **visible="false"**.
+
+The *optional* **generate-using** attribute specifies whether
+``using namespace`` is generated into the wrapper code for classes within
+the namespace (default: **yes**). This ensures for example that not fully
+qualified enumeration values of default argument values compile.
+However, in rare cases, it might cause ambiguities and can then be turned
+off.
+
+The **package** attribute can be used to override the package of the type system.
+
+The *optional* **since** value is used to specify the API version of this type.
+
+The **revision** attribute can be used to specify a revision for each type, easing the
+production of ABI compatible bindings.
+
+The *optional* **extends** attribute specifies the module name where the given
+namespace first occurs in case of a namespace spanning several modules. For
+example, in Qt, the namespace ``Qt`` first occurs in the ``QtCore`` module and
+is further populated in the ``QtGui`` module. ``QtGui.Qt`` will then be
+generated extending ``QtCore.Qt`` if **extends** is specified.
+
+The *optional* **file** attribute specifies a regular expression matching the
+include files whose contents are to be associated with the current module in
+case of a namespace spanning several modules.
+
+.. _enum-type:
+
+enum-type
+^^^^^^^^^
+
+The ``enum-type`` node maps the given enum from C++ to the target language,
+and it is a child of the :ref:`typesystem` node. Use
+:ref:`reject-enum-value` child nodes to reject values.
+
+.. code-block:: xml
+
+ <typesystem>
+ <enum-type name="..."
+ identified-by-value="..."
+ class="yes | no"
+ since="..."
+ flags="yes | no"
+ flags-revision="..."
+ cpp-type = "..."
+ doc-file = "..."
+ python-type = "IntEnum | IntFlag"
+ lower-bound="..."
+ upper-bound="..."
+ force-integer="yes | no"
+ extensible="yes | no"
+ revision="..." />
+ </typesystem>
+
+The **name** attribute is the fully qualified C++ name of the enum
+(e.g.,"Qt::FillRule"). If the *optional* **flags** attribute is set to *yes*
+(the default is *no*), the generator will expect an existing QFlags<T> for the
+given enum type. The **lower-bound** and **upper-bound** attributes are used
+to specify runtime bounds checking for the enum value. The value must be a
+compilable target language statement, such as "QGradient.Spread.PadSpread"
+(taking again Python as an example). If the **force-integer** attribute is
+set to *yes* (the default is *no*), the generated target language code will
+use the target language integers instead of enums. And finally, the
+**extensible** attribute specifies whether the given enum can be extended
+with user values (the default is *no*).
+
+The *optional* **since** value is used to specify the API version of this type.
+
+The attribute **identified-by-value** helps to specify anonymous enums using the
+name of one of their values, which is unique for the anonymous enum scope.
+Notice that the **enum-type** tag can either have **name** or **identified-by-value**
+but not both.
+
+The *optional* **python-type** attribute specifies the underlying
+Python type.
+
+The *optional* **cpp-type** attribute specifies a C++ to be used for
+casting values. This can be useful for large values triggering MSVC
+signedness issues.
+
+The *optional* **doc-file** attribute specifies the base name of the C++ or
+``.qdoc`` file indicated by ``\relates`` or ``\headerfile`` in ``qdoc``, to
+which the documentation of the enumeration is to be added and displayed in the
+case its a global enumeration. This attribute is for ``qdoc`` only.
+
+The **revision** attribute can be used to specify a revision for each type, easing the
+production of ABI compatible bindings.
+
+The **flags-revision** attribute has the same purposes of **revision** attribute but
+is used for the QFlag related to this enum.
+
+.. _reject-enum-value:
+
+reject-enum-value
+^^^^^^^^^^^^^^^^^
+
+The ``reject-enum-value`` node rejects the enum value specified by the
+**name** attribute, and it is a child of the :ref:`enum-type` node.
+
+.. code-block:: xml
+
+ <enum-type>
+ <reject-enum-value name="..."/>
+ </enum-type>
+
+This node is used when a C++ enum implementation has several identical numeric
+values, some of which are typically obsolete.
+
+.. _value-type:
+
+value-type
+^^^^^^^^^^
+
+The ``value-type`` node indicates that the given C++ type is mapped onto the target
+language as a value type. This means that it is an object passed by value on C++,
+i.e. it is stored in the function call stack. It is a child of the :ref:`typesystem`
+node or other type nodes and may contain :ref:`add-function`, :ref:`add-pymethoddef`,
+:ref:`configuration-element`, :ref:`declare-function`, :ref:`conversion-rule`,
+:ref:`enum-type`, :ref:`extra-includes`, :ref:`include-element`, :ref:`modify-function`,
+:ref:`object-type`, :ref:`smart-pointer-type`, :ref:`typedef-type` or further
+``value-type`` child nodes.
+
+.. code-block:: xml
+
+ <typesystem>
+ <value-type name="..." since="..."
+ copyable="yes | no"
+ allow-thread="..."
+ disable-wrapper="yes | no"
+ exception-handling="..."
+ generate-functions="..."
+ isNull ="yes | no"
+ operator-bool="yes | no"
+ hash-function="..."
+ private="yes | no"
+ qt-register-metatype = "yes | no | base"
+ stream="yes | no"
+ default-constructor="..."
+ revision="..."
+ snake-case="yes | no | both" />
+ </typesystem>
+
+The **name** attribute is the fully qualified C++ class name, such as
+"QMatrix" or "QPainterPath::Element". The **copyable** attribute is used to
+force or not specify if this type is copyable. The *optional* **hash-function**
+attribute informs the function name of a hash function for the type.
+
+The *optional* attribute **stream** specifies whether this type will be able to
+use externally defined operators, like QDataStream << and >>. If equals to **yes**,
+these operators will be called as normal methods within the current class.
+
+The *optional* **since** value is used to specify the API version of this type.
+
+The *optional* **default-constructor** specifies the minimal constructor
+call to build one instance of the value-type. This is not needed when the
+value-type may be built with a default constructor (the one without arguments).
+Usually a code generator may guess a minimal constructor for a value-type based
+on its constructor signatures, thus **default-constructor** is used only in
+very odd cases.
+
+For the *optional* **disable-wrapper** and **generate-functions**
+attributes, see :ref:`object-type`.
+
+For the *optional* **private** attribute, see :ref:`private_types`.
+
+The *optional* **qt-register-metatype** attribute determines whether
+a Qt meta type registration is generated for ``name``. By
+default, this is generated for non-abstract, default-constructible
+types for usage in signals and slots.
+The value ``base`` means that the registration will be generated for the
+class in question but not for inheriting classes. This allows for
+restricting the registration to base classes of type hierarchies.
+
+The **revision** attribute can be used to specify a revision for each type, easing the
+production of ABI compatible bindings.
+
+The *optional* attributes **allow-thread** and **exception-handling**
+specify the default handling for the corresponding function modification
+(see :ref:`modify-function`).
+
+The *optional* **snake-case** attribute allows for overriding the value
+specified on the **typesystem** element.
+
+The *optional* **isNull** and **operator-bool** attributes can be used
+to override the command line setting for generating bool casts
+(see :ref:`bool-cast`).
+
+.. _object-type:
+
+object-type
+^^^^^^^^^^^
+
+The object-type node indicates that the given C++ type is mapped onto the target
+language as an object type. This means that it is an object passed by pointer on
+C++ and it is stored on the heap. It is a child of the :ref:`typesystem` node
+or other type nodes and may contain :ref:`add-function`, :ref:`add-pymethoddef`,
+:ref:`configuration-element`, :ref:`declare-function`, :ref:`enum-type`,
+:ref:`extra-includes`, :ref:`include-element`, :ref:`modify-function`,
+``object-type``, :ref:`smart-pointer-type`, :ref:`typedef-type` or
+:ref:`value-type` child nodes.
+
+.. code-block:: xml
+
+ <typesystem>
+ <object-type name="..."
+ since="..."
+ copyable="yes | no"
+ allow-thread="..."
+ disable-wrapper="yes | no"
+ exception-handling="..."
+ generate-functions="..."
+ force-abstract="yes | no"
+ hash-function="..."
+ isNull ="yes | no"
+ operator-bool="yes | no"
+ parent-management="yes | no"
+ polymorphic-id-expression="..."
+ polymorphic-name-function="..."
+ polymorphic-base="yes | no"
+ private="yes | no"
+ qt-metaobject="yes | no"
+ qt-register-metatype = "yes | no | base"
+ stream="yes | no"
+ revision="..."
+ snake-case="yes | no | both" />
+ </typesystem>
+
+The **name** attribute is the fully qualified C++ class name. If there is no
+C++ base class, the default-superclass attribute can be used to specify a
+superclass for the given type, in the generated target language API. The
+**copyable** and **hash-function** attributes are the same as described for
+:ref:`value-type`.
+
+The *optional* **force-abstract** attribute forces the class to be
+abstract, disabling its instantiation. The generator will normally detect
+this automatically unless the class inherits from an abstract base class
+that is not in the type system.
+
+The *optional* **disable-wrapper** attribute disables the generation of a
+**C++ Wrapper** (see :ref:`codegenerationterminology`). This will
+effectively disable overriding virtuals methods in Python for the class.
+It can be used when the class cannot be instantiated from Python and
+its virtual methods pose some problem for the code generator (by returning
+references, or using a default value that cannot be generated for a
+parameter, or similar).
+
+For the *optional* **private** attribute, see :ref:`private_types`.
+
+The *optional* **qt-metaobject** attribute specifies whether
+the special Qt virtual functions ``metaObject()``,
+``metaCall()``, and ``metaCast()`` are generated. For classes
+using dynamic meta objects, for example, ``QDBusInterface``,
+it can be turned off.
+
+The *optional* **qt-register-metatype** attribute determines whether
+a Qt meta type registration is generated for ``name *``. By
+default, this is only generated for non-QObject types for usage
+in signals and slots.
+The value ``base`` means that the registration will be generated for the
+class in question but not for inheriting classes. This allows for
+restricting the registration to base classes of type hierarchies.
+
+The *optional* attribute **stream** specifies whether this type will be able to
+use externally defined operators, like QDataStream << and >>. If equals to **yes**,
+these operators will be called as normal methods within the current class.
+
+The *optional* **since** value is used to specify the API version of this type.
+
+The **revision** attribute can be used to specify a revision for each type, easing the
+production of ABI compatible bindings.
+
+The *optional* attributes **allow-thread** and **exception-handling**
+specify the default handling for the corresponding function modification
+(see :ref:`modify-function`).
+
+The *optional* **generate-functions** specifies a semicolon-separated
+list of function names or minimal signatures to be generated.
+This allows for restricting the functions for which bindings are generated.
+This also applies to virtual functions; so, all abstract functions
+need to be listed to prevent non-compiling code to be generated.
+If nothing is specified, bindings for all suitable functions are
+generated. Note that special functions (constructors, etc),
+cannot be specified.
+
+The *optional* **snake-case** attribute allows for overriding the value
+specified on the **typesystem** element.
+
+The *optional* **isNull** and **operator-bool** attributes can be used
+to override the command line setting for generating bool casts
+(see :ref:`bool-cast`).
+
+The *optional* **parent-management** attribute specifies that the class is
+used for building object trees consisting of parents and children, for
+example, user interfaces like the ``QWidget`` classes. For those classes,
+the heuristics enabled by :ref:`ownership-parent-heuristics` and
+:ref:`return-value-heuristics` are applied to automatically set parent
+relationships. Compatibility note: In shiboken 6, when no class of the
+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.
+
+For the *optional* **polymorphic-id-expression**, **polymorphic-name-function**
+and **polymorphic-base** attributes, see :ref:`typediscovery-attributes`.
+
+interface-type
+^^^^^^^^^^^^^^
+
+This type is deprecated and no longer has any effect. Use object-type instead.
+
+.. _container-type:
+
+container-type
+^^^^^^^^^^^^^^
+
+The ``container-type`` node indicates that the given class is a container and
+must be handled using one of the conversion helpers provided by attribute **type**.
+It is a child of the :ref:`typesystem` node and may contain
+:ref:`conversion-rule` child nodes.
+
+.. code-block:: xml
+
+ <typesystem>
+ <container-type name="..."
+ since="..."
+ type ="..."
+ opaque-containers ="..." />
+ </typesystem>
+
+The **name** attribute is the fully qualified C++ class name. The **type**
+attribute is used to indicate what conversion rule will be applied to the
+container. It can be one of: *list*, *set*, *map*, *multi-map* or *pair*.
+
+Some types were deprecated in 6.2: *string-list*, *linked-list*, *vector*,
+*stack* and *queue* are equivalent to *list*. *hash* and *multi-hash*
+are equivalent to *map* and *multi-map*, respectively.
+
+The *optional* **opaque-containers** attribute specifies a semi-colon separated
+list of mappings from instantiations to a type name for
+:ref:`opaque-containers`:
+
+.. code-block:: xml
+
+ <typesystem>
+ <container-type name="std::array"
+ opaque-containers ="int,3:IntArray3;float,4:FloatArray4">
+
+
+The *optional* **since** value is used to specify the API version of this container.
+
+Some common standard containers are :ref:`built-in <builtin-cpp-container-types>`,
+and there are also a number of useful
+:ref:`predefined conversion templates <predefined_templates>`.
+
+.. _opaque-container:
+
+opaque-container
+^^^^^^^^^^^^^^^^
+
+The ``opaque-container`` element can be used to add further instantiations
+of :ref:`opaque containers <opaque-containers>` to existing container types
+(built-in or specified by :ref:`container-type` in included modules).
+It is a child of the :ref:`typesystem` node.
+
+.. code-block:: xml
+
+ <typesystem>
+ <oqaque-container name="..." opaque-containers ="..." />
+ </typesystem>
+
+For the **name** and **opaque-containers** attributes,
+see :ref:`container-type`.
+
+.. _typedef-type:
+
+typedef-type
+^^^^^^^^^^^^
+
+The ``typedef-type`` node allows for specifying typedefs in the typesystem. They
+are mostly equivalent to spelling out the typedef in the included header, which
+is often complicated when trying to wrap libraries whose source code cannot be
+easily extended.
+It is a child of the :ref:`typesystem` node or other type nodes.
+
+.. code-block:: xml
+
+ <typesystem>
+ <typedef-type name="..."
+ source="..."
+ since="..." />
+ </typesystem>
+
+The **source** attribute is the source. Example:
+
+.. code-block:: xml
+
+ <namespace-type name='std'>
+ <value-type name='optional' generate='no'/>\n"
+ </namespace-type>
+ <typedef-type name="IntOptional" source="std::optional&lt;int&gt;"/>
+
+is equivalent to
+
+.. code-block:: c++
+
+ typedef std::optional<int> IntOptional;
+
+The *optional* **since** value is used to specify the API version of this type.
+
+.. _custom-type:
+
+custom-type
+^^^^^^^^^^^
+
+The ``custom-type`` node simply makes the parser aware of the existence of a target
+language type, thus avoiding errors when trying to find a type used in function
+signatures and other places. The proper handling of the custom type is meant to
+be done by a generator using the APIExractor.
+It is a child of the :ref:`typesystem` node.
+
+.. code-block:: xml
+
+ <typesystem>
+ <custom-type name="..."
+ check-function="..." />
+ </typesystem>
+
+The **name** attribute is the name of the custom type, e.g., "PyObject".
+
+The *optional* **check-function** attribute can be used to specify a
+boolean check function that verifies if the PyObject is of the given type
+in the function overload decisor. While shiboken knows common check
+functions like ``PyLong_Check()`` or ``PyType_Check()``, it might be useful
+to provide one for function arguments modified to be custom types
+handled by injected code (see :ref:`replace-type`).
+
+See :ref:`cpython-types` for built-in types.
+
+.. _smart-pointer-type:
+
+smart-pointer-type
+^^^^^^^^^^^^^^^^^^
+
+The ``smart pointer`` type node indicates that the given class is a smart pointer
+and requires inserting calls to **getter** to access the pointeee.
+Currently, the usage is limited to function return values.
+**ref-count-method** specifies the name of the method used to do reference counting.
+It is a child of the :ref:`typesystem` node or other type nodes.
+
+The *optional* attribute **instantiations** specifies for which instantiations
+of the smart pointer wrappers will be generated (comma-separated list).
+By default, this will happen for all instantiations found by code parsing.
+This might be a problem when linking different modules, since wrappers for the
+same instantiation might be generated into different modules, which then clash.
+Providing an instantiations list makes it possible to specify which wrappers
+will be generated into specific modules.
+
+.. code-block:: xml
+
+ <typesystem>
+ <smart-pointer-type name="..."
+ since="..."
+ type="shared | handle | value-handle | unique"
+ getter="..."
+ ref-count-method="..."
+ value-check-method="..."
+ null-check-method="..."
+ reset-method="..."
+ instantiations="..."/>
+ </typesystem>
+
+
+The *optional* attribute **value-check-method** specifies a method
+that can be used to check whether the pointer has a value.
+
+The *optional* attribute **null-check-method** specifies a method
+that can be used to check for ``nullptr``.
+
+The *optional* attribute **reset-method** specifies a method
+that can be used to clear the pointer.
+
+The *optional* instantiations attribute specifies a comma-separated
+list of instantiation types. When left empty, all instantiations
+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:
+
+*shared*
+ A standard shared pointer.
+*handle*
+ A basic pointer handle which has a getter function and an
+ ``operator->``.
+*value-handle*
+ A handle which has a getter function returning a value
+ (``T`` instead of ``T *`` as for the other types).
+ It can be used for ``std::optional``.
+*unique*
+ A standard, unique pointer (``std::unique_ptr``) or a similar
+ movable pointer.
+ Specifying the ``reset-method`` attribute is required for this work.
+
+The example below shows an entry for a ``std::shared_ptr``:
+
+.. code-block:: xml
+
+ <system-include file-name="memory"/>
+
+ <namespace-type name="std">
+ <include file-name="memory" location="global"/>
+ <modify-function signature="^.*$" remove="all"/>
+ <enum-type name="pointer_safety"/>
+ <smart-pointer-type name="shared_ptr" type="shared" getter="get"
+ ref-count-method="use_count"
+ instantiations="Integer">
+ <include file-name="memory" location="global"/>
+ </smart-pointer-type>
+ </namespace-type>
+
+If the smart pointer is the only relevant class from namespace ``std``,
+it can also be hidden:
+
+.. code-block:: xml
+
+ <namespace-type name="std" visible="no">
+ <smart-pointer-type name="shared_ptr" type="shared" getter="get"
+ ref-count-method="use_count"
+ instantiations="Integer">
+ <include file-name="memory" location="global"/>
+ </smart-pointer-type>
+ </namespace-type>
+
+First, shiboken is told to actually parse the system include files
+containing the class definition using the :ref:`system_include`
+element. For the ``namespace-type`` and ``smart-pointer-type``, the
+standard include files are given to override the internal implementation
+header ``shared_ptr.h``.
+This creates some wrapper sources which need to be added to the
+``CMakeLists.txt`` of the module.
+
+.. _function:
+
+function
+^^^^^^^^
+
+The ``function`` node indicates that the given C++ global function is mapped
+onto the target language. It is a child of the :ref:`typesystem` node
+and may contain a :ref:`modify-function` child node.
+
+.. code-block:: xml
+
+ <typesystem>
+ <function signature="..." rename="..." since="..."
+ allow-thread="true | auto | false"
+ doc-file = "..."
+ exception-handling="off | auto-off | auto-on | on"
+ overload-number="number"
+ snake-case="yes | no | both" />
+ </typesystem>
+
+There is a limitation; you cannot add a function overload using
+the :ref:`add-function` tag to an existent function.
+
+The *optional* **since** attribute is used to specify the API version in which
+the function was introduced.
+
+The *optional* **rename** attribute is used to modify the function name.
+
+The *optional* **doc-file** attribute specifies the base name of the C++ or
+``.qdoc`` file indicated by ``\relates`` or ``\headerfile`` in ``qdoc``, to
+which the documentation of the function is to be added and displayed in the
+case its a global function. This attribute is for ``qdoc`` only.
+
+For the *optional* attributes **allow-thread**, **exception-handling**,
+**overload-number** and **snake-case**, see :ref:`modify-function`.
+
+.. _system_include:
+
+system-include
+^^^^^^^^^^^^^^
+
+The optional **system-include** specifies the name of a system include
+file or a system include path (indicated by a trailing slash) to be
+parsed. Normally, include files considered to be system include
+files are skipped by the C++ code parser. Its primary use case
+is exposing classes from the STL library.
+It is a child of the :ref:`typesystem` node.
+
+.. code-block:: xml
+
+ <typesystem>
+ <system-include file-name="memory"/>
+ <system-include file-name="/usr/include/Qt/"/>
+ </typesystem>
+
+.. _conditional_processing:
+
+Conditional Processing
+^^^^^^^^^^^^^^^^^^^^^^
+
+Simple processing instructions are provided for including or excluding
+sections depending on the presence of keywords. The syntax is:
+
+.. code-block:: xml
+
+ <?if keyword !excluded_keyword ?>
+ ...
+ <?endif?>
+
+There are predefined keywords indicating the operating system (``windows``,
+``unix`` and ``darwin``).
+
+The language level passed to the ``language-level`` command line option
+is reflected as ``c++11``, ``c++14``, ``c++17`` or ``c++20``.
+
+The class names passed to the
+:ref:`--drop-type-entries <drop-type-entries>` command line option
+are also predefined, prefixed by ``no_``. This allows for example
+for enclosing added functions referring to those classes within
+``<?if !no_ClassName?>``, ``<?endif?>``.
+
+Other keywords can be specified using the
+:ref:`--keywords <conditional_keywords>` command line option.
+
+.. _private_types:
+
+Defining Entities
+^^^^^^^^^^^^^^^^^
+
+It is possible to define entities using a simple processing instruction:
+
+.. code-block:: xml
+
+ <?entity name value?>
+ <text>&name;</text>
+
+This allows for defining function signatures depending on platform
+in conjunction with :ref:`conditional_processing`.
+
+Private Types
+^^^^^^^^^^^^^
+
+Marking :ref:`object-type` or :ref:`value-type` entries as private causes a
+separate, private module header besides the public module header to be
+generated for them.
+
+This can be used for classes that are not referenced in dependent modules
+and helps to prevent the propagation of for example private C++ headers
+required for them.
diff --git a/sources/shiboken6/doc/typesystem_templates.rst b/sources/shiboken6/doc/typesystem_templates.rst
new file mode 100644
index 000000000..c32eb97d1
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_templates.rst
@@ -0,0 +1,133 @@
+.. _using-code-templates:
+
+Using Code Templates
+--------------------
+
+.. _template:
+
+template
+^^^^^^^^
+
+The ``template`` node registers a template that can be used to avoid
+duplicate code when extending the generated code, and it is a child of the
+:ref:`typesystem` node.
+
+.. code-block:: xml
+
+ <typesystem>
+ <template name="my_template">
+ // the code
+ </template>
+ </typesystem>
+
+Use the ``insert-template`` node to insert the template code (identified
+by the template's ``name`` attribute) into the generated code base.
+
+.. _insert-template:
+
+insert-template
+^^^^^^^^^^^^^^^
+
+The ``insert-template`` node includes the code template identified by the
+name attribute, and it can be a child of the :ref:`inject-code`,
+:ref:`conversion-rule` or :ref:`template` nodes.
+
+.. code-block:: xml
+
+ <inject-code class="target" position="beginning">
+ <insert-template name="my_template" />
+ </inject-code>
+
+Use the ``replace`` node to modify the template code.
+
+replace
+^^^^^^^
+
+The ``replace`` node allows you to modify template code before inserting it into
+the generated code, and it can be a child of the :ref:`insert-template` node.
+
+.. code-block:: xml
+
+ <insert-template name="my_template">
+ <replace from="..." to="..." />
+ </insert-template>
+
+This node will replace the attribute ``from`` with the value pointed by
+``to``.
+
+.. _predefined_templates:
+
+Predefined Templates
+--------------------
+
+There are a number of XML templates for conversion rules for STL and Qt types
+built into shiboken.
+
+Templates for :ref:`primitive-type`:
+
++---------------------------------------+--------------------------------+
+|Name | Description |
++---------------------------------------+--------------------------------+
+| ``shiboken_conversion_pylong_to_cpp`` | Convert a PyLong to a C++ type |
++---------------------------------------+--------------------------------+
+
+Templates for :ref:`container-type`:
+
+Some container types are :ref:`built-in <builtin-cpp-container-types>`.
+In case they need to explicitly specified, the following templates can be used:
+
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_pysequence_to_cpppair`` | Convert a PySequence to a C++ pair (std::pair/QPair) |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_cpppair_to_pytuple`` | Convert a C++ pair (std::pair/QPair) to a PyTuple |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_cppsequence_to_pylist`` | Convert a C++ sequential container to a PyList |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_cppsequence_to_pyset`` | Convert a C++ sequential container to a PySet |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_pyiterable_to_cppsequentialcontainer`` | Convert an iterable Python type to a C++ sequential container (STL/Qt) |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve`` | Convert an iterable Python type to a C++ sequential container supporting reserve() |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_pyiterable_to_cpparray`` | Convert an iterable Python type to a fixed-size array (std::array, std::span) |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_pyiterable_to_cppsetcontainer`` | Convert a PySequence to a set-type C++ container (std::set/QSet) |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_stdmap_to_pydict`` | Convert a std::map/std::unordered_map to a PyDict |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_qmap_to_pydict`` | Convert a QMap/QHash to a PyDict |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_pydict_to_stdmap`` | Convert a PyDict to a std::map/std::unordered_map |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_pydict_to_qmap`` | Convert a PyDict to a QMap/QHash |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_stdmultimap_to_pydict`` | Convert a std::multimap to a PyDict of value lists |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_qmultimap_to_pydict`` | Convert a QMultiMap to a PyDict of value lists |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_stdunorderedmultimap_to_pydict`` | Convert a std::unordered_multimap to a PyDict of value lists |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_qmultihash_to_pydict`` | Convert a QMultiHash to a PyDict of value lists |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_pydict_to_stdmultimap`` | Convert a PyDict of value lists to std::multimap/std::unordered_multimap |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+| ``shiboken_conversion_pydict_to_qmultihash`` | Convert a PyDict of value lists to QMultiMap/QMultiHash |
++----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+
+An entry for the type ``std::list`` using these templates looks like:
+
+.. code-block:: xml
+
+ <container-type name="std::list" type="list">
+ <include file-name="list" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist"/>
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer"/>
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </container-type>
diff --git a/sources/shiboken6/doc/typesystem_variables.rst b/sources/shiboken6/doc/typesystem_variables.rst
new file mode 100644
index 000000000..d40891b9b
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_variables.rst
@@ -0,0 +1,339 @@
+.. _typesystemvariables:
+
+*********************
+Type System Variables
+*********************
+
+User written code can be placed in arbitrary places using the
+:ref:`inject-code <inject-code>` tag. To ease the binding developer
+work, the injected code can make use of special variables that will be replaced
+by the correct values. This also shields the developer from some |project|
+implementation specifics.
+
+
+.. _variables:
+
+Variables
+=========
+
+
+.. _cpp_return_argument:
+
+**%0**
+ Replaced by the C++ return variable of the Python method/function wrapper.
+
+
+.. _arg_number:
+
+**%<number>**
+ Replaced by the name of a C++ argument in the position indicated by ``<number>``.
+ The argument counting starts with ``%1``, since ``%0`` represents the return
+ variable name. If the number indicates a variable that was removed in the
+ type system description, but there is a default value for it, this value will
+ be used. Consider this example:
+
+ .. code-block:: c++
+
+ void argRemoval(int a0, int a1 = 123);
+
+
+ .. code-block:: xml
+
+ <modify-function signature="argRemoval(int, int)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ </modify-function>
+
+ The ``%1`` will be replaced by the C++ argument name, and ``%2`` will get the
+ value ``123``.
+
+
+.. _argument_names:
+
+**%ARGUMENT_NAMES**
+ Replaced by a comma separated list with the names of all C++ arguments that
+ were not removed on the type system description for the method/function. When
+ the removed argument has a default value (original or provided in the type
+ system), this value will be inserted in the argument list. If you want to remove
+ the argument so completely that it doesn't appear in any form on the
+ ``%ARGUMENT_NAMES`` replacement, don't forget to remove also its default value
+ with the :ref:`remove-default-expression <remove-default-expression>` type system tag.
+
+
+ Take the following method and related type system description as an example:
+
+ .. code-block:: c++
+
+ void argRemoval(int a0, Point a1 = Point(1, 2), bool a2 = true, Point a3 = Point(3, 4), int a4 = 56);
+
+
+ .. code-block:: xml
+
+ <modify-function signature="argRemoval(int, Point, bool, Point, int)">
+ <modify-argument index="2">
+ <remove-argument/>
+ <replace-default-expression with="Point(6, 9)"/>
+ </modify-argument>
+ <modify-argument index="4">
+ <remove-argument/>
+ </modify-argument>
+ </modify-function>
+
+ As seen on the XML description, the function's ``a1`` and ``a3`` arguments
+ were removed. If any ``inject-code`` for this function uses ``%ARGUMENT_NAMES``
+ the resulting list will be the equivalent of using individual argument type
+ system variables this way:
+
+ .. code-block:: c++
+
+ %1, Point(6, 9), %3, Point(3, 4), %5
+
+
+.. _arg_type:
+
+**%ARG#_TYPE**
+ Replaced by the type of a C++ argument in the position indicated by ``#``.
+ The argument counting starts with ``%1``, since ``%0`` represents the return
+ variable in other contexts, but ``%ARG0_TYPE`` will not translate to the
+ return type, as this is already done by the
+ :ref:`%RETURN_TYPE <return_type>` variable.
+ Example:
+
+ .. code-block:: c++
+
+ void argRemoval(int a0, int a1 = 123);
+
+
+ .. code-block:: xml
+
+ <modify-function signature="argRemoval(int, int)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ </modify-function>
+
+ The ``%1`` will be replaced by the C++ argument name, and ``%2`` will get the
+ value ``123``.
+
+
+.. _converttocpp:
+
+**%CONVERTTOCPP[CPPTYPE]**
+ Replaced by a |project| conversion call that converts a Python variable
+ to a C++ variable of the type indicated by ``CPPTYPE``.
+
+ Typically, this is a variable assignment:
+
+ .. code-block:: c++
+
+ double value = %CONVERTTOCPP[double](pyValue);
+
+ Pointer assignments are also possible:
+
+ .. code-block:: c++
+
+ void f(double *valuePtr)
+ {
+ *valuePtr = %CONVERTTOCPP[double](pyValue);
+
+ Note however, that for variable definitions, the type must
+ be a space-delimited token:
+
+ .. code-block:: c++
+
+ double * valuePtr = %CONVERTTOCPP[double](pyValue);
+
+ since it otherwise would be indistinguishable from the pointer assignment
+ above.
+
+ It is possible to use "auto" as type.
+
+.. _converttopython:
+
+**%CONVERTTOPYTHON[CPPTYPE]**
+ Replaced by a |project| conversion call that converts a C++ variable of the
+ type indicated by ``CPPTYPE`` to the proper Python object.
+
+
+.. _isconvertible:
+
+**%ISCONVERTIBLE[CPPTYPE]**
+ Replaced by a |project| "isConvertible" call that checks if a Python
+ variable is convertible (via an implicit conversion or cast operator call)
+ to a C++ variable of the type indicated by ``CPPTYPE``.
+
+
+.. _checktype:
+
+**%CHECKTYPE[CPPTYPE]**
+ Replaced by a |project| "checkType" call that verifies if a Python
+ if of the type indicated by ``CPPTYPE``.
+
+
+.. _cppself:
+
+**%CPPSELF**
+ Replaced by the wrapped C++ object instance that owns the method in which the
+ code with this variable was inserted.
+
+.. _cpptype:
+
+**%CPPTYPE**
+ Replaced by the original name of the C++ class, without any namespace prefix,
+ that owns the method in which the code with this variable was inserted. It will
+ work on class level code injections also. Notice that ``CPPTYPE`` differs from
+ the :ref:`%TYPE <type>` variable, for this latter may be translated to the original
+ C++ class name or to the C++ wrapper class name.
+
+ Namespaces will are treated as classes, so ``CPPTYPE`` will work for them and their
+ enclosed functions as well.
+
+.. _function_name:
+
+**%FUNCTION_NAME**
+ Replaced by the name of a function or method.
+
+
+.. _py_return_argument:
+
+**%PYARG_0**
+ Replaced by the name of the Python return variable of the Python method/function wrapper.
+
+
+.. _pyarg:
+
+**%PYARG_<number>**
+ Similar to ``%<number>``, but is replaced by the Python arguments (PyObjects)
+ received by the Python wrapper method.
+
+ If used in the context of a native code injection, i.e. in a virtual method
+ override, ``%PYARG_<number>`` will be translated to one item of the Python tuple
+ holding the arguments that should be passed to the Python override for this
+ virtual method.
+
+ The example
+
+ .. code-block:: c++
+
+ long a = PyLong_AS_LONG(%PYARG_1);
+
+
+ is equivalent of
+
+ .. code-block:: c++
+
+ long a = PyLong_AS_LONG(PyTuple_GET_ITEM(%PYTHON_ARGUMENTS, 0));
+
+
+ The generator tries to be smart with attributions, but it will work for the
+ only simplest cases.
+
+ This example
+
+ .. code-block:: c++
+
+ Py_DECREF(%PYARG_1);
+ %PYARG_1 = PyLong_FromLong(10);
+
+
+ is equivalent of
+
+ .. code-block:: c++
+
+ Py_DECREF(PyTuple_GET_ITEM(%PYTHON_ARGUMENTS, 0));
+ PyTuple_SET_ITEM(%PYTHON_ARGUMENTS, 0, PyLong_FromLong(10));
+
+
+.. _pyself:
+
+**%PYSELF**
+ Replaced by the Python wrapper variable (a PyObject) representing the instance
+ bounded to the Python wrapper method which receives the custom code.
+
+
+.. _python_arguments:
+
+**%PYTHON_ARGUMENTS**
+ Replaced by the pointer to the Python tuple with Python objects converted from
+ the C++ arguments received on the binding override of a virtual method.
+ This tuple is the same passed as arguments to the Python method overriding the
+ C++ parent's one.
+
+
+.. _python_method_override:
+
+**%PYTHON_METHOD_OVERRIDE**
+ This variable is used only on :ref:`native method code injections
+ <codeinjecting_method_native>`, i.e. on the binding overrides for C++ virtual
+ methods. It is replaced by a pointer to the Python method override.
+
+
+.. _pythontypeobject:
+
+**%PYTHONTYPEOBJECT**
+ Replaced by the Python type object for the context in which it is inserted:
+ method or class modification.
+
+
+.. _beginallowthreads:
+
+**%BEGIN_ALLOW_THREADS**
+ Replaced by a thread state saving procedure.
+ Must match with a :ref:`%END_ALLOW_THREADS <endallowthreads>` variable.
+
+
+.. _endallowthreads:
+
+**%END_ALLOW_THREADS**
+ Replaced by a thread state restoring procedure.
+ Must match with a :ref:`%BEGIN_ALLOW_THREADS <beginallowthreads>` variable.
+
+
+.. _return_type:
+
+**%RETURN_TYPE**
+ Replaced by the type returned by a function or method.
+
+
+.. _type:
+
+**%TYPE**
+ Replaced by the name of the class to which a function belongs. May be used
+ in code injected at method or class level.
+
+
+.. _example:
+
+Example
+=======
+
+Just to illustrate the usage of the variables described in the previous
+sections, below is an excerpt from the type system description of a |project|
+test. It changes a method that received ``argc/argv`` arguments into something
+that expects a Python sequence instead.
+
+.. code-block:: xml
+
+ <modify-function signature="overloadedMethod(int, char**)">
+ <modify-argument index="1">
+ <replace-type modified-type="PySequence" />
+ </modify-argument>
+ <modify-argument index="2">
+ <remove-argument />
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ int argc;
+ char** argv;
+ if (!PySequence_to_argc_argv(%PYARG_1, &amp;argc, &amp;argv)) {
+ PyErr_SetString(PyExc_TypeError, "error");
+ return 0;
+ }
+ %RETURN_TYPE foo = %CPPSELF.%FUNCTION_NAME(argc, argv);
+ %0 = %CONVERTTOPYTHON[%RETURN_TYPE](foo);
+
+ for (int i = 0; i &lt; argc; ++i)
+ delete[] argv[i];
+ delete[] argv;
+ </inject-code>
+ </modify-function>
diff --git a/sources/shiboken6/generator/CMakeLists.txt b/sources/shiboken6/generator/CMakeLists.txt
new file mode 100644
index 000000000..aebe2cd5e
--- /dev/null
+++ b/sources/shiboken6/generator/CMakeLists.txt
@@ -0,0 +1,121 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(shibokengenerator)
+set(package_name "Shiboken6Tools")
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT (Qt${QT_MAJOR_VERSION}Core_FOUND AND Python_Interpreter_FOUND))
+ message(WARNING "Some dependencies were not found: shiboken6 generator compilation disabled!")
+ return()
+endif()
+
+set(shiboken6_SRC
+defaultvalue.cpp defaultvalue.h
+generator.cpp generator.h
+generatorcontext.cpp generatorcontext.h
+main.cpp
+shiboken/configurablescope.h
+shiboken/cppgenerator.cpp shiboken/cppgenerator.h
+shiboken/cppgenerator_container.cpp
+shiboken/cppgenerator_smartpointer.cpp
+shiboken/ctypenames.h
+shiboken/generatorargument.cpp shiboken/generatorargument.h shiboken/generatorstrings.h
+shiboken/headergenerator.cpp shiboken/headergenerator.h
+shiboken/overloaddata.cpp shiboken/overloaddata.h
+shiboken/pytypenames.h
+shiboken/shibokengenerator.cpp shiboken/shibokengenerator.h
+)
+
+find_libclang()
+
+if(${STANDALONE})
+ list(APPEND CMAKE_INSTALL_RPATH ${base}/Qt/lib)
+else()
+ list(APPEND CMAKE_INSTALL_RPATH ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_LIBS}
+ ${libclang_lib_dir})
+endif()
+
+add_executable(shiboken6 ${shiboken6_SRC})
+add_executable(Shiboken6::shiboken6 ALIAS shiboken6)
+add_dependencies(shiboken6 apiextractor)
+
+set_target_properties(shiboken6 PROPERTIES OUTPUT_NAME shiboken6${shiboken6_SUFFIX})
+target_include_directories(shiboken6 PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/shiboken
+ ${CMAKE_CURRENT_SOURCE_DIR}/qtdoc
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${apiextractor_SOURCE_DIR}
+ )
+target_link_libraries(shiboken6 apiextractor Qt::Core)
+if (NOT DISABLE_DOCSTRINGS)
+ target_sources(shiboken6 PRIVATE
+ qtdoc/qtdocgenerator.cpp qtdoc/qtdocgenerator.h
+ qtdoc/qtxmltosphinx.cpp qtdoc/qtxmltosphinx.h
+ qtdoc/qtxmltosphinxinterface.h
+ qtdoc/rstformat.h)
+ target_compile_definitions(shiboken6 PUBLIC DOCSTRINGS_ENABLED QT_LEAN_HEADERS=1)
+endif()
+
+configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
+
+install(TARGETS shiboken6
+ EXPORT "${package_name}Targets"
+ DESTINATION "bin")
+install(EXPORT "${package_name}Targets"
+ NAMESPACE "Shiboken6::"
+ DESTINATION ${LIB_INSTALL_DIR}/cmake/${package_name})
+
+set(shiboken_generator_package_name "shiboken6_generator")
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/_config.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/_config.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
+
+# shiboken6 setuptools entry point
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_tool.py
+ DESTINATION bin
+ PERMISSIONS
+ OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ GROUP_EXECUTE GROUP_READ
+ WORLD_EXECUTE WORLD_READ)
+
+# Use absolute path instead of relative path, to avoid ninja build errors due to
+# duplicate file dependency inconsistency.
+set(shiboken_version_relative_path "${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_version.py")
+get_filename_component(shiboken_version_path ${shiboken_version_relative_path} ABSOLUTE)
+configure_file("${shiboken_version_path}"
+ "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_generator_version.py" @ONLY)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_generator_version.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
+
+include(CMakePackageConfigHelpers)
+
+# Single build-tree and install-tree Config file. There's no need for separate ones because we
+# don't specify any PATH_VARS, so the relative path of PACKAGE_PREFIX_DIR does not really matter.
+configure_package_config_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/../data/${package_name}Config.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/${package_name}Config.cmake"
+ INSTALL_DESTINATION "${LIB_INSTALL_DIR}/cmake/${package_name}"
+)
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/${package_name}ConfigVersion.cmake"
+ VERSION "${shiboken6_VERSION}"
+ COMPATIBILITY AnyNewerVersion
+ ARCH_INDEPENDENT
+)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${package_name}Config.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/${package_name}")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${package_name}ConfigVersion.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/${package_name}")
diff --git a/sources/shiboken6/generator/__init__.py.in b/sources/shiboken6/generator/__init__.py.in
new file mode 100644
index 000000000..4be6a833b
--- /dev/null
+++ b/sources/shiboken6/generator/__init__.py.in
@@ -0,0 +1,2 @@
+__version__ = "@FINAL_PACKAGE_VERSION@"
+__version_info__ = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
diff --git a/sources/shiboken6/generator/_config.py.in b/sources/shiboken6/generator/_config.py.in
new file mode 100644
index 000000000..ed7e67098
--- /dev/null
+++ b/sources/shiboken6/generator/_config.py.in
@@ -0,0 +1,10 @@
+version = "@FINAL_PACKAGE_VERSION@"
+version_info = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+
+@PACKAGE_BUILD_DATE@
+@PACKAGE_BUILD_COMMIT_DATE@
+@PACKAGE_BUILD_COMMIT_HASH@
+@PACKAGE_BUILD_COMMIT_HASH_DESCRIBED@
+@PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
+@PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT@
+@QT_MACOS_DEPLOYMENT_TARGET@
diff --git a/sources/shiboken6/generator/defaultvalue.cpp b/sources/shiboken6/generator/defaultvalue.cpp
new file mode 100644
index 000000000..89cc9fa77
--- /dev/null
+++ b/sources/shiboken6/generator/defaultvalue.cpp
@@ -0,0 +1,120 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "defaultvalue.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+// DefaultValue is used for storing default values of types for which code is
+// generated in different contexts:
+//
+// Context | Example: "Class *" | Example: "Class" with default Constructor
+// --------------------+-------------------------------+------------------------------------------
+// Variable | var{nullptr}; | var;
+// initializations | |
+// --------------------+-------------------------------+------------------------------------------
+// Return values | return nullptr; | return {}
+// --------------------+-------------------------------+------------------------------------------
+// constructor | static_cast<Class *>(nullptr) | Class()
+// arguments lists | |
+// (recursive, precise | |
+// matching). | |
+
+DefaultValue::DefaultValue(Type t, QString value) :
+ m_type(t), m_value(std::move(value))
+{
+}
+
+DefaultValue::DefaultValue(QString customValue) :
+ m_type(Custom), m_value(std::move(customValue))
+{
+}
+
+QString DefaultValue::returnValue() const
+{
+ switch (m_type) {
+ case DefaultValue::Boolean:
+ return u"false"_s;
+ case DefaultValue::CppScalar:
+ return u"0"_s;
+ case DefaultValue::Custom:
+ case DefaultValue::Enum:
+ return m_value;
+ case DefaultValue::Pointer:
+ return u"nullptr"_s;
+ case DefaultValue::Void:
+ return {};
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ return m_value + u"()"_s;
+ case DefaultValue::DefaultConstructor:
+ break;
+ }
+ return u"{}"_s;
+}
+
+QString DefaultValue::initialization() const
+{
+ switch (m_type) {
+ case DefaultValue::Boolean:
+ return u"{false}"_s;
+ case DefaultValue::CppScalar:
+ return u"{0}"_s;
+ case DefaultValue::Custom:
+ return u" = "_s + m_value;
+ case DefaultValue::Enum:
+ return u'{' + m_value + u'}';
+ case DefaultValue::Pointer:
+ return u"{nullptr}"_s;
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ break;
+ }
+ return {};
+}
+
+QString DefaultValue::constructorParameter() const
+{
+ switch (m_type) {
+ case DefaultValue::Boolean:
+ return u"false"_s;
+ case DefaultValue::CppScalar: {
+ // PYSIDE-846: Use static_cast in case of "unsigned long" and similar
+ const QString cast = m_value.contains(u' ')
+ ? u"static_cast<"_s + m_value + u'>'
+ : m_value;
+ return cast + u"(0)"_s;
+ }
+ case DefaultValue::Custom:
+ case DefaultValue::Enum:
+ return m_value;
+ case DefaultValue::Pointer:
+ // Be precise here to be able to differentiate between constructors
+ // taking different pointer types, cf
+ // QTreeWidgetItemIterator(QTreeWidget *) and
+ // QTreeWidgetItemIterator(QTreeWidgetItemIterator *).
+ return u"static_cast<"_s + m_value + u"*>(nullptr)"_s;
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ break;
+ }
+ return m_value + u"()"_s;
+}
+
+QDebug operator<<(QDebug debug, const DefaultValue &v)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "DefaultValue(" << v.type() << ", \"" << v.value() << "\")";
+ return debug;
+}
diff --git a/sources/shiboken6/generator/defaultvalue.h b/sources/shiboken6/generator/defaultvalue.h
new file mode 100644
index 000000000..d518d134f
--- /dev/null
+++ b/sources/shiboken6/generator/defaultvalue.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DEFAULTVALUE_H
+#define DEFAULTVALUE_H
+
+#include <QtCore/QString>
+
+QT_FORWARD_DECLARE_CLASS(QDebug);
+
+class DefaultValue
+{
+public:
+ enum Type
+ {
+ Boolean,
+ CppScalar, // A C++ scalar type (int,..) specified by value()
+ Custom, // A custom constructor/expression, uses value() as is
+ DefaultConstructor, // For classes named value()
+ DefaultConstructorWithDefaultValues, // as DefaultConstructor, but can't return {} though.
+ Enum, // Enum value as specified by value()
+ Pointer, // Pointer of type value()
+ Void // "", for return values only
+ };
+
+ explicit DefaultValue(Type t, QString value = QString());
+ explicit DefaultValue(QString customValue);
+
+ QString returnValue() const;
+ QString initialization() const;
+ QString constructorParameter() const;
+
+ QString value() const { return m_value; }
+ void setValue(const QString &value) { m_value = value; }
+
+ Type type() const { return m_type; }
+ void setType(Type type) { m_type = type; }
+
+private:
+ Type m_type;
+ QString m_value;
+};
+
+QDebug operator<<(QDebug debug, const DefaultValue &v);
+
+#endif // DEFAULTVALUE_H
diff --git a/sources/shiboken6/generator/generator.cpp b/sources/shiboken6/generator/generator.cpp
new file mode 100644
index 000000000..a01326530
--- /dev/null
+++ b/sources/shiboken6/generator/generator.cpp
@@ -0,0 +1,700 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "generator.h"
+#include "defaultvalue.h"
+#include "generatorcontext.h"
+#include "apiextractorresult.h"
+#include "abstractmetaargument.h"
+#include "abstractmetaenum.h"
+#include "abstractmetafunction.h"
+#include "abstractmetalang.h"
+#include "messages.h"
+#include <optionsparser.h>
+#include "reporthandler.h"
+#include "fileout.h"
+#include "arraytypeentry.h"
+#include "enumtypeentry.h"
+#include "enumvaluetypeentry.h"
+#include "namespacetypeentry.h"
+#include "primitivetypeentry.h"
+#include "typesystemtypeentry.h"
+#include <typedatabase.h>
+
+#include "qtcompat.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QRegularExpression>
+
+using namespace Qt::StringLiterals;
+
+static constexpr auto ENABLE_PYSIDE_EXTENSIONS = "enable-pyside-extensions"_L1;
+static constexpr auto AVOID_PROTECTED_HACK = "avoid-protected-hack"_L1;
+
+struct GeneratorOptions
+{
+ bool usePySideExtensions = false;
+ bool avoidProtectedHack = false;
+};
+
+struct Generator::GeneratorPrivate
+{
+ ApiExtractorResult api;
+ QString outDir;
+ // License comment
+ QString licenseComment;
+ AbstractMetaClassCList m_invisibleTopNamespaces;
+ bool m_hasPrivateClasses = false;
+ static GeneratorOptions m_options;
+};
+
+GeneratorOptions Generator::GeneratorPrivate::m_options;
+
+// Kept as a variable for a potential Qt-in-namespace support
+QString Generator::m_gsp = "::"_L1;
+
+Generator::Generator() : m_d(new GeneratorPrivate)
+{
+}
+
+Generator::~Generator()
+{
+ delete m_d;
+}
+
+bool Generator::setup(const ApiExtractorResult &api)
+{
+ m_d->api = api;
+ const auto moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
+ if (!moduleEntry) {
+ qCWarning(lcShiboken,"Couldn't find the package name!!");
+ return false;
+ }
+ if (!moduleEntry->generateCode()) {
+ qCWarning(lcShiboken, "Code generation of root typesystem is disabled!!");
+ return false;
+ }
+
+ for (const auto &c : api.classes()) {
+ if (c->enclosingClass() == nullptr && c->isInvisibleNamespace()) {
+ m_d->m_invisibleTopNamespaces.append(c);
+ c->invisibleNamespaceRecursion([&](const AbstractMetaClassCPtr &ic) {
+ m_d->m_invisibleTopNamespaces.append(ic);
+ });
+ }
+ }
+
+ return doSetup();
+}
+
+QList<OptionDescription> Generator::options()
+{
+ return {
+ {AVOID_PROTECTED_HACK,
+ u"Avoid the use of the '#define protected public' hack."_s},
+ {ENABLE_PYSIDE_EXTENSIONS,
+ u"Enable PySide extensions, such as support for signal/slots,\n"
+ "use this if you are creating a binding for a Qt-based library."_s}
+ };
+}
+
+class GeneratorOptionsParser : public OptionsParser
+{
+public:
+ explicit GeneratorOptionsParser(GeneratorOptions *o) : m_options(o) {}
+
+ bool handleBoolOption(const QString &key, OptionSource source) override;
+
+private:
+ GeneratorOptions *m_options;
+};
+
+bool GeneratorOptionsParser::handleBoolOption(const QString & key, OptionSource source)
+{
+ if (source == OptionSource::CommandLineSingleDash)
+ return false;
+ if (key == ENABLE_PYSIDE_EXTENSIONS)
+ return ( m_options->usePySideExtensions = true);
+ if (key == AVOID_PROTECTED_HACK)
+ return ( m_options->avoidProtectedHack = true);
+ return false;
+}
+
+std::shared_ptr<OptionsParser> Generator::createOptionsParser()
+{
+ return std::make_shared<GeneratorOptionsParser>(&GeneratorPrivate::m_options);
+}
+
+QString Generator::fileNameForContextHelper(const GeneratorContext &context,
+ const QString &suffix,
+ FileNameFlags flags)
+
+{
+ if (!context.forSmartPointer()) {
+ const auto metaClass = context.metaClass();
+ QString fileNameBase = flags.testFlag(FileNameFlag::UnqualifiedName)
+ ? metaClass->name() : metaClass->qualifiedCppName();
+ if (!flags.testFlag(FileNameFlag::KeepCase))
+ fileNameBase = fileNameBase.toLower();
+ fileNameBase.replace(u"::"_s, u"_"_s);
+ return fileNameBase + suffix;
+ }
+
+ // FIXME: PYSIDE7: Use the above code path for all types. Note the file
+ // names will then change to reflect the namespaces of the pointee
+ // (smart/integer2).
+ const AbstractMetaType &smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType);
+ return fileNameBase + suffix;
+}
+
+const AbstractMetaClassCList &Generator::invisibleTopNamespaces() const
+{
+ return m_d->m_invisibleTopNamespaces;
+}
+
+PrimitiveTypeEntryCList Generator::primitiveTypes()
+{
+ return TypeDatabase::instance()->primitiveTypes();
+}
+
+ContainerTypeEntryCList Generator::containerTypes()
+{
+ return TypeDatabase::instance()->containerTypes();
+}
+
+QString Generator::licenseComment() const
+{
+ return m_d->licenseComment;
+}
+
+void Generator::setLicenseComment(const QString &licenseComment)
+{
+ m_d->licenseComment = licenseComment;
+}
+
+QString Generator::packageName()
+{
+ return TypeDatabase::instance()->defaultPackageName();
+}
+
+static QString getModuleName()
+{
+ QString result = TypeDatabase::instance()->defaultPackageName();
+ result.remove(0, result.lastIndexOf(u'.') + 1);
+ return result;
+}
+
+QString Generator::moduleName()
+{
+ static const QString result = getModuleName();
+ return result;
+}
+
+QString Generator::outputDirectory() const
+{
+ return m_d->outDir;
+}
+
+void Generator::setOutputDirectory(const QString &outDir)
+{
+ m_d->outDir = outDir;
+}
+
+bool Generator::generateFileForContext(const GeneratorContext &context)
+{
+ const auto cls = context.metaClass();
+ auto typeEntry = cls->typeEntry();
+
+ if (!shouldGenerate(typeEntry))
+ return true;
+
+ const QString fileName = fileNameForContext(context);
+ if (fileName.isEmpty())
+ return true;
+
+ QString filePath = outputDirectory() + u'/'
+ + subDirectoryForPackage(typeEntry->targetLangPackage())
+ + u'/' + fileName;
+ FileOut fileOut(filePath);
+
+ generateClass(fileOut.stream, context);
+
+ fileOut.done();
+ return true;
+}
+
+QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType &smartPointerType)
+{
+ const AbstractMetaType innerType = smartPointerType.getSmartPointerInnerType();
+ smartPointerType.typeEntry()->qualifiedCppName();
+ QString fileName = smartPointerType.typeEntry()->qualifiedCppName().toLower();
+ fileName.append(u'_');
+ fileName.append(innerType.name().toLower());
+ fileName.replace(u"::"_s, u"_"_s); // std::shared_ptr<std::string>
+ return fileName;
+}
+
+GeneratorContext Generator::contextForClass(const AbstractMetaClassCPtr &c) const
+{
+ GeneratorContext result;
+ result.m_metaClass = c;
+ return result;
+}
+
+GeneratorContext
+ Generator::contextForSmartPointer(const AbstractMetaClassCPtr &c,
+ const AbstractMetaType &t,
+ const AbstractMetaClassCPtr &pointeeClass)
+{
+ GeneratorContext result;
+ result.m_metaClass = c;
+ result.m_preciseClassType = t;
+ result.m_type = GeneratorContext::SmartPointer;
+ result.m_pointeeClass = pointeeClass;
+ return result;
+}
+
+bool Generator::generate()
+{
+ for (const auto &cls : m_d->api.classes()) {
+ if (!generateFileForContext(contextForClass(cls)))
+ return false;
+ auto te = cls->typeEntry();
+ if (shouldGenerate(te) && te->isPrivate())
+ m_d->m_hasPrivateClasses = true;
+ }
+
+ for (const auto &smp: m_d->api.instantiatedSmartPointers()) {
+ AbstractMetaClassCPtr pointeeClass;
+ const auto instantiatedType = smp.type.instantiations().constFirst().typeEntry();
+ if (instantiatedType->isComplex()) // not a C++ primitive
+ pointeeClass = AbstractMetaClass::findClass(m_d->api.classes(), instantiatedType);
+ if (!generateFileForContext(contextForSmartPointer(smp.specialized, smp.type,
+ pointeeClass))) {
+ return false;
+ }
+ }
+ return finishGeneration();
+}
+
+bool Generator::shouldGenerate(const TypeEntryCPtr &typeEntry) const
+{
+ return typeEntry->shouldGenerate();
+}
+
+const ApiExtractorResult &Generator::api() const
+{
+ return m_d->api;
+}
+
+bool Generator::hasPrivateClasses() const
+{
+ return m_d->m_hasPrivateClasses;
+}
+
+bool Generator::usePySideExtensions()
+{
+ return GeneratorPrivate::m_options.usePySideExtensions;
+}
+
+bool Generator::avoidProtectedHack()
+{
+ return GeneratorPrivate::m_options.avoidProtectedHack;
+}
+
+QString Generator::getFullTypeName(TypeEntryCPtr type)
+{
+ QString result = type->qualifiedCppName();
+ if (type->isArray())
+ type = std::static_pointer_cast<const ArrayTypeEntry>(type)->nestedTypeEntry();
+ return isCppPrimitive(type) ? result : addGlobalScopePrefix(result);
+}
+
+QString Generator::getFullTypeName(const AbstractMetaType &type)
+{
+ if (type.isCString())
+ return u"const char*"_s;
+ if (type.isVoidPointer())
+ return u"void*"_s;
+ if (type.typeEntry()->isContainer())
+ return addGlobalScopePrefix(type.cppSignature());
+ QString typeName;
+ if (type.typeEntry()->isComplex() && type.hasInstantiations())
+ typeName = getFullTypeNameWithoutModifiers(type);
+ else
+ typeName = getFullTypeName(type.typeEntry());
+ return typeName + QString::fromLatin1("*").repeated(type.indirections());
+}
+
+QString Generator::getFullTypeName(const AbstractMetaClassCPtr &metaClass)
+{
+ const QString &qualName = metaClass->qualifiedCppName();
+ // Typedefs are generated into the global namespace
+ return metaClass->isTypeDef() ? qualName : addGlobalScopePrefix(qualName);
+}
+
+QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType &type)
+{
+ if (type.isCString())
+ return u"const char*"_s;
+ if (type.isVoidPointer())
+ return u"void*"_s;
+ if (!type.hasInstantiations())
+ return getFullTypeName(type.typeEntry());
+ QString typeName = type.cppSignature();
+ if (type.isConstant())
+ typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
+ switch (type.referenceType()) {
+ case NoReference:
+ break;
+ case LValueReference:
+ typeName.chop(1);
+ break;
+ case RValueReference:
+ typeName.chop(2);
+ break;
+ }
+ while (typeName.endsWith(u'*') || typeName.endsWith(u' '))
+ typeName.chop(1);
+ return addGlobalScopePrefix(typeName);
+}
+
+std::optional<DefaultValue>
+ Generator::minimalConstructor(const ApiExtractorResult &api,
+ const AbstractMetaType &type,
+ QString *errorString)
+{
+ if (type.referenceType() == LValueReference && type.isObjectType())
+ return {};
+
+ if (type.isContainer()) {
+ QString ctor = type.cppSignature();
+ if (ctor.endsWith(u'*')) {
+ ctor.chop(1);
+ return DefaultValue(DefaultValue::Pointer, ctor.trimmed());
+ }
+ if (ctor.startsWith(u"const "))
+ ctor.remove(0, sizeof("const ") / sizeof(char) - 1);
+ if (ctor.endsWith(u'&')) {
+ ctor.chop(1);
+ ctor = ctor.trimmed();
+ }
+ return DefaultValue(DefaultValue::DefaultConstructor, u"::"_s + ctor);
+ }
+
+ if (type.isNativePointer())
+ return DefaultValue(DefaultValue::Pointer, type.typeEntry()->qualifiedCppName());
+ if (type.isPointer())
+ return DefaultValue(DefaultValue::Pointer, getFullTypeName(type.typeEntry()));
+
+ if (type.typeEntry()->isSmartPointer())
+ return minimalConstructor(api, type.typeEntry());
+
+ if (type.typeEntry()->isComplex()) {
+ auto cType = std::static_pointer_cast<const ComplexTypeEntry>(type.typeEntry());
+ if (cType->hasDefaultConstructor())
+ return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
+ auto klass = AbstractMetaClass::findClass(api.classes(), cType);
+ if (!klass) {
+ if (errorString != nullptr)
+ *errorString = msgClassNotFound(cType);
+ return {};
+ }
+ auto ctorO = minimalConstructor(api, klass);
+ if (ctorO.has_value() && type.hasInstantiations()) {
+ auto ctor = ctorO.value();
+ QString v = ctor.value();
+ v.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ ctor.setValue(v);
+ return ctor;
+ }
+ return ctorO;
+ }
+
+ return minimalConstructor(api, type.typeEntry(), errorString);
+}
+
+std::optional<DefaultValue>
+ Generator::minimalConstructor(const ApiExtractorResult &api,
+ const TypeEntryCPtr &type,
+ QString *errorString)
+{
+ if (!type)
+ return {};
+
+ if (isCppPrimitive(type)) {
+ const QString &name = type->qualifiedCppName();
+ return name == u"bool"
+ ? DefaultValue(DefaultValue::Boolean)
+ : DefaultValue(DefaultValue::CppScalar, name);
+ }
+
+ if (type->isEnum()) {
+ const auto enumEntry = std::static_pointer_cast<const EnumTypeEntry>(type);
+ if (const auto nullValue = enumEntry->nullValue())
+ return DefaultValue(DefaultValue::Enum, nullValue->name());
+ return DefaultValue(DefaultValue::Custom,
+ "static_cast< "_L1 + getFullTypeName(type) + ">(0)"_L1);
+ }
+
+ if (type->isFlags()) {
+ return DefaultValue(DefaultValue::Custom,
+ type->qualifiedCppName() + u"(0)"_s);
+ }
+
+ if (type->isPrimitive()) {
+ QString ctor = std::static_pointer_cast<const PrimitiveTypeEntry>(type)->defaultConstructor();
+ // If a non-C++ (i.e. defined by the user) primitive type does not have
+ // a default constructor defined by the user, the empty constructor is
+ // heuristically returned. If this is wrong the build of the generated
+ // bindings will tell.
+ return ctor.isEmpty()
+ ? DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues, u"::"_s
+ + type->qualifiedCppName())
+ : DefaultValue(DefaultValue::Custom, ctor);
+ }
+
+ if (type->isSmartPointer())
+ return DefaultValue(DefaultValue::DefaultConstructor, type->qualifiedCppName());
+
+ if (type->isComplex()) {
+ auto klass = AbstractMetaClass::findClass(api.classes(), type);
+ if (!klass) {
+ if (errorString != nullptr)
+ *errorString = msgClassNotFound(type);
+ return {};
+ }
+ return minimalConstructor(api, klass, errorString);
+ }
+
+ if (errorString != nullptr)
+ *errorString = u"No default value could be determined."_s;
+ return {};
+}
+
+static QString constructorCall(const QString &qualifiedCppName, const QStringList &args)
+{
+ return u"::"_s + qualifiedCppName + u'('
+ + args.join(u", "_s) + u')';
+}
+
+std::optional<DefaultValue>
+ Generator::minimalConstructor(const ApiExtractorResult &api,
+ const AbstractMetaClassCPtr &metaClass,
+ QString *errorString)
+{
+ if (!metaClass)
+ return {};
+
+ auto cType = std::static_pointer_cast<const ComplexTypeEntry>(metaClass->typeEntry());
+ if (cType->hasDefaultConstructor())
+ return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
+
+ const QString qualifiedCppName = cType->qualifiedCppName();
+ // Obtain a list of constructors sorted by complexity and number of arguments
+ QMultiMap<int, const AbstractMetaFunctionCPtr> candidates;
+ const auto &constructors = metaClass->queryFunctions(FunctionQueryOption::Constructors);
+ for (const auto &ctor : constructors) {
+ if (!ctor->isUserAdded() && !ctor->isPrivate()
+ && (ctor->isPublic() || !api.flags().testFlag(ApiExtractorFlag::AvoidProtectedHack))) {
+ // No arguments: Default constructible
+ const auto &arguments = ctor->arguments();
+ if (arguments.isEmpty()) {
+ return DefaultValue(DefaultValue::DefaultConstructor,
+ u"::"_s + qualifiedCppName);
+ }
+ // First argument has unmodified default: Default constructible with values
+ if (arguments.constFirst().hasUnmodifiedDefaultValueExpression()) {
+ return DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues,
+ u"::"_s + qualifiedCppName);
+ }
+ // Examine arguments, exclude functions taking a self parameter
+ bool simple = true;
+ bool suitable = true;
+ for (qsizetype i = 0, size = arguments.size();
+ suitable && i < size && !arguments.at(i).hasOriginalDefaultValueExpression(); ++i) {
+ const AbstractMetaArgument &arg = arguments.at(i);
+ TypeEntryCPtr aType = arg.type().typeEntry();
+ suitable &= aType != cType;
+ simple &= isCppPrimitive(aType) || aType->isEnum() || arg.type().isPointer();
+ }
+ if (suitable)
+ candidates.insert(arguments.size() + (simple ? 0 : 100), ctor);
+ }
+ }
+
+ for (auto it = candidates.cbegin(), end = candidates.cend(); it != end; ++it) {
+ const AbstractMetaArgumentList &arguments = it.value()->arguments();
+ QStringList args;
+ for (const auto &arg : arguments) {
+ if (arg.hasModifiedDefaultValueExpression()) {
+ args << arg.defaultValueExpression(); // Spell out modified values
+ break;
+ }
+ if (arg.hasOriginalDefaultValueExpression())
+ break;
+ auto argValue = minimalConstructor(api, arg.type(), errorString);
+ if (!argValue.has_value())
+ return {};
+ args << argValue->constructorParameter();
+ }
+ return DefaultValue(DefaultValue::Custom, constructorCall(qualifiedCppName, args));
+ }
+
+ return {};
+}
+
+QString Generator::translateType(AbstractMetaType cType,
+ const AbstractMetaClassCPtr &context,
+ Options options) const
+{
+ QString s;
+
+ if (context &&
+ context->typeEntry()->isGenericClass() &&
+ cType.originalTemplateType()) {
+ cType = *cType.originalTemplateType();
+ }
+
+ if (cType.isVoid()) {
+ s = u"void"_s;
+ } else if (cType.isArray()) {
+ s = translateType(*cType.arrayElementType(), context, options) + u"[]"_s;
+ } else {
+ AbstractMetaType copyType = cType;
+ if (options & Generator::ExcludeConst || options & Generator::ExcludeReference) {
+ if (options & Generator::ExcludeConst)
+ copyType.setConstant(false);
+ if (options & Generator::ExcludeReference)
+ copyType.setReferenceType(NoReference);
+ }
+
+ s = copyType.cppSignature();
+ const auto te = copyType.typeEntry();
+ if (!te->isVoid() && !isCppPrimitive(te)) { // Add scope resolution
+ const auto pos = s.indexOf(te->qualifiedCppName()); // Skip const/volatile
+ Q_ASSERT(pos >= 0);
+ s.insert(pos, u"::"_s);
+ }
+ }
+
+ return s;
+}
+
+static const QHash<QString, QString> &pythonOperators()
+{
+ static const QHash<QString, QString> result = {
+ // call operator
+ {u"operator()"_s, u"__call__"_s},
+ // Arithmetic operators
+ {u"operator+"_s, u"__add__"_s},
+ {u"operator-"_s, u"__sub__"_s},
+ {u"operator*"_s, u"__mul__"_s},
+ {u"operator/"_s, u"__div__"_s},
+ {u"operator%"_s, u"__mod__"_s},
+ // Inplace arithmetic operators
+ {u"operator+="_s, u"__iadd__"_s},
+ {u"operator-="_s, u"__isub__"_s},
+ {u"operator++"_s, u"__iadd__"_s},
+ {u"operator--"_s, u"__isub__"_s},
+ {u"operator*="_s, u"__imul__"_s},
+ {u"operator%="_s, u"__imod__"_s},
+ // Bitwise operators
+ {u"operator&"_s, u"__and__"_s},
+ {u"operator^"_s, u"__xor__"_s},
+ {u"operator|"_s, u"__or__"_s},
+ {u"operator<<"_s, u"__lshift__"_s},
+ {u"operator>>"_s, u"__rshift__"_s},
+ {u"operator~"_s, u"__invert__"_s},
+ // Inplace bitwise operators
+ {u"operator&="_s, u"__iand__"_s},
+ {u"operator^="_s, u"__ixor__"_s},
+ {u"operator|="_s, u"__ior__"_s},
+ {u"operator<<="_s, u"__ilshift__"_s},
+ {u"operator>>="_s, u"__irshift__"_s},
+ // Comparison operators
+ {u"operator=="_s, u"__eq__"_s},
+ {u"operator!="_s, u"__ne__"_s},
+ {u"operator<"_s, u"__lt__"_s},
+ {u"operator>"_s, u"__gt__"_s},
+ {u"operator<="_s, u"__le__"_s},
+ {u"operator>="_s, u"__ge__"_s},
+ // Conversion (note bool has special handling with heuristics)
+ {u"operator int"_s, u"__int__"_s},
+ {u"operator double"_s, u"__float__"_s}
+ };
+ return result;
+}
+
+QString Generator::pythonOperatorFunctionName(const QString &cppOpFuncName)
+{
+ return pythonOperators().value(cppOpFuncName);
+}
+
+bool Generator::isPythonOperatorFunctionName(const QString &cppOpFuncName)
+{
+ return pythonOperators().contains(cppOpFuncName);
+}
+
+QString Generator::subDirectoryForPackage(QString packageNameIn) const
+{
+ if (packageNameIn.isEmpty())
+ packageNameIn = packageName();
+ packageNameIn.replace(u'.', QDir::separator());
+ return packageNameIn;
+}
+
+QString Generator::addGlobalScopePrefix(const QString &t)
+{
+ return t.startsWith("std::"_L1) ? t : m_gsp + t;
+}
+
+QString Generator::globalScopePrefix(const GeneratorContext &classContext)
+{
+ return classContext.useWrapper() ? QString{} : m_gsp;
+}
+
+template<typename T>
+static QString getClassTargetFullName_(T t, bool includePackageName)
+{
+ QString name = t->name();
+ AbstractMetaClassCPtr context = t->enclosingClass();
+ while (context) {
+ // If the type was marked as 'visible=false' we should not use it in
+ // the type name
+ if (NamespaceTypeEntry::isVisibleScope(context->typeEntry())) {
+ name.prepend(u'.');
+ name.prepend(context->name());
+ }
+ context = context->enclosingClass();
+ }
+ if (includePackageName) {
+ name.prepend(u'.');
+ name.prepend(t->package());
+ }
+ return name;
+}
+
+QString getClassTargetFullName(const AbstractMetaClassCPtr &metaClass,
+ bool includePackageName)
+{
+ return getClassTargetFullName_(metaClass, includePackageName);
+}
+
+QString getClassTargetFullName(const AbstractMetaEnum &metaEnum,
+ bool includePackageName)
+{
+ return getClassTargetFullName_(&metaEnum, includePackageName);
+}
+
+QString getFilteredCppSignatureString(QString signature)
+{
+ signature.replace(u"::"_s, u"_"_s);
+ signature.replace(u'<', u'_');
+ signature.replace(u'>', u'_');
+ signature.replace(u' ', u'_');
+ return signature;
+}
diff --git a/sources/shiboken6/generator/generator.h b/sources/shiboken6/generator/generator.h
new file mode 100644
index 000000000..5b051b599
--- /dev/null
+++ b/sources/shiboken6/generator/generator.h
@@ -0,0 +1,233 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef GENERATOR_H
+#define GENERATOR_H
+
+#include <abstractmetalang_typedefs.h>
+#include <typedatabase_typedefs.h>
+#include <QtCore/QList>
+
+#include <memory>
+#include <optional>
+
+
+class ApiExtractorResult;
+class GeneratorContext;
+class DefaultValue;
+struct OptionDescription;
+class OptionsParser;
+class TextStream;
+
+QString getClassTargetFullName(const AbstractMetaClassCPtr &metaClass,
+ bool includePackageName = true);
+QString getClassTargetFullName(const AbstractMetaEnum &metaEnum,
+ bool includePackageName = true);
+QString getFilteredCppSignatureString(QString signature);
+
+/**
+ * Base class for all generators. The default implementations does nothing,
+ * you must subclass this to create your own generators.
+ */
+class Generator
+{;
+public:
+ Q_DISABLE_COPY_MOVE(Generator)
+
+ /// Options used around the generator code
+ enum Option {
+ NoOption = 0x00000000,
+ ExcludeConst = 0x00000001,
+ ExcludeReference = 0x00000002,
+
+ SkipReturnType = 0x00000010,
+ VirtualCall = 0x00000040,
+ OriginalTypeDescription = 0x00000080,
+ SkipRemovedArguments = 0x00000100,
+
+ SkipDefaultValues = 0x00000200,
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ enum FileNameFlag {
+ UnqualifiedName = 0x1,
+ KeepCase = 0x2
+ };
+ Q_DECLARE_FLAGS(FileNameFlags, FileNameFlag)
+
+ Generator();
+ virtual ~Generator();
+
+ bool setup(const ApiExtractorResult &api);
+
+ static QList<OptionDescription> options();
+ static std::shared_ptr<OptionsParser> createOptionsParser();
+
+ /// Returns the top namespace made invisible
+ const AbstractMetaClassCList &invisibleTopNamespaces() const;
+
+ /// Returns the output directory
+ QString outputDirectory() const;
+
+ /// Set the output directory
+ void setOutputDirectory(const QString &outDir);
+
+ /**
+ * Start the code generation, be sure to call setClasses before callign this method.
+ * For each class it creates a QTextStream, call the write method with the current
+ * class and the associated text stream, then write the text stream contents if needed.
+ * \see #write
+ */
+ bool generate();
+
+ /// Returns the license comment to be prepended to each source file generated.
+ QString licenseComment() const;
+
+ /// Sets the license comment to be prepended to each source file generated.
+ void setLicenseComment(const QString &licenseComment);
+
+ /// Returns the generator's name. Used for cosmetic purposes.
+ virtual const char *name() const = 0;
+
+ /// Returns the API as determined by ApiExtractor
+ const ApiExtractorResult &api() const;
+
+ bool hasPrivateClasses() const;
+
+ /// Returns true if the user enabled PySide extensions (command line option)
+ static bool usePySideExtensions();
+ /// Returns true if the generated code should not use the
+ /// "#define protected public" hack.
+ static bool avoidProtectedHack();
+
+ /**
+ * Retrieves the name of the currently processed module.
+ * While package name is a complete package idetification, e.g. 'PySide.QtCore',
+ * a module name represents the last part of the package, e.g. 'QtCore'.
+ * If the target language separates the modules with characters other than
+ * dots ('.') the generator subclass must overload this method.
+ * \return a string representing the last part of a package name
+ */
+ static QString moduleName();
+
+ static QString pythonOperatorFunctionName(const QString &cppOpFuncName);
+ static bool isPythonOperatorFunctionName(const QString &cppOpFuncName);
+
+protected:
+ /// Helper for determining the file name
+ static QString fileNameForContextHelper(const GeneratorContext &context,
+ const QString &suffix,
+ FileNameFlags flags = {});
+
+ /// Returns all primitive types found by APIExtractor
+ static PrimitiveTypeEntryCList primitiveTypes();
+
+ /// Returns all container types found by APIExtractor
+ static ContainerTypeEntryCList containerTypes();
+
+ virtual GeneratorContext contextForClass(const AbstractMetaClassCPtr &c) const;
+ static GeneratorContext
+ contextForSmartPointer(const AbstractMetaClassCPtr &c, const AbstractMetaType &t,
+ const AbstractMetaClassCPtr &pointeeClass = {});
+
+ /// Generates a file for given AbstractMetaClass or AbstractMetaType (smart pointer case).
+ bool generateFileForContext(const GeneratorContext &context);
+
+ /// Returns the file base name for a smart pointer.
+ static QString getFileNameBaseForSmartPointer(const AbstractMetaType &smartPointerType);
+
+ /// Returns true if the generator should generate any code for the AbstractMetaClass.
+ virtual bool shouldGenerate(const TypeEntryCPtr &t) const;
+
+ /**
+ * Translate metatypes to binding source format.
+ * \param metatype a pointer to metatype
+ * \param context the current meta class
+ * \param option some extra options
+ * \return the metatype translated to binding source format
+ */
+ QString translateType(AbstractMetaType metatype,
+ const AbstractMetaClassCPtr &context,
+ Options options = NoOption) const;
+
+ /**
+ * Returns the package name.
+ */
+ static QString packageName();
+
+ // Returns the full name of the type.
+ static QString getFullTypeName(TypeEntryCPtr type);
+ static QString getFullTypeName(const AbstractMetaType &type);
+ static QString getFullTypeName(const AbstractMetaClassCPtr &metaClass);
+
+ /**
+ * Returns the full qualified C++ name for an AbstractMetaType, but removing modifiers
+ * as 'const', '&', and '*' (except if the class is not derived from a template).
+ * This is useful for instantiated templates.
+ */
+ static QString getFullTypeNameWithoutModifiers(const AbstractMetaType &type);
+
+ /**
+ * Tries to build a minimal constructor for the type.
+ * It will check first for a user defined default constructor.
+ * Returns a null string if it fails.
+ */
+ static std::optional<DefaultValue>
+ minimalConstructor(const ApiExtractorResult &api, const TypeEntryCPtr &type,
+ QString *errorString = nullptr);
+ static std::optional<DefaultValue>
+ minimalConstructor(const ApiExtractorResult &api, const AbstractMetaType &type,
+ QString *errorString = nullptr);
+ static std::optional<DefaultValue>
+ minimalConstructor(const ApiExtractorResult &api,
+ const AbstractMetaClassCPtr &metaClass,
+ QString *errorString = nullptr);
+
+ /**
+ * Returns the file name used to write the binding code of an AbstractMetaClass/Type.
+ * \param context the GeneratorContext which contains an AbstractMetaClass or AbstractMetaType
+ * for which the file name must be returned
+ * \return the file name used to write the binding code for the class
+ */
+ virtual QString fileNameForContext(const GeneratorContext &context) const = 0;
+
+
+ virtual bool doSetup() = 0;
+
+ /**
+ * Write the bindding code for an AbstractMetaClass.
+ * This is called by generate method.
+ * \param s text stream to write the generated output
+ * \param metaClass the class that should be generated
+ */
+ virtual void generateClass(TextStream &s, const GeneratorContext &classContext) = 0;
+ virtual bool finishGeneration() = 0;
+
+ /**
+ * Returns the subdirectory path for a given package
+ * (aka module, aka library) name.
+ * If the target language separates the package modules with characters other
+ * than dots ('.') the generator subclass must overload this method.
+ * /param packageName complete package name for which to return the subdirectory path
+ * or nothing the use the name of the currently processed package
+ * /return a string representing the subdirectory path for the given package
+ */
+ virtual QString subDirectoryForPackage(QString packageName = QString()) const;
+
+ static QString addGlobalScopePrefix(const QString &t);
+ static QString globalScopePrefix(const GeneratorContext &classContext);
+
+ static QString m_gsp;
+
+private:
+ struct GeneratorPrivate;
+ GeneratorPrivate *m_d;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options)
+Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::FileNameFlags)
+
+using GeneratorPtr = std::shared_ptr<Generator>;
+using Generators = QList<GeneratorPtr>;
+
+#endif // GENERATOR_H
diff --git a/sources/shiboken6/generator/generatorcontext.cpp b/sources/shiboken6/generator/generatorcontext.cpp
new file mode 100644
index 000000000..b50c2effb
--- /dev/null
+++ b/sources/shiboken6/generator/generatorcontext.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "generatorcontext.h"
+#include <abstractmetalang.h>
+
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+QString GeneratorContext::wrapperName() const
+{
+ Q_ASSERT(m_type == WrappedClass);
+ return m_wrappername;
+}
+
+QString GeneratorContext::effectiveClassName() const
+{
+ if (m_type == SmartPointer)
+ return m_preciseClassType.cppSignature();
+ return m_type == WrappedClass ? m_wrappername : m_metaClass->qualifiedCppName();
+}
+
+QDebug operator<<(QDebug debug, const GeneratorContext &c)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "GeneratorContext(\"" << c.metaClass()->name() << "\" ";
+ if (c.useWrapper())
+ debug << "[wrapper]";
+ else if (c.forSmartPointer())
+ debug << "[smart pointer] \"" << c.preciseType().cppSignature() << '"';
+ else
+ debug << "[class]";
+ debug << ')';
+ return debug;
+}
diff --git a/sources/shiboken6/generator/generatorcontext.h b/sources/shiboken6/generator/generatorcontext.h
new file mode 100644
index 000000000..2e58d4346
--- /dev/null
+++ b/sources/shiboken6/generator/generatorcontext.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef GENERATORCONTEXT_H
+#define GENERATORCONTEXT_H
+
+#include <abstractmetalang_typedefs.h>
+#include <abstractmetatype.h>
+#include <QtCore/QList>
+
+QT_FORWARD_DECLARE_CLASS(QDebug);
+
+// A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized
+// AbstractMetaType, for which code is currently being generated.
+//
+// The main case is when the context contains only an AbstractMetaClass pointer, which is used
+// by different methods to generate appropriate expressions, functions, type names, etc.
+//
+// The second case is for generation of code for smart pointers. In this case the m_metaClass
+// member contains the generic template class of the smart pointer, and the m_preciseClassType
+// member contains the instantiated template type, e.g. a concrete shared_ptr<int>. To
+// distinguish this case, the member m_forSmartPointer is set to true.
+//
+// In the future the second case might be generalized for all template type instantiations.
+
+class GeneratorContext {
+ friend class ShibokenGenerator;
+ friend class Generator;
+public:
+ enum Type { Class, WrappedClass, SmartPointer };
+
+ GeneratorContext() = default;
+
+ AbstractMetaClassCPtr metaClass() const { return m_metaClass; }
+ const AbstractMetaType &preciseType() const { return m_preciseClassType; }
+ AbstractMetaClassCPtr pointeeClass() const { return m_pointeeClass; }
+
+ bool forSmartPointer() const { return m_type == SmartPointer; }
+ bool useWrapper() const { return m_type == WrappedClass; }
+
+ QString wrapperName() const;
+ /// Returns the wrapper name in case of useWrapper(), the qualified class
+ /// name or the smart pointer specialization.
+ QString effectiveClassName() const;
+
+private:
+ AbstractMetaClassCPtr m_metaClass;
+ AbstractMetaClassCPtr m_pointeeClass;
+ AbstractMetaType m_preciseClassType;
+ QString m_wrappername;
+ Type m_type = Class;
+};
+
+QDebug operator<<(QDebug debug, const GeneratorContext &c);
+
+#endif // GENERATORCONTEXT_H
diff --git a/sources/shiboken6/generator/main.cpp b/sources/shiboken6/generator/main.cpp
new file mode 100644
index 000000000..9871df206
--- /dev/null
+++ b/sources/shiboken6/generator/main.cpp
@@ -0,0 +1,435 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "shibokenconfig.h"
+#include "cppgenerator.h"
+#include "generator.h"
+#include "headergenerator.h"
+#include "qtdocgenerator.h"
+
+#include <apiextractor.h>
+#include <apiextractorresult.h>
+#include <exception.h>
+#include <fileout.h>
+#include <messages.h>
+#include <optionsparser.h>
+#include <reporthandler.h>
+#include <typedatabase.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QLibrary>
+#include <QtCore/QVariant>
+
+#include "qtcompat.h"
+
+#include <exception>
+#include <iostream>
+
+using namespace Qt::StringLiterals;
+
+static const char helpHint[] = "Note: use --help or -h for more information.\n";
+static const char appName[] = "shiboken";
+
+static inline Generators docGenerators()
+{
+ Generators result;
+#ifdef DOCSTRINGS_ENABLED
+ result.append(GeneratorPtr(new QtDocGenerator));
+#endif
+ return result;
+}
+
+static inline Generators shibokenGenerators()
+{
+ Generators result;
+ result << GeneratorPtr(new CppGenerator) << GeneratorPtr(new HeaderGenerator);
+ return result;
+}
+
+struct CommonOptions
+{
+ QString generatorSet;
+ QString licenseComment;
+ QString outputDirectory = u"out"_s;
+ QStringList headers;
+ QString typeSystemFileName;
+ bool help = false;
+ bool version = false;
+ bool diff = false;
+ bool dryRun = false;
+ bool logUnmatched = false;
+ bool printBuiltinTypes = false;
+};
+
+class CommonOptionsParser : public OptionsParser
+{
+public:
+ explicit CommonOptionsParser(CommonOptions *o) : m_options(o) {}
+
+ bool handleBoolOption(const QString &key, OptionSource source) override;
+ bool handleOption(const QString &key, const QString &value, OptionSource source) override;
+
+ static OptionDescriptions optionDescriptions();
+
+private:
+ CommonOptions *m_options;
+};
+
+OptionDescriptions CommonOptionsParser::optionDescriptions()
+{
+ return {
+ {u"debug-level=[sparse|medium|full]"_s,
+ u"Set the debug level"_s},
+ {u"documentation-only"_s,
+ u"Do not generates any code, just the documentation"_s},
+ {u"compiler=<type>"_s,
+ u"Emulated compiler type (g++, msvc, clang)"_s},
+ {u"platform=<name>"_s,
+ u"Emulated platform (windows, darwin, unix)"_s},
+ {u"compiler-path=<file>"_s,
+ u"Path to the compiler for determining builtin include paths"_s},
+ {u"generator-set=<\"generator module\">"_s,
+ u"generator-set to be used. e.g. qtdoc"_s},
+ {u"diff"_s, u"Print a diff of wrapper files"_s},
+ {u"dry-run"_s, u"Dry run, do not generate wrapper files"_s},
+ {u"-h"_s, {} },
+ {u"help"_s, u"Display this help and exit"_s},
+ {u"-I<path>"_s, {} },
+ {u"include-paths="_s + OptionsParser::pathSyntax(),
+ u"Include paths used by the C++ parser"_s},
+ {u"license-file=<license-file>"_s,
+ u"File used for copyright headers of generated files"_s},
+ {u"no-suppress-warnings"_s,
+ u"Show all warnings"_s},
+ {u"output-directory=<path>"_s,
+ u"The directory where the generated files will be written"_s},
+ {u"project-file=<file>"_s,
+ u"text file containing a description of the binding project.\n"
+ "Replaces and overrides command line arguments"_s},
+ {u"silent"_s, u"Avoid printing any message"_s},
+ {u"print-builtin-types"_s,
+ u"Print information about builtin types"_s},
+ {u"version"_s,
+ u"Output version information and exit"_s}
+ };
+}
+
+bool CommonOptionsParser::handleBoolOption(const QString &key, OptionSource source)
+{
+ if (source == OptionSource::CommandLineSingleDash) {
+ if (key == u"h") {
+ m_options->help = true;
+ return true;
+ }
+ return false;
+ }
+
+ if (key == u"version") {
+ m_options->version = true;
+ return true;
+ }
+ if (key == u"help") {
+ m_options->help = true;
+ return true;
+ }
+ if (key == u"diff") {
+ FileOut::setDiff(true);
+ return true;
+ }
+ if (key == u"dry-run") {
+ FileOut::setDryRun(true);
+ return true;
+ }
+ if (key == u"silent") {
+ ReportHandler::setSilent(true);
+ return true;
+ }
+ if (key == u"log-unmatched") {
+ m_options->logUnmatched = true;
+ return true;
+ }
+ if (key == u"print-builtin-types") {
+ m_options->printBuiltinTypes = true;
+ return true;
+ }
+
+ return false;
+}
+
+bool CommonOptionsParser::handleOption(const QString &key, const QString &value,
+ OptionSource source)
+{
+ if (source == OptionSource::CommandLineSingleDash)
+ return false;
+
+ if (key == u"generator-set" || key == u"generatorSet" /* legacy */) {
+ m_options->generatorSet = value;
+ return true;
+ }
+ if (key == u"license-file") {
+ QFile licenseFile(value);
+ if (!licenseFile.open(QIODevice::ReadOnly))
+ throw Exception(msgCannotOpenForReading(licenseFile));
+ m_options->licenseComment = QString::fromUtf8(licenseFile.readAll());
+ return true;
+ }
+ if (key == u"debug-level") {
+ if (!ReportHandler::setDebugLevelFromArg(value))
+ throw Exception(u"Invalid debug level: "_s + value);
+ return true;
+ }
+ if (key == u"output-directory") {
+ m_options->outputDirectory = value;
+ return true;
+ }
+ if (key == u"compiler") {
+ if (!clang::setCompiler(value))
+ throw Exception(u"Invalid value \""_s + value + u"\" passed to --compiler"_s);
+ return true;
+ }
+ if (key == u"compiler-path") {
+ clang::setCompilerPath(value);
+ return true;
+ }
+ if (key == u"platform") {
+ if (!clang::setPlatform(value))
+ throw Exception(u"Invalid value \""_s + value + u"\" passed to --platform"_s);
+ return true;
+ }
+
+ if (source == OptionSource::ProjectFile) {
+ if (key == u"header-file") {
+ m_options->headers.append(value);
+ return true;
+ }
+ if (key == u"typesystem-file") {
+ m_options->typeSystemFileName = value;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void printUsage()
+{
+ const auto generatorOptions = Generator::options();
+
+ QTextStream s(stdout);
+ s << "Usage:\n "
+ << "shiboken [options] header-file(s) typesystem-file\n\n"
+ << "General options:\n"
+ << CommonOptionsParser::optionDescriptions()
+ << ApiExtractor::options()
+ << TypeDatabase::options()
+ << "\nSource generator options:\n\n" << generatorOptions
+ << ShibokenGenerator::options();
+
+#ifdef DOCSTRINGS_ENABLED
+ s << "\nDocumentation Generator options:\n\n"
+ << generatorOptions << QtDocGenerator::options();
+#endif
+}
+
+static inline void printVerAndBanner()
+{
+ std::cout << appName << " v" << SHIBOKEN_VERSION << std::endl;
+ std::cout << "Copyright (C) 2016 The Qt Company Ltd." << std::endl;
+}
+
+static inline void errorPrint(const QString &s, const QStringList &arguments)
+{
+ std::cerr << appName << ": " << qPrintable(s) << "\nCommand line:\n";
+ for (const auto &argument : arguments)
+ std::cerr << " \"" << qPrintable(argument) << "\"\n";
+}
+
+int shibokenMain(const QStringList &argV)
+{
+ // PYSIDE-757: Request a deterministic ordering of QHash in the code model
+ // and type system.
+ QHashSeed::setDeterministicGlobalSeed();
+
+ ReportHandler::install();
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug))
+ qCInfo(lcShiboken()).noquote().nospace() << appName << ' ' << argV.join(u' ');
+
+ Options options;
+ options.setOptions(argV);
+
+ CommonOptions commonOptions;
+ {
+ CommonOptionsParser parser(&commonOptions);
+ parser.process(&options);
+ }
+ if (commonOptions.version) {
+ printVerAndBanner();
+ return EXIT_SUCCESS;
+ }
+ if (commonOptions.help) {
+ printUsage();
+ return EXIT_SUCCESS;
+ }
+
+ Generators generators;
+
+ OptionsParserList optionParser;
+ optionParser.append(Generator::createOptionsParser());
+ optionParser.append(TypeDatabase::instance()->createOptionsParser());
+ ApiExtractor extractor;
+ optionParser.append(extractor.createOptionsParser());
+
+ // Pre-defined generator sets.
+ if (commonOptions.generatorSet == u"qtdoc") {
+ generators = docGenerators();
+ if (generators.isEmpty()) {
+ errorPrint(u"Doc strings extractions was not enabled in this shiboken build."_s, argV);
+ return EXIT_FAILURE;
+ }
+#ifdef DOCSTRINGS_ENABLED
+ optionParser.append(QtDocGenerator::createOptionsParser());
+#endif
+ } else if (commonOptions.generatorSet.isEmpty() || commonOptions.generatorSet == u"shiboken") {
+ generators = shibokenGenerators();
+ optionParser.append(ShibokenGenerator::createOptionsParser());
+ } else {
+ errorPrint(u"Unknown generator set, try \"shiboken\" or \"qtdoc\"."_s, argV);
+ return EXIT_FAILURE;
+ }
+
+ if (!QDir(commonOptions.outputDirectory).exists()) {
+ if (!QDir().mkpath(commonOptions.outputDirectory)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Can't create output directory: "
+ << QDir::toNativeSeparators(commonOptions.outputDirectory);
+ return EXIT_FAILURE;
+ }
+ }
+
+ // Create and set-up API Extractor
+ extractor.setLogDirectory(commonOptions.outputDirectory);
+
+ if (commonOptions.typeSystemFileName.isEmpty() && commonOptions.headers.isEmpty()) {
+ if (options.positionalArguments.size() < 2) {
+ errorPrint(u"Insufficient positional arguments, specify header-file and typesystem-file."_s,
+ argV);
+ std::cout << '\n';
+ printUsage();
+ return EXIT_FAILURE;
+ }
+
+ commonOptions.typeSystemFileName = options.positionalArguments.takeLast();
+ commonOptions.headers = options.positionalArguments;
+ }
+
+ QString messagePrefix = QFileInfo(commonOptions.typeSystemFileName).baseName();
+ if (messagePrefix.startsWith(u"typesystem_"))
+ messagePrefix.remove(0, 11);
+ ReportHandler::setPrefix(u'(' + messagePrefix + u')');
+
+ QFileInfoList cppFileNames;
+ for (const QString &cppFileName : std::as_const(commonOptions.headers)) {
+ const QFileInfo cppFileNameFi(cppFileName);
+ if (!cppFileNameFi.isFile() && !cppFileNameFi.isSymLink()) {
+ errorPrint(u'"' + cppFileName + u"\" does not exist."_s, argV);
+ return EXIT_FAILURE;
+ }
+ cppFileNames.append(cppFileNameFi);
+ }
+
+ optionParser.process(&options);
+ optionParser.clear();
+
+ if (!options.boolOptions.isEmpty() || !options.valueOptions.isEmpty()) {
+ errorPrint(msgLeftOverArguments(options.msgUnprocessedOptions(), argV), argV);
+ std::cout << helpHint;
+ return EXIT_FAILURE;
+ }
+
+ if (commonOptions.typeSystemFileName.isEmpty()) {
+ std::cout << "You must specify a Type System file." << std::endl << helpHint;
+ return EXIT_FAILURE;
+ }
+
+ extractor.setCppFileNames(cppFileNames);
+ extractor.setTypeSystem(commonOptions.typeSystemFileName);
+
+ ApiExtractorFlags apiExtractorFlags;
+ if (generators.constFirst()->usePySideExtensions())
+ apiExtractorFlags.setFlag(ApiExtractorFlag::UsePySideExtensions);
+ if (generators.constFirst()->avoidProtectedHack())
+ apiExtractorFlags.setFlag(ApiExtractorFlag::AvoidProtectedHack);
+ const std::optional<ApiExtractorResult> apiOpt = extractor.run(apiExtractorFlags);
+
+ if (!apiOpt.has_value()) {
+ errorPrint(u"Error running ApiExtractor."_s, argV);
+ return EXIT_FAILURE;
+ }
+
+ if (apiOpt->classes().isEmpty())
+ qCWarning(lcShiboken) << "No C++ classes found!";
+
+ if (ReportHandler::isDebug(ReportHandler::FullDebug)
+ || qEnvironmentVariableIsSet("SHIBOKEN_DUMP_CODEMODEL")) {
+ qCInfo(lcShiboken) << "API Extractor:\n" << extractor
+ << "\n\nType datase:\n" << *TypeDatabase::instance();
+ }
+
+ if (commonOptions.printBuiltinTypes)
+ TypeDatabase::instance()->formatBuiltinTypes(qInfo());
+
+ for (const GeneratorPtr &g : std::as_const(generators)) {
+ g->setOutputDirectory(commonOptions.outputDirectory);
+ g->setLicenseComment(commonOptions.licenseComment);
+ ReportHandler::startProgress("Ran "_ba + g->name() + '.');
+ const bool ok = g->setup(apiOpt.value()) && g->generate();
+ ReportHandler::endProgress();
+ if (!ok) {
+ errorPrint(u"Error running generator: "_s
+ + QLatin1StringView(g->name()) + u'.', argV);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (commonOptions.logUnmatched)
+ TypeDatabase::instance()->logUnmatched();
+
+ const QByteArray doneMessage = ReportHandler::doneMessage();
+ std::cout << doneMessage.constData() << std::endl;
+
+ return EXIT_SUCCESS;
+}
+
+#ifndef Q_OS_WIN
+
+static inline QString argvToString(const char *arg)
+{
+ return QString::fromLocal8Bit(arg);
+}
+
+int main(int argc, char *argv[])
+#else
+
+static inline QString argvToString(const wchar_t *arg)
+{
+ return QString::fromWCharArray(arg);
+}
+
+int wmain(int argc, wchar_t *argv[])
+#endif
+{
+ int ex = EXIT_SUCCESS;
+
+ QStringList argV;
+ argV.reserve(argc - 1);
+ std::transform(argv + 1, argv + argc, std::back_inserter(argV), argvToString);
+
+ try {
+ ex = shibokenMain(argV);
+ } catch (const std::exception &e) {
+ std::cerr << appName << " error: " << e.what() << std::endl;
+ ex = EXIT_FAILURE;
+ }
+ return ex;
+}
diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
new file mode 100644
index 000000000..1634a7e83
--- /dev/null
+++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
@@ -0,0 +1,1591 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qtdocgenerator.h"
+#include "generatorcontext.h"
+#include "codesnip.h"
+#include "exception.h"
+#include "abstractmetaargument.h"
+#include "apiextractorresult.h"
+#include "qtxmltosphinx.h"
+#include "rstformat.h"
+#include "ctypenames.h"
+#include "pytypenames.h"
+#include <abstractmetaenum.h>
+#include <abstractmetafield.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include "abstractmetalang_helpers.h"
+#include <fileout.h>
+#include <messages.h>
+#include <modifications.h>
+#include <propertyspec.h>
+#include <reporthandler.h>
+#include <textstream.h>
+#include <typedatabase.h>
+#include <functiontypeentry.h>
+#include <enumtypeentry.h>
+#include <complextypeentry.h>
+#include <flagstypeentry.h>
+#include <primitivetypeentry.h>
+#include <qtdocparser.h>
+#include <doxygenparser.h>
+
+#include "qtcompat.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QSet>
+
+#include <algorithm>
+#include <limits>
+
+using namespace Qt::StringLiterals;
+
+static inline QString classScope(const AbstractMetaClassCPtr &metaClass)
+{
+ return metaClass->fullName();
+}
+
+struct DocPackage
+{
+ QStringList classPages;
+ QStringList decoratorPages;
+ AbstractMetaFunctionCList globalFunctions;
+ AbstractMetaEnumList globalEnums;
+};
+
+struct DocGeneratorOptions
+{
+ QtXmlToSphinxParameters parameters;
+ QString extraSectionDir;
+ QString additionalDocumentationList;
+ QString inheritanceFile;
+ bool doxygen = false;
+ bool inheritanceDiagram = true;
+};
+
+struct GeneratorDocumentation
+{
+ struct Property
+ {
+ QString name;
+ Documentation documentation;
+ AbstractMetaType type;
+ AbstractMetaFunctionCPtr getter;
+ AbstractMetaFunctionCPtr setter;
+ AbstractMetaFunctionCPtr reset;
+ AbstractMetaFunctionCPtr notify;
+ };
+
+ AbstractMetaFunctionCList allFunctions;
+ AbstractMetaFunctionCList tocNormalFunctions; // Index lists
+ AbstractMetaFunctionCList tocVirtuals;
+ AbstractMetaFunctionCList tocSignalFunctions;
+ AbstractMetaFunctionCList tocSlotFunctions;
+ AbstractMetaFunctionCList tocStaticFunctions;
+
+ QList<Property> properties;
+};
+
+static bool operator<(const GeneratorDocumentation::Property &lhs,
+ const GeneratorDocumentation::Property &rhs)
+{
+ return lhs.name < rhs.name;
+}
+
+static QString propertyRefTarget(const QString &name)
+{
+ QString result = name;
+ // For sphinx referencing, disambiguate the target from the getter name
+ // by appending an invisible "Hangul choseong filler" character.
+ result.append(QChar(0x115F));
+ return result;
+}
+
+constexpr auto additionalDocumentationOption = "additional-documentation"_L1;
+
+constexpr auto none = "None"_L1;
+
+static bool shouldSkip(const AbstractMetaFunctionCPtr &func)
+{
+ if (DocParser::skipForQuery(func))
+ return true;
+
+ // Search a const clone (QImage::bits() vs QImage::bits() const)
+ if (func->isConstant())
+ return false;
+
+ const AbstractMetaArgumentList funcArgs = func->arguments();
+ const auto &ownerFunctions = func->ownerClass()->functions();
+ for (const auto &f : ownerFunctions) {
+ if (f != func
+ && f->isConstant()
+ && f->name() == func->name()
+ && f->arguments().size() == funcArgs.size()) {
+ // Compare each argument
+ bool cloneFound = true;
+
+ const AbstractMetaArgumentList fargs = f->arguments();
+ for (qsizetype i = 0, max = funcArgs.size(); i < max; ++i) {
+ if (funcArgs.at(i).type().typeEntry() != fargs.at(i).type().typeEntry()) {
+ cloneFound = false;
+ break;
+ }
+ }
+ if (cloneFound)
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool functionSort(const AbstractMetaFunctionCPtr &func1, const AbstractMetaFunctionCPtr &func2)
+{
+ const bool ctor1 = func1->isConstructor();
+ if (ctor1 != func2->isConstructor())
+ return ctor1;
+ const QString &name1 = func1->name();
+ const QString &name2 = func2->name();
+ if (name1 != name2)
+ return name1 < name2;
+ return func1->arguments().size() < func2->arguments().size();
+}
+
+static inline QVersionNumber versionOf(const TypeEntryCPtr &te)
+{
+ if (te) {
+ const auto version = te->version();
+ if (!version.isNull() && version > QVersionNumber(0, 0))
+ return version;
+ }
+ return {};
+}
+
+struct docRef
+{
+ explicit docRef(const char *kind, QAnyStringView name) :
+ m_kind(kind), m_name(name) {}
+
+ const char *m_kind;
+ QAnyStringView m_name;
+};
+
+static TextStream &operator<<(TextStream &s, const docRef &dr)
+{
+ s << ':' << dr.m_kind << ":`" << dr.m_name << '`';
+ return s;
+}
+
+static QString fileNameToTocEntry(const QString &fileName)
+{
+ constexpr auto rstSuffix = ".rst"_L1;
+
+ QString result = fileName;
+ if (result.endsWith(rstSuffix))
+ result.chop(rstSuffix.size()); // Remove the .rst extension
+ // skip namespace if necessary
+ auto lastDot = result.lastIndexOf(u'.');
+ if (lastDot != -1)
+ result.remove(0, lastDot + 1);
+ return result;
+}
+
+static void readExtraDoc(const QFileInfo &fi,
+ const QString &moduleName,
+ const QString &outputDir,
+ DocPackage *docPackage, QStringList *extraTocEntries)
+{
+ // Strip to "Property.rst" in output directory
+ const QString newFileName = fi.fileName().mid(moduleName.size() + 1);
+ QFile sourceFile(fi.absoluteFilePath());
+ if (!sourceFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotOpenForReading(sourceFile)));
+ return;
+ }
+ const QByteArray contents = sourceFile.readAll();
+ sourceFile.close();
+ QFile targetFile(outputDir + u'/' + newFileName);
+ if (!targetFile.open(QIODevice::WriteOnly|QIODevice::Text)) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotOpenForWriting(targetFile)));
+ return;
+ }
+ targetFile.write(contents);
+ if (contents.contains("decorator::"))
+ docPackage->decoratorPages.append(newFileName);
+ else
+ docPackage->classPages.append(newFileName);
+ extraTocEntries->append(fileNameToTocEntry(newFileName));
+}
+
+// Format a short documentation reference (automatically dropping the prefix
+// by using '~'), usable for property/attributes ("attr").
+struct shortDocRef
+{
+ explicit shortDocRef(const char *kind, QAnyStringView name) :
+ m_kind(kind), m_name(name) {}
+
+ const char *m_kind;
+ QAnyStringView m_name;
+};
+
+static TextStream &operator<<(TextStream &s, const shortDocRef &sdr)
+{
+ s << ':' << sdr.m_kind << ":`~" << sdr.m_name << '`';
+ return s;
+}
+
+struct functionRef : public docRef
+{
+ explicit functionRef(QAnyStringView name) : docRef("meth", name) {}
+};
+
+struct classRef : public shortDocRef
+{
+ explicit classRef(QAnyStringView name) : shortDocRef("class", name) {}
+};
+
+struct propRef : public shortDocRef // Attribute/property (short) reference
+{
+ explicit propRef(const QString &target) :
+ shortDocRef("attr", target) {}
+};
+
+struct headline
+{
+ explicit headline(QAnyStringView title, char underLineChar = '-') :
+ m_title(title), m_underLineChar(underLineChar) {}
+
+ QAnyStringView m_title;
+ char m_underLineChar;
+};
+
+static TextStream &operator<<(TextStream &s, const headline &h)
+{
+ s << h.m_title << '\n' << Pad(h.m_underLineChar, h.m_title.size()) << "\n\n";
+ return s;
+}
+
+struct pyClass
+{
+ explicit pyClass(QAnyStringView name) : m_name(name) {}
+
+ QAnyStringView m_name;
+};
+
+static TextStream &operator<<(TextStream &s, pyClass c)
+{
+ s << ".. py:class:: " << c.m_name << "\n\n";
+ return s;
+}
+
+struct currentModule
+{
+ explicit currentModule(QAnyStringView module) : m_module(module) {}
+
+ QAnyStringView m_module;
+};
+
+static TextStream &operator<<(TextStream &s, const currentModule &m)
+{
+ s << ".. currentmodule:: " << m.m_module << "\n\n\n";
+ return s;
+}
+
+DocGeneratorOptions QtDocGenerator::m_options;
+
+QtDocGenerator::QtDocGenerator()
+{
+ m_options.parameters.snippetComparison =
+ ReportHandler::debugLevel() >= ReportHandler::FullDebug;
+}
+
+QtDocGenerator::~QtDocGenerator() = default;
+
+QString QtDocGenerator::fileNameSuffix()
+{
+ return u".rst"_s;
+}
+
+bool QtDocGenerator::shouldGenerate(const TypeEntryCPtr &te) const
+{
+ return Generator::shouldGenerate(te)
+ && te->type() != TypeEntry::SmartPointerType;
+}
+
+QString QtDocGenerator::fileNameForContext(const GeneratorContext &context) const
+{
+ return fileNameForContextHelper(context, fileNameSuffix(),
+ FileNameFlag::UnqualifiedName
+ | FileNameFlag::KeepCase);
+}
+
+void QtDocGenerator::writeFormattedBriefText(TextStream &s, const Documentation &doc,
+ const QString &scope) const
+{
+ writeFormattedText(s, doc.brief(), doc.format(), scope);
+}
+
+void QtDocGenerator::writeFormattedDetailedText(TextStream &s, const Documentation &doc,
+ const QString &scope) const
+{
+ writeFormattedText(s, doc.detailed(), doc.format(), scope);
+}
+
+void QtDocGenerator::writeFormattedText(TextStream &s, const QString &doc,
+ Documentation::Format format,
+ const QString &scope) const
+{
+ if (format == Documentation::Native) {
+ QtXmlToSphinx x(this, m_options.parameters, doc, scope);
+ s << x;
+ } else {
+ const auto lines = QStringView{doc}.split(u'\n');
+ int typesystemIndentation = std::numeric_limits<int>::max();
+ // check how many spaces must be removed from the beginning of each line
+ for (const auto &line : lines) {
+ const auto it = std::find_if(line.cbegin(), line.cend(),
+ [] (QChar c) { return !c.isSpace(); });
+ if (it != line.cend())
+ typesystemIndentation = qMin(typesystemIndentation, int(it - line.cbegin()));
+ }
+ if (typesystemIndentation == std::numeric_limits<int>::max())
+ typesystemIndentation = 0;
+ for (const auto &line : lines) {
+ s << (typesystemIndentation > 0 && typesystemIndentation < line.size()
+ ? line.right(line.size() - typesystemIndentation) : line)
+ << '\n';
+ }
+ }
+
+ s << '\n';
+}
+
+static void writeInheritanceList(TextStream &s, const AbstractMetaClassCList& classes,
+ const char *label)
+{
+ s << "**" << label << ":** ";
+ for (qsizetype i = 0, size = classes.size(); i < size; ++i) {
+ if (i > 0)
+ s << ", ";
+ s << classRef(classes.at(i)->fullName());
+ }
+ s << "\n\n";
+}
+
+static void writeInheritedByList(TextStream &s, const AbstractMetaClassCPtr &metaClass,
+ const AbstractMetaClassCList& allClasses)
+{
+ AbstractMetaClassCList res;
+ for (const auto &c : allClasses) {
+ if (c != metaClass && inheritsFrom(c, metaClass))
+ res << c;
+ }
+
+ if (!res.isEmpty())
+ writeInheritanceList(s, res, "Inherited by");
+}
+
+static void writeInheritedFromList(TextStream &s, const AbstractMetaClassCPtr &metaClass)
+{
+ AbstractMetaClassCList res;
+
+ recurseClassHierarchy(metaClass, [&res, metaClass](const AbstractMetaClassCPtr &c) {
+ if (c.get() != metaClass.get())
+ res.append(c);
+ return false;
+ });
+
+ if (!res.isEmpty())
+ writeInheritanceList(s, res, "Inherits from");
+}
+
+void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classContext)
+{
+ AbstractMetaClassCPtr metaClass = classContext.metaClass();
+ qCDebug(lcShibokenDoc).noquote().nospace() << "Generating Documentation for " << metaClass->fullName();
+
+ m_packages[metaClass->package()].classPages << fileNameForContext(classContext);
+
+ m_docParser->setPackageName(metaClass->package());
+ m_docParser->fillDocumentation(std::const_pointer_cast<AbstractMetaClass>(metaClass));
+
+ s << currentModule(metaClass->package()) << pyClass(metaClass->name());
+ Indentation indent(s);
+
+ auto documentation = metaClass->documentation();
+ const QString scope = classScope(metaClass);
+ if (documentation.hasBrief())
+ writeFormattedBriefText(s, documentation, scope);
+
+ if (!metaClass->baseClasses().isEmpty()) {
+ if (m_options.inheritanceDiagram) {
+ s << ".. inheritance-diagram:: " << metaClass->fullName()<< '\n'
+ << " :parts: 2\n\n";
+ } else {
+ writeInheritedFromList(s, metaClass);
+ }
+ }
+
+ writeInheritedByList(s, metaClass, api().classes());
+
+ const auto version = versionOf(metaClass->typeEntry());
+ if (!version.isNull())
+ s << rstVersionAdded(version);
+ if (metaClass->attributes().testFlag(AbstractMetaClass::Deprecated))
+ s << rstDeprecationNote("class");
+
+ const GeneratorDocumentation doc = generatorDocumentation(metaClass);
+
+ if (!doc.allFunctions.isEmpty() || !doc.properties.isEmpty()) {
+ s << '\n' << headline("Synopsis");
+ writePropertyToc(s, doc);
+ writeFunctionToc(s, u"Methods"_s, doc.tocNormalFunctions);
+ writeFunctionToc(s, u"Virtual methods"_s, doc.tocVirtuals);
+ writeFunctionToc(s, u"Slots"_s, doc.tocSlotFunctions);
+ writeFunctionToc(s, u"Signals"_s, doc.tocSignalFunctions);
+ writeFunctionToc(s, u"Static functions"_s, doc.tocStaticFunctions);
+ }
+
+ s << "\n.. note::\n"
+ " This documentation may contain snippets that were automatically\n"
+ " translated from C++ to Python. We always welcome contributions\n"
+ " to the snippet translation. If you see an issue with the\n"
+ " translation, you can also let us know by creating a ticket on\n"
+ " https:/bugreports.qt.io/projects/PYSIDE\n\n";
+
+ s << '\n' << headline("Detailed Description") << ".. _More:\n";
+
+ writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass);
+ if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass))
+ writeFormattedDetailedText(s, documentation, scope);
+ writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass);
+
+ writeEnums(s, metaClass->enums(), scope);
+
+ if (!doc.properties.isEmpty())
+ writeProperties(s, doc, metaClass);
+
+ if (!metaClass->isNamespace())
+ writeFields(s, metaClass);
+
+ writeFunctions(s, doc.allFunctions, metaClass, scope);
+}
+
+void QtDocGenerator::writeFunctionToc(TextStream &s, const QString &title,
+ const AbstractMetaFunctionCList &functions)
+{
+ if (!functions.isEmpty()) {
+ s << headline(title, '^')
+ << ".. container:: function_list\n\n" << indent;
+ // Functions are sorted by the Metabuilder; erase overloads
+ QStringList toc;
+ toc.reserve(functions.size());
+ std::transform(functions.cbegin(), functions.end(),
+ std::back_inserter(toc), getFuncName);
+ toc.erase(std::unique(toc.begin(), toc.end()), toc.end());
+ for (const auto &func : toc)
+ s << "* def " << functionRef(func) << '\n';
+ s << outdent << "\n\n";
+ }
+}
+
+void QtDocGenerator::writePropertyToc(TextStream &s,
+ const GeneratorDocumentation &doc)
+{
+ if (doc.properties.isEmpty())
+ return;
+
+ s << headline("Properties", '^')
+ << ".. container:: function_list\n\n" << indent;
+ for (const auto &prop : doc.properties) {
+ s << "* " << propRef(propertyRefTarget(prop.name));
+ if (prop.documentation.hasBrief())
+ s << " - " << prop.documentation.brief();
+ s << '\n';
+ }
+ s << outdent << "\n\n";
+}
+
+void QtDocGenerator::writeProperties(TextStream &s,
+ const GeneratorDocumentation &doc,
+ const AbstractMetaClassCPtr &cppClass) const
+{
+ s << "\n.. note:: Properties can be used directly when "
+ << "``from __feature__ import true_property`` is used or via accessor "
+ << "functions otherwise.\n\n";
+
+ const QString scope = classScope(cppClass);
+ for (const auto &prop : doc.properties) {
+ const QString type = translateToPythonType(prop.type, cppClass, /* createRef */ false);
+ s << ".. py:property:: " << propertyRefTarget(prop.name)
+ << "\n :type: " << type << "\n\n\n";
+ if (!prop.documentation.isEmpty())
+ writeFormattedText(s, prop.documentation.detailed(), Documentation::Native, scope);
+ s << "**Access functions:**\n";
+ if (prop.getter)
+ s << " * " << functionRef(prop.getter->name()) << '\n';
+ if (prop.setter)
+ s << " * " << functionRef(prop.setter->name()) << '\n';
+ if (prop.reset)
+ s << " * " << functionRef(prop.reset->name()) << '\n';
+ if (prop.notify)
+ s << " * Signal " << functionRef(prop.notify->name()) << '\n';
+ s << '\n';
+ }
+}
+
+void QtDocGenerator::writeEnums(TextStream &s, const AbstractMetaEnumList &enums,
+ const QString &scope) const
+{
+ for (const AbstractMetaEnum &en : enums) {
+ s << pyClass(en.name());
+ Indentation indent(s);
+ writeFormattedDetailedText(s, en.documentation(), scope);
+ const auto version = versionOf(en.typeEntry());
+ if (!version.isNull())
+ s << rstVersionAdded(version);
+ }
+
+}
+
+void QtDocGenerator::writeFields(TextStream &s, const AbstractMetaClassCPtr &cppClass) const
+{
+ constexpr auto section_title = ".. attribute:: "_L1;
+
+ const QString scope = classScope(cppClass);
+ for (const AbstractMetaField &field : cppClass->fields()) {
+ s << section_title << cppClass->fullName() << "." << field.name() << "\n\n";
+ writeFormattedDetailedText(s, field.documentation(), scope);
+ }
+}
+
+QString QtDocGenerator::formatArgs(const AbstractMetaFunctionCPtr &func)
+{
+ QString ret = u"("_s;
+ int optArgs = 0;
+
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument &arg : arguments) {
+
+ if (arg.isModifiedRemoved())
+ continue;
+
+ bool thisIsoptional = !arg.defaultValueExpression().isEmpty();
+ if (optArgs || thisIsoptional) {
+ ret += u'[';
+ optArgs++;
+ }
+
+ if (arg.argumentIndex() > 0)
+ ret += u", "_s;
+
+ ret += arg.name();
+
+ if (thisIsoptional) {
+ QString defValue = arg.defaultValueExpression();
+ if (defValue == u"QString()") {
+ defValue = u"\"\""_s;
+ } else if (defValue == u"QStringList()"
+ || defValue.startsWith(u"QVector")
+ || defValue.startsWith(u"QList")) {
+ defValue = u"list()"_s;
+ } else if (defValue == u"QVariant()") {
+ defValue = none;
+ } else {
+ defValue.replace(u"::"_s, u"."_s);
+ if (defValue == u"nullptr")
+ defValue = none;
+ else if (defValue == u"0" && arg.type().isObject())
+ defValue = none;
+ }
+ ret += u'=' + defValue;
+ }
+ }
+
+ ret += QString(optArgs, u']') + u')';
+ return ret;
+}
+
+void QtDocGenerator::writeDocSnips(TextStream &s,
+ const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language)
+{
+ Indentation indentation(s);
+ static const QStringList invalidStrings{u"*"_s, u"//"_s, u"/*"_s, u"*/"_s};
+ const static QString startMarkup = u"[sphinx-begin]"_s;
+ const static QString endMarkup = u"[sphinx-end]"_s;
+
+ for (const CodeSnip &snip : codeSnips) {
+ if ((snip.position != position) ||
+ !(snip.language & language))
+ continue;
+
+ QString code = snip.code();
+ while (code.contains(startMarkup) && code.contains(endMarkup)) {
+ const auto startBlock = code.indexOf(startMarkup) + startMarkup.size();
+ const auto endBlock = code.indexOf(endMarkup);
+
+ if ((startBlock == -1) || (endBlock == -1))
+ break;
+
+ QString codeBlock = code.mid(startBlock, endBlock - startBlock);
+ const QStringList rows = codeBlock.split(u'\n');
+ int currentRow = 0;
+ qsizetype offset = 0;
+
+ for (QString row : rows) {
+ for (const QString &invalidString : std::as_const(invalidStrings))
+ row.remove(invalidString);
+
+ if (row.trimmed().size() == 0) {
+ if (currentRow == 0)
+ continue;
+ s << '\n';
+ }
+
+ if (currentRow == 0) {
+ //find offset
+ for (auto c : row) {
+ if (c == u' ')
+ offset++;
+ else if (c == u'\n')
+ offset = 0;
+ else
+ break;
+ }
+ }
+ s << QStringView{row}.mid(offset) << '\n';
+ currentRow++;
+ }
+
+ code = code.mid(endBlock+endMarkup.size());
+ }
+ }
+}
+
+bool QtDocGenerator::writeDocModifications(TextStream &s,
+ const DocModificationList &mods,
+ TypeSystem::DocModificationMode mode,
+ const QString &scope) const
+{
+ bool didSomething = false;
+ for (const DocModification &mod : mods) {
+ if (mod.mode() == mode) {
+ switch (mod.format()) {
+ case TypeSystem::NativeCode:
+ writeFormattedText(s, mod.code(), Documentation::Native, scope);
+ didSomething = true;
+ break;
+ case TypeSystem::TargetLangCode:
+ writeFormattedText(s, mod.code(), Documentation::Target, scope);
+ didSomething = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return didSomething;
+}
+
+bool QtDocGenerator::writeInjectDocumentation(TextStream &s,
+ TypeSystem::DocModificationMode mode,
+ const AbstractMetaClassCPtr &cppClass) const
+{
+ const bool didSomething =
+ writeDocModifications(s, DocParser::getDocModifications(cppClass),
+ mode, classScope(cppClass));
+ s << '\n';
+
+ // FIXME PYSIDE-7: Deprecate the use of doc string on glue code.
+ // This is pre "add-function" and "inject-documentation" tags.
+ const TypeSystem::CodeSnipPosition pos = mode == TypeSystem::DocModificationPrepend
+ ? TypeSystem::CodeSnipPositionBeginning : TypeSystem::CodeSnipPositionEnd;
+ writeDocSnips(s, cppClass->typeEntry()->codeSnips(), pos, TypeSystem::TargetLangCode);
+ return didSomething;
+}
+
+bool QtDocGenerator::writeInjectDocumentation(TextStream &s,
+ TypeSystem::DocModificationMode mode,
+ const DocModificationList &modifications,
+ const AbstractMetaFunctionCPtr &func,
+ const QString &scope) const
+{
+ const bool didSomething = writeDocModifications(s, modifications, mode, scope);
+ s << '\n';
+
+ // FIXME PYSIDE-7: Deprecate the use of doc string on glue code.
+ // This is pre "add-function" and "inject-documentation" tags.
+ const TypeSystem::CodeSnipPosition pos = mode == TypeSystem::DocModificationPrepend
+ ? TypeSystem::CodeSnipPositionBeginning : TypeSystem::CodeSnipPositionEnd;
+ writeDocSnips(s, func->injectedCodeSnips(), pos, TypeSystem::TargetLangCode);
+ return didSomething;
+}
+
+static QString inline toRef(const QString &t)
+{
+ return ":class:`~"_L1 + t + u'`';
+}
+
+QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
+ const AbstractMetaClassCPtr &cppClass,
+ bool createRef) const
+{
+ static const QStringList nativeTypes =
+ {boolT, floatT, intT, pyObjectT, pyStrT};
+
+ QString name = type.name();
+ if (nativeTypes.contains(name))
+ return name;
+
+ if (type.typeUsagePattern() == AbstractMetaType::PrimitivePattern) {
+ const auto &basicName = basicReferencedTypeEntry(type.typeEntry())->name();
+ if (AbstractMetaType::cppSignedIntTypes().contains(basicName)
+ || AbstractMetaType::cppUnsignedIntTypes().contains(basicName)) {
+ return intT;
+ }
+ if (AbstractMetaType::cppFloatTypes().contains(basicName))
+ return floatT;
+ }
+
+ static const QSet<QString> stringTypes = {
+ u"uchar"_s, u"std::string"_s, u"std::wstring"_s,
+ u"std::stringview"_s, u"std::wstringview"_s,
+ qStringT, u"QStringView"_s, u"QAnyStringView"_s, u"QUtf8StringView"_s
+ };
+ if (stringTypes.contains(name))
+ return pyStrT;
+
+ static const QHash<QString, QString> typeMap = {
+ { cPyObjectT, pyObjectT },
+ { u"QStringList"_s, u"list of strings"_s },
+ { qVariantT, pyObjectT }
+ };
+ const auto found = typeMap.constFind(name);
+ if (found != typeMap.cend())
+ return found.value();
+
+ if (type.isFlags()) {
+ const auto fte = std::static_pointer_cast<const FlagsTypeEntry>(type.typeEntry());
+ auto enumTypeEntry = fte->originator();
+ auto enumName = enumTypeEntry->targetLangName();
+ if (createRef)
+ enumName.prepend(enumTypeEntry->targetLangPackage() + u'.');
+ return "Combination of "_L1 + (createRef ? toRef(enumName) : enumName);
+ } else if (type.isEnum()) {
+ auto enumTypeEntry = std::static_pointer_cast<const EnumTypeEntry>(type.typeEntry());
+ auto enumName = enumTypeEntry->targetLangName();
+ if (createRef)
+ enumName.prepend(enumTypeEntry->targetLangPackage() + u'.');
+ return createRef ? toRef(enumName) : enumName;
+ }
+
+ if (type.isConstant() && name == "char"_L1 && type.indirections() == 1)
+ return "str"_L1;
+
+ if (type.isContainer()) {
+ QString strType = translateType(type, cppClass, Options(ExcludeConst) | ExcludeReference);
+ strType.remove(u'*');
+ strType.remove(u'>');
+ strType.remove(u'<');
+ strType.replace(u"::"_s, u"."_s);
+ if (strType.contains(u"QList") || strType.contains(u"QVector")) {
+ strType.replace(u"QList"_s, u"list of "_s);
+ strType.replace(u"QVector"_s, u"list of "_s);
+ } else if (strType.contains(u"QHash") || strType.contains(u"QMap")) {
+ strType.remove(u"QHash"_s);
+ strType.remove(u"QMap"_s);
+ QStringList types = strType.split(u',');
+ strType = QString::fromLatin1("Dictionary with keys of type %1 and values of type %2.")
+ .arg(types[0], types[1]);
+ }
+ return strType;
+ }
+
+ if (auto k = AbstractMetaClass::findClass(api().classes(), type.typeEntry()))
+ return createRef ? toRef(k->fullName()) : k->name();
+
+ return createRef ? toRef(name) : name;
+}
+
+QString QtDocGenerator::getFuncName(const AbstractMetaFunctionCPtr &cppFunc)
+{
+ if (cppFunc->isConstructor())
+ return "__init__"_L1;
+ QString result = cppFunc->name();
+ if (cppFunc->isOperatorOverload()) {
+ const QString pythonOperator = Generator::pythonOperatorFunctionName(result);
+ if (!pythonOperator.isEmpty())
+ return pythonOperator;
+ }
+ result.replace(u"::"_s, u"."_s);
+ return result;
+}
+
+void QtDocGenerator::writeParameterType(TextStream &s,
+ const AbstractMetaClassCPtr &cppClass,
+ const AbstractMetaArgument &arg) const
+{
+ s << ":param " << arg.name() << ": "
+ << translateToPythonType(arg.type(), cppClass) << '\n';
+}
+
+void QtDocGenerator::writeFunctionParametersType(TextStream &s,
+ const AbstractMetaClassCPtr &cppClass,
+ const AbstractMetaFunctionCPtr &func) const
+{
+ s << '\n';
+ const AbstractMetaArgumentList &funcArgs = func->arguments();
+ for (const AbstractMetaArgument &arg : funcArgs) {
+ if (!arg.isModifiedRemoved())
+ writeParameterType(s, cppClass, arg);
+ }
+
+ QString retType;
+ if (!func->isConstructor()) {
+ // check if the return type was modified
+ retType = func->modifiedTypeName();
+ if (retType.isEmpty() && !func->isVoid())
+ retType = translateToPythonType(func->type(), cppClass);
+ }
+
+ if (!retType.isEmpty())
+ s << ":rtype: " << retType << '\n';
+
+ s << '\n';
+}
+
+static bool containsFunctionDirective(const DocModification &dm)
+{
+ return dm.mode() != TypeSystem::DocModificationXPathReplace
+ && dm.code().contains(".. py:"_L1);
+}
+
+void QtDocGenerator::writeFunctions(TextStream &s, const AbstractMetaFunctionCList &funcs,
+ const AbstractMetaClassCPtr &cppClass, const QString &scope)
+{
+ QString lastName;
+ for (const auto &func : funcs) {
+ const bool indexed = func->name() != lastName;
+ lastName = func->name();
+ writeFunction(s, func, cppClass, scope, indexed);
+ }
+}
+
+void QtDocGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaClassCPtr &cppClass,
+ const QString &scope, bool indexed)
+{
+ const auto modifications = DocParser::getDocModifications(func, cppClass);
+
+ // Enable injecting parameter documentation by adding a complete function directive.
+ if (std::none_of(modifications.cbegin(), modifications.cend(), containsFunctionDirective)) {
+ if (func->ownerClass() == nullptr)
+ s << ".. py:function:: ";
+ else
+ s << (func->isStatic() ? ".. py:staticmethod:: " : ".. py:method:: ");
+ s << getFuncName(func) << formatArgs(func);
+ Indentation indentation(s);
+ if (!indexed)
+ s << "\n:noindex:";
+ if (func->cppAttributes().testFlag(FunctionAttribute::Final))
+ s << "\n:final:";
+ else if (func->isAbstract())
+ s << "\n:abstractmethod:";
+ s << "\n\n";
+ writeFunctionParametersType(s, cppClass, func);
+ const auto version = versionOf(func->typeEntry());
+ if (!version.isNull())
+ s << rstVersionAdded(version);
+ if (func->isDeprecated())
+ s << rstDeprecationNote("function");
+ }
+
+ writeFunctionDocumentation(s, func, modifications, scope);
+
+ if (auto propIndex = func->propertySpecIndex(); propIndex >= 0) {
+ const QString name = cppClass->propertySpecs().at(propIndex).name();
+ const QString target = propertyRefTarget(name);
+ if (func->isPropertyReader())
+ s << "\nGetter of property " << propRef(target) << " .\n\n";
+ else if (func->isPropertyWriter())
+ s << "\nSetter of property " << propRef(target) << " .\n\n";
+ else if (func->isPropertyResetter())
+ s << "\nReset function of property " << propRef(target) << " .\n\n";
+ else if (func->attributes().testFlag(AbstractMetaFunction::Attribute::PropertyNotify))
+ s << "\nNotification signal of property " << propRef(target) << " .\n\n";
+ }
+}
+
+void QtDocGenerator::writeFunctionDocumentation(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const DocModificationList &modifications,
+ const QString &scope) const
+
+{
+ writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, modifications, func, scope);
+ if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, modifications, func, scope)) {
+ writeFormattedBriefText(s, func->documentation(), scope);
+ writeFormattedDetailedText(s, func->documentation(), scope);
+ }
+ writeInjectDocumentation(s, TypeSystem::DocModificationAppend, modifications, func, scope);
+}
+
+static QStringList fileListToToc(const QStringList &items)
+{
+ QStringList result;
+ result.reserve(items.size());
+ std::transform(items.cbegin(), items.cend(), std::back_inserter(result),
+ fileNameToTocEntry);
+ return result;
+}
+
+static QStringList functionListToToc(const AbstractMetaFunctionCList &functions)
+{
+ QStringList result;
+ result.reserve(functions.size());
+ for (const auto &f : functions)
+ result.append(f->name());
+ // Functions are sorted by the Metabuilder; erase overloads
+ result.erase(std::unique(result.begin(), result.end()), result.end());
+ return result;
+}
+
+static QStringList enumListToToc(const AbstractMetaEnumList &enums)
+{
+ QStringList result;
+ result.reserve(enums.size());
+ for (const auto &e : enums)
+ result.append(e.name());
+ return result;
+}
+
+// Sort entries for a TOC by first character, dropping the
+// leading common Qt prefixes like 'Q'.
+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() || 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))
+ return key.at(3).toUpper(); // "QT_TR" -> 'T'
+ auto idx = 0;
+ for (; idx < size && key.at(idx) == u'_'; ++idx) {
+ } // "__init__" -> 'I'
+ return idx < size ? key.at(idx).toUpper() : u'A';
+}
+
+static void writeFancyToc(TextStream& s, QAnyStringView title,
+ const QStringList& items,
+ QLatin1StringView referenceType)
+{
+ using TocMap = QMap<QChar, QStringList>;
+
+ if (items.isEmpty())
+ return;
+
+ TocMap tocMap;
+ for (const QString &item : items)
+ tocMap[sortKey(item)] << item;
+
+ static const qsizetype numColumns = 4;
+
+ QtXmlToSphinx::Table table;
+ for (auto it = tocMap.cbegin(), end = tocMap.cend(); it != end; ++it) {
+ QtXmlToSphinx::TableRow row;
+ const QString charEntry = u"**"_s + it.key() + u"**"_s;
+ row << QtXmlToSphinx::TableCell(charEntry);
+ for (const QString &item : std::as_const(it.value())) {
+ if (row.size() >= numColumns) {
+ table.appendRow(row);
+ row.clear();
+ row << QtXmlToSphinx::TableCell(QString{});
+ }
+ const QString entry = "* :"_L1 + referenceType + ":`"_L1 + item + u'`';
+ row << QtXmlToSphinx::TableCell(entry);
+ }
+ if (row.size() > 1)
+ table.appendRow(row);
+ }
+
+ table.normalize();
+ s << '\n' << headline(title) << ".. container:: pysidetoc\n\n";
+ table.format(s);
+}
+
+bool QtDocGenerator::finishGeneration()
+{
+ for (const auto &f : api().globalFunctions()) {
+ auto ncf = std::const_pointer_cast<AbstractMetaFunction>(f);
+ m_docParser->fillGlobalFunctionDocumentation(ncf);
+ m_packages[f->targetLangPackage()].globalFunctions.append(f);
+ }
+
+ for (auto e : api().globalEnums()) {
+ m_docParser->fillGlobalEnumDocumentation(e);
+ m_packages[e.typeEntry()->targetLangPackage()].globalEnums.append(e);
+ }
+
+ if (!m_packages.isEmpty())
+ writeModuleDocumentation();
+ if (!m_options.additionalDocumentationList.isEmpty())
+ writeAdditionalDocumentation();
+ if (!m_options.inheritanceFile.isEmpty() && !writeInheritanceFile())
+ return false;
+ return true;
+}
+
+bool QtDocGenerator::writeInheritanceFile()
+{
+ QFile inheritanceFile(m_options.inheritanceFile);
+ if (!inheritanceFile.open(QIODevice::WriteOnly | QIODevice::Text))
+ throw Exception(msgCannotOpenForWriting(m_options.inheritanceFile));
+
+ QJsonObject dict;
+ for (const auto &c : api().classes()) {
+ const auto &bases = c->baseClasses();
+ if (!bases.isEmpty()) {
+ QJsonArray list;
+ for (const auto &base : bases)
+ list.append(QJsonValue(base->fullName()));
+ dict[c->fullName()] = list;
+ }
+ }
+ QJsonDocument document;
+ document.setObject(dict);
+ inheritanceFile.write(document.toJson(QJsonDocument::Compact));
+ return true;
+}
+
+// Remove function entries that have extra documentation pages
+static inline void removeExtraDocs(const QStringList &extraTocEntries,
+ AbstractMetaFunctionCList *functions)
+{
+ auto predicate = [&extraTocEntries](const AbstractMetaFunctionCPtr &f) {
+ return extraTocEntries.contains(f->name());
+ };
+ functions->erase(std::remove_if(functions->begin(),functions->end(), predicate),
+ functions->end());
+}
+
+void QtDocGenerator::writeModuleDocumentation()
+{
+ for (auto it = m_packages.begin(), end = m_packages.end(); it != end; ++it) {
+ auto &docPackage = it.value();
+ std::sort(docPackage.classPages.begin(), docPackage.classPages.end());
+
+ QString key = it.key();
+ key.replace(u'.', u'/');
+ QString outputDir = outputDirectory() + u'/' + key;
+ FileOut output(outputDir + u"/index.rst"_s);
+ TextStream& s = output.stream;
+
+ const QString &title = it.key();
+ s << ".. module:: " << title << "\n\n" << headline(title, '*');
+
+ // Store the it.key() in a QString so that it can be stripped off unwanted
+ // information when neeeded. For example, the RST files in the extras directory
+ // doesn't include the PySide# prefix in their names.
+ QString moduleName = it.key();
+ const int lastIndex = moduleName.lastIndexOf(u'.');
+ if (lastIndex >= 0)
+ moduleName.remove(0, lastIndex + 1);
+
+ // Search for extra-sections
+ QStringList extraTocEntries;
+ if (!m_options.extraSectionDir.isEmpty()) {
+ QDir extraSectionDir(m_options.extraSectionDir);
+ if (!extraSectionDir.exists()) {
+ const QString m = u"Extra sections directory "_s +
+ m_options.extraSectionDir + u" doesn't exist"_s;
+ throw Exception(m);
+ }
+
+ // Filter for "QtCore.Property.rst", skipping module doc "QtCore.rst"
+ const QString filter = moduleName + u".?*.rst"_s;
+ const auto fileList =
+ extraSectionDir.entryInfoList({filter}, QDir::Files, QDir::Name);
+ for (const auto &fi : fileList)
+ readExtraDoc(fi, moduleName, outputDir, &docPackage, &extraTocEntries);
+ }
+
+ removeExtraDocs(extraTocEntries, &docPackage.globalFunctions);
+ const bool hasGlobals = !docPackage.globalFunctions.isEmpty()
+ || !docPackage.globalEnums.isEmpty();
+ const QString globalsPage = moduleName + "_globals.rst"_L1;
+
+ s << ".. container:: hide\n\n" << indent
+ << ".. toctree::\n" << indent
+ << ":maxdepth: 1\n\n";
+ if (hasGlobals)
+ s << globalsPage << '\n';
+ for (const QString &className : std::as_const(docPackage.classPages))
+ s << className << '\n';
+ s << "\n\n" << outdent << outdent << headline("Detailed Description");
+
+ // module doc is always wrong and C++istic, so go straight to the extra directory!
+ QFile moduleDoc(m_options.extraSectionDir + u'/' + moduleName
+ + u".rst"_s);
+ if (moduleDoc.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ s << moduleDoc.readAll();
+ moduleDoc.close();
+ } else {
+ // try the normal way
+ Documentation moduleDoc = m_docParser->retrieveModuleDocumentation(it.key());
+ if (moduleDoc.format() == Documentation::Native) {
+ QString context = it.key();
+ QtXmlToSphinx::stripPythonQualifiers(&context);
+ QtXmlToSphinx x(this, m_options.parameters, moduleDoc.detailed(), context);
+ s << x;
+ } else {
+ s << moduleDoc.detailed();
+ }
+ }
+
+ writeFancyToc(s, "List of Classes", fileListToToc(docPackage.classPages),
+ "class"_L1);
+ writeFancyToc(s, "List of Decorators", fileListToToc(docPackage.decoratorPages),
+ "deco"_L1);
+ writeFancyToc(s, "List of Functions", functionListToToc(docPackage.globalFunctions),
+ "py:func"_L1);
+ writeFancyToc(s, "List of Enumerations", enumListToToc(docPackage.globalEnums),
+ "any"_L1);
+
+ output.done();
+
+ if (hasGlobals)
+ writeGlobals(it.key(), outputDir + u'/' + globalsPage, docPackage);
+ }
+}
+
+void QtDocGenerator::writeGlobals(const QString &package,
+ const QString &fileName,
+ const DocPackage &docPackage)
+{
+ FileOut output(fileName);
+ TextStream &s = output.stream;
+
+ // Write out functions with injected documentation
+ if (!docPackage.globalFunctions.isEmpty()) {
+ s << currentModule(package) << headline("Functions");
+ writeFunctions(s, docPackage.globalFunctions, {}, {});
+ }
+
+ if (!docPackage.globalEnums.isEmpty()) {
+ s << headline("Enumerations");
+ writeEnums(s, docPackage.globalEnums, package);
+ }
+
+ output.done();
+}
+
+static inline QString msgNonExistentAdditionalDocFile(const QString &dir,
+ const QString &fileName)
+{
+ QString result;
+ QTextStream(&result) << "Additional documentation file \""
+ << fileName << "\" does not exist in "
+ << QDir::toNativeSeparators(dir) << '.';
+ return result;
+}
+
+void QtDocGenerator::writeAdditionalDocumentation() const
+{
+ QFile additionalDocumentationFile(m_options.additionalDocumentationList);
+ if (!additionalDocumentationFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ throw Exception(msgCannotOpenForReading(additionalDocumentationFile));
+
+ QDir outDir(outputDirectory());
+ const QString rstSuffix = fileNameSuffix();
+
+ QString errorMessage;
+ int successCount = 0;
+ int count = 0;
+
+ QString targetDir = outDir.absolutePath();
+
+ while (!additionalDocumentationFile.atEnd()) {
+ const QByteArray lineBA = additionalDocumentationFile.readLine().trimmed();
+ if (lineBA.isEmpty() || lineBA.startsWith('#'))
+ continue;
+ const QString line = QFile::decodeName(lineBA);
+ // Parse "[directory]" specification
+ if (line.size() > 2 && line.startsWith(u'[') && line.endsWith(u']')) {
+ const QString dir = line.mid(1, line.size() - 2);
+ if (dir.isEmpty() || dir == u".") {
+ targetDir = outDir.absolutePath();
+ } else {
+ if (!outDir.exists(dir) && !outDir.mkdir(dir)) {
+ const QString m = "Cannot create directory "_L1
+ + dir + " under "_L1
+ + QDir::toNativeSeparators(outputDirectory());
+ throw Exception(m);
+ }
+ targetDir = outDir.absoluteFilePath(dir);
+ }
+ } else {
+ // Normal file entry
+ QFileInfo fi(m_options.parameters.docDataDir + u'/' + line);
+ if (fi.isFile()) {
+ const QString rstFileName = fi.baseName() + rstSuffix;
+ const QString rstFile = targetDir + u'/' + rstFileName;
+ const QString context = targetDir.mid(targetDir.lastIndexOf(u'/') + 1);
+ if (convertToRst(fi.absoluteFilePath(),
+ rstFile, context, &errorMessage)) {
+ ++successCount;
+ qCDebug(lcShibokenDoc).nospace().noquote() << __FUNCTION__
+ << " converted " << fi.fileName()
+ << ' ' << rstFileName;
+ } else {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+ }
+ } else {
+ // FIXME: This should be an exception, in principle, but it
+ // requires building all modules.
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgNonExistentAdditionalDocFile(m_options.parameters.docDataDir, line)));
+ }
+ ++count;
+ }
+ }
+ additionalDocumentationFile.close();
+
+ qCInfo(lcShibokenDoc, "Created %d/%d additional documentation files.",
+ successCount, count);
+}
+
+#ifdef __WIN32__
+# define PATH_SEP ';'
+#else
+# define PATH_SEP ':'
+#endif
+
+bool QtDocGenerator::doSetup()
+{
+ if (m_options.parameters.codeSnippetDirs.isEmpty()) {
+ m_options.parameters.codeSnippetDirs =
+ m_options.parameters.libSourceDir.split(QLatin1Char(PATH_SEP));
+ }
+
+ if (m_docParser.isNull()) {
+ if (m_options.doxygen)
+ m_docParser.reset(new DoxygenParser);
+ else
+ m_docParser.reset(new QtDocParser);
+ }
+
+ if (m_options.parameters.libSourceDir.isEmpty()
+ || m_options.parameters.docDataDir.isEmpty()) {
+ qCWarning(lcShibokenDoc) << "Documentation data dir and/or Qt source dir not informed, "
+ "documentation will not be extracted from Qt sources.";
+ return false;
+ }
+
+ m_docParser->setDocumentationDataDirectory(m_options.parameters.docDataDir);
+ m_docParser->setLibrarySourceDirectory(m_options.parameters.libSourceDir);
+ m_options.parameters.outputDirectory = outputDirectory();
+ return true;
+}
+
+QList<OptionDescription> QtDocGenerator::options()
+{
+ return {
+ {u"doc-parser=<parser>"_s,
+ u"The documentation parser used to interpret the documentation\n"
+ "input files (qdoc|doxygen)"_s},
+ {u"documentation-code-snippets-dir=<dir>"_s,
+ u"Directory used to search code snippets used by the documentation"_s},
+ {u"snippets-path-rewrite=old:new"_s,
+ u"Replacements in code snippet path to find .cpp/.h snippets converted to Python"_s},
+ {u"documentation-data-dir=<dir>"_s,
+ u"Directory with XML files generated by documentation tool"_s},
+ {u"documentation-extra-sections-dir=<dir>"_s,
+ u"Directory used to search for extra documentation sections"_s},
+ {u"library-source-dir=<dir>"_s,
+ u"Directory where library source code is located"_s},
+ {additionalDocumentationOption + u"=<file>"_s,
+ u"List of additional XML files to be converted to .rst files\n"
+ "(for example, tutorials)."_s},
+ {u"inheritance-file=<file>"_s,
+ u"Generate a JSON file containing the class inheritance."_s},
+ {u"disable-inheritance-diagram"_s,
+ u"Disable the generation of the inheritance diagram."_s}
+ };
+}
+
+class QtDocGeneratorOptionsParser : public OptionsParser
+{
+public:
+ explicit QtDocGeneratorOptionsParser(DocGeneratorOptions *o) : m_options(o) {}
+
+ bool handleBoolOption(const QString &key, OptionSource source) override;
+ bool handleOption(const QString &key, const QString &value, OptionSource source) override;
+
+private:
+ DocGeneratorOptions *m_options;
+};
+
+bool QtDocGeneratorOptionsParser::handleBoolOption(const QString &key, OptionSource)
+{
+ if (key == "disable-inheritance-diagram"_L1) {
+ m_options->inheritanceDiagram = false;
+ return true;
+ }
+ return false;
+}
+
+bool QtDocGeneratorOptionsParser::handleOption(const QString &key, const QString &value,
+ OptionSource source)
+{
+ if (source == OptionSource::CommandLineSingleDash)
+ return false;
+ if (key == u"library-source-dir") {
+ m_options->parameters.libSourceDir = value;
+ return true;
+ }
+ if (key == u"documentation-data-dir") {
+ m_options->parameters.docDataDir = value;
+ return true;
+ }
+ if (key == u"documentation-code-snippets-dir") {
+ m_options->parameters.codeSnippetDirs = value.split(QLatin1Char(PATH_SEP));
+ return true;
+ }
+
+ if (key == u"snippets-path-rewrite") {
+ const auto pos = value.indexOf(u':');
+ if (pos == -1)
+ return false;
+ m_options->parameters.codeSnippetRewriteOld= value.left(pos);
+ m_options->parameters.codeSnippetRewriteNew = value.mid(pos + 1);
+ return true;
+ }
+
+ if (key == u"documentation-extra-sections-dir") {
+ m_options->extraSectionDir = value;
+ return true;
+ }
+ if (key == u"doc-parser") {
+ qCDebug(lcShibokenDoc).noquote().nospace() << "doc-parser: " << value;
+ if (value == u"doxygen")
+ m_options->doxygen = true;
+ return true;
+ }
+ if (key == additionalDocumentationOption) {
+ m_options->additionalDocumentationList = value;
+ return true;
+ }
+
+ if (key == u"inheritance-file") {
+ m_options->inheritanceFile = value;
+ return true;
+ }
+
+ return false;
+}
+
+std::shared_ptr<OptionsParser> QtDocGenerator::createOptionsParser()
+{
+ return std::make_shared<QtDocGeneratorOptionsParser>(&m_options);
+}
+
+bool QtDocGenerator::convertToRst(const QString &sourceFileName,
+ const QString &targetFileName,
+ const QString &context,
+ QString *errorMessage) const
+{
+ QFile sourceFile(sourceFileName);
+ if (!sourceFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ if (errorMessage)
+ *errorMessage = msgCannotOpenForReading(sourceFile);
+ return false;
+ }
+ const QString doc = QString::fromUtf8(sourceFile.readAll());
+ sourceFile.close();
+
+ FileOut targetFile(targetFileName);
+ QtXmlToSphinx x(this, m_options.parameters, doc, context);
+ targetFile.stream << x;
+ targetFile.done();
+ return true;
+}
+
+GeneratorDocumentation
+ QtDocGenerator::generatorDocumentation(const AbstractMetaClassCPtr &cppClass)
+{
+ GeneratorDocumentation result;
+ const auto allFunctions = cppClass->functions();
+ result.allFunctions.reserve(allFunctions.size());
+ std::remove_copy_if(allFunctions.cbegin(), allFunctions.cend(),
+ std::back_inserter(result.allFunctions), shouldSkip);
+
+ std::stable_sort(result.allFunctions.begin(), result.allFunctions.end(), functionSort);
+
+ for (const auto &func : std::as_const(result.allFunctions)) {
+ if (func->isStatic())
+ result.tocStaticFunctions.append(func);
+ else if (func->isVirtual())
+ result.tocVirtuals.append(func);
+ else if (func->isSignal())
+ result.tocSignalFunctions.append(func);
+ else if (func->isSlot())
+ result.tocSlotFunctions.append(func);
+ else
+ result.tocNormalFunctions.append(func);
+ }
+
+ // Find the property getters/setters
+ for (const auto &spec: cppClass->propertySpecs()) {
+ GeneratorDocumentation::Property property;
+ property.name = spec.name();
+ property.type = spec.type();
+ property.documentation = spec.documentation();
+ if (!spec.read().isEmpty())
+ property.getter = AbstractMetaFunction::find(result.allFunctions, spec.read());
+ if (!spec.write().isEmpty())
+ property.setter = AbstractMetaFunction::find(result.allFunctions, spec.write());
+ if (!spec.reset().isEmpty())
+ property.reset = AbstractMetaFunction::find(result.allFunctions, spec.reset());
+ if (!spec.notify().isEmpty())
+ property.notify = AbstractMetaFunction::find(result.tocSignalFunctions, spec.notify());
+ result.properties.append(property);
+ }
+ std::sort(result.properties.begin(), result.properties.end());
+
+ return result;
+}
+
+// QtXmlToSphinxDocGeneratorInterface
+QString QtDocGenerator::expandFunction(const QString &function) const
+{
+ const auto firstDot = function.indexOf(u'.');
+ AbstractMetaClassCPtr metaClass;
+ if (firstDot != -1) {
+ const auto className = QStringView{function}.left(firstDot);
+ for (const auto &cls : api().classes()) {
+ if (cls->name() == className) {
+ metaClass = cls;
+ break;
+ }
+ }
+ }
+
+ return metaClass
+ ? metaClass->typeEntry()->qualifiedTargetLangName()
+ + function.right(function.size() - firstDot)
+ : function;
+}
+
+QString QtDocGenerator::expandClass(const QString &context,
+ const QString &name) const
+{
+ if (auto typeEntry = TypeDatabase::instance()->findType(name))
+ return typeEntry->qualifiedTargetLangName();
+ // fall back to the old heuristic if the type wasn't found.
+ QString result = name;
+ const auto rawlinklist = QStringView{name}.split(u'.');
+ QStringList splittedContext = context.split(u'.');
+ if (rawlinklist.size() == 1 || rawlinklist.constFirst() == splittedContext.constLast()) {
+ splittedContext.removeLast();
+ result.prepend(u'~' + splittedContext.join(u'.') + u'.');
+ }
+ return result;
+}
+
+QString QtDocGenerator::resolveContextForMethod(const QString &context,
+ const QString &methodName) const
+{
+ const auto currentClass = QStringView{context}.split(u'.').constLast();
+
+ AbstractMetaClassCPtr metaClass;
+ for (const auto &cls : api().classes()) {
+ if (cls->name() == currentClass) {
+ metaClass = cls;
+ break;
+ }
+ }
+
+ if (metaClass) {
+ AbstractMetaFunctionCList funcList;
+ const auto &methods = metaClass->queryFunctionsByName(methodName);
+ for (const auto &func : methods) {
+ if (methodName == func->name())
+ funcList.append(func);
+ }
+
+ AbstractMetaClassCPtr implementingClass;
+ for (const auto &func : std::as_const(funcList)) {
+ implementingClass = func->implementingClass();
+ if (implementingClass->name() == currentClass)
+ break;
+ }
+
+ if (implementingClass)
+ return implementingClass->typeEntry()->qualifiedTargetLangName();
+ }
+
+ return u'~' + context;
+}
+
+const QLoggingCategory &QtDocGenerator::loggingCategory() const
+{
+ return lcShibokenDoc();
+}
+
+static bool isRelativeHtmlFile(const QString &linkRef)
+{
+ return !linkRef.startsWith(u"http")
+ && (linkRef.endsWith(u".html") || linkRef.contains(u".html#"));
+}
+
+// Resolve relative, local .html documents links to doc.qt.io as they
+// otherwise will not work and neither be found in the HTML tree.
+QtXmlToSphinxLink QtDocGenerator::resolveLink(const QtXmlToSphinxLink &link) const
+{
+ if (link.type != QtXmlToSphinxLink::Reference || !isRelativeHtmlFile(link.linkRef))
+ return link;
+ static const QString prefix = "https://doc.qt.io/qt-"_L1
+ + QString::number(QT_VERSION_MAJOR) + u'/';
+ QtXmlToSphinxLink resolved = link;
+ resolved.type = QtXmlToSphinxLink::External;
+ resolved.linkRef = prefix + link.linkRef;
+ if (resolved.linkText.isEmpty()) {
+ resolved.linkText = link.linkRef;
+ const qsizetype anchor = resolved.linkText.lastIndexOf(u'#');
+ if (anchor != -1)
+ resolved.linkText.truncate(anchor);
+ }
+ 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
new file mode 100644
index 000000000..56e15e2a1
--- /dev/null
+++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
@@ -0,0 +1,130 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#ifndef DOCGENERATOR_H
+#define DOCGENERATOR_H
+
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtCore/QScopedPointer>
+
+#include "generator.h"
+#include "documentation.h"
+#include <optionsparser.h>
+#include "typesystem_enums.h"
+#include "modifications_typedefs.h"
+#include "qtxmltosphinxinterface.h"
+
+class DocParser;
+struct DocGeneratorOptions;
+struct GeneratorDocumentation;
+struct DocPackage;
+
+/**
+* The DocGenerator generates documentation from library being binded.
+*/
+class QtDocGenerator : public Generator, public QtXmlToSphinxDocGeneratorInterface
+{
+public:
+ Q_DISABLE_COPY_MOVE(QtDocGenerator)
+
+ QtDocGenerator();
+ ~QtDocGenerator();
+
+ bool doSetup() override;
+
+ const char* name() const override
+ {
+ return "QtDocGenerator";
+ }
+
+ static QList<OptionDescription> options();
+ static std::shared_ptr<OptionsParser> createOptionsParser();
+
+ // QtXmlToSphinxDocGeneratorInterface
+ QString expandFunction(const QString &function) const override;
+ QString expandClass(const QString &context,
+ const QString &name) const override;
+ QString resolveContextForMethod(const QString &context,
+ 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);
+
+protected:
+ bool shouldGenerate(const TypeEntryCPtr &) const override;
+ static QString fileNameSuffix();
+ QString fileNameForContext(const GeneratorContext &context) const override;
+ void generateClass(TextStream &ts, const GeneratorContext &classContext) override;
+ bool finishGeneration() override;
+
+private:
+ void writeEnums(TextStream &s, const AbstractMetaEnumList &enums,
+ const QString &scope) const;
+
+ void writeFields(TextStream &s, const AbstractMetaClassCPtr &cppClass) const;
+ void writeFunctions(TextStream &s, const AbstractMetaFunctionCList &funcs,
+ const AbstractMetaClassCPtr &cppClass, const QString &scope);
+ void writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaClassCPtr &cppClass = {},
+ const QString &scope = {}, bool indexed = true);
+ void writeFunctionDocumentation(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const DocModificationList &modifications,
+ const QString &scope) const;
+ void writeFunctionParametersType(TextStream &s, const AbstractMetaClassCPtr &cppClass,
+ const AbstractMetaFunctionCPtr &func) const;
+ static void writeFunctionToc(TextStream &s, const QString &title,
+ const AbstractMetaFunctionCList &functions);
+ static void writePropertyToc(TextStream &s,
+ const GeneratorDocumentation &doc);
+ void writeProperties(TextStream &s,
+ const GeneratorDocumentation &doc,
+ const AbstractMetaClassCPtr &cppClass) const;
+ void writeParameterType(TextStream &s, const AbstractMetaClassCPtr &cppClass,
+ const AbstractMetaArgument &arg) const;
+ void writeFormattedText(TextStream &s, const QString &doc,
+ Documentation::Format format,
+ const QString &scope = {}) const;
+ void writeFormattedBriefText(TextStream &s, const Documentation &doc,
+ const QString &scope = {}) const;
+ void writeFormattedDetailedText(TextStream &s, const Documentation &doc,
+ const QString &scope = {}) const;
+
+ bool writeInjectDocumentation(TextStream &s, TypeSystem::DocModificationMode mode,
+ const AbstractMetaClassCPtr &cppClass) const;
+ bool writeInjectDocumentation(TextStream &s, TypeSystem::DocModificationMode mode,
+ const DocModificationList &modifications,
+ const AbstractMetaFunctionCPtr &func,
+ const QString &scope = {}) const;
+ bool writeDocModifications(TextStream &s, const DocModificationList &mods,
+ TypeSystem::DocModificationMode mode,
+ const QString &scope = {}) const;
+ static void writeDocSnips(TextStream &s, const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position, TypeSystem::Language language);
+
+ void writeModuleDocumentation();
+ void writeGlobals(const QString &package, const QString &fileName,
+ const DocPackage &docPackage);
+ void writeAdditionalDocumentation() const;
+ bool writeInheritanceFile();
+
+ QString translateToPythonType(const AbstractMetaType &type,
+ const AbstractMetaClassCPtr &cppClass,
+ bool createRef = true) const;
+
+ bool convertToRst(const QString &sourceFileName,
+ const QString &targetFileName,
+ const QString &context = QString(),
+ QString *errorMessage = nullptr) const;
+
+ static GeneratorDocumentation generatorDocumentation(const AbstractMetaClassCPtr &cppClass);
+
+ QStringList m_functionList;
+ QMap<QString, DocPackage> m_packages;
+ QScopedPointer<DocParser> m_docParser;
+ static DocGeneratorOptions m_options;
+};
+
+#endif // DOCGENERATOR_H
diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp
new file mode 100644
index 000000000..b8fec836c
--- /dev/null
+++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp
@@ -0,0 +1,1643 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qtxmltosphinx.h"
+#include "exception.h"
+#include "qtxmltosphinxinterface.h"
+#include <codesniphelpers.h>
+#include "rstformat.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QHash>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QXmlStreamReader>
+
+using namespace Qt::StringLiterals;
+
+QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &message)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "While handling <";
+ const auto currentTag = reader.name();
+ if (currentTag.isEmpty())
+ str << tag;
+ else
+ str << currentTag;
+ str << "> in " << context << ", line "<< reader.lineNumber()
+ << ": " << message;
+ return result;
+}
+
+QString msgFallbackWarning(const QString &location, const QString &identifier,
+ const QString &fallback)
+{
+ QString message = u"Falling back to \""_s
+ + QDir::toNativeSeparators(fallback) + u"\" for \""_s
+ + location + u'"';
+ if (!identifier.isEmpty())
+ message += u" ["_s + identifier + u']';
+ return message;
+}
+
+QString msgSnippetsResolveError(const QString &path, const QStringList &locations)
+{
+ QString result;
+ QTextStream(&result) << "Could not resolve \"" << path << R"(" in ")"
+ << locations.join(uR"(", ")"_s);
+ return result;
+}
+
+static bool isHttpLink(const QString &ref)
+{
+ return ref.startsWith(u"http://") || ref.startsWith(u"https://");
+}
+
+static QString trimRight(QString s)
+{
+ while (!s.isEmpty() && s.crbegin()->isSpace())
+ s.chop(1);
+ return s;
+}
+
+static QString trimLeadingNewlines(QString s)
+{
+ while (!s.isEmpty() && s.at(0) == u'\n')
+ s.remove(0, 1);
+ return s;
+}
+
+QDebug operator<<(QDebug d, const QtXmlToSphinxLink &l)
+{
+ static const QHash<QtXmlToSphinxLink::Type, const char *> typeName = {
+ {QtXmlToSphinxLink::Method, "Method"},
+ {QtXmlToSphinxLink::Function, "Function"},
+ {QtXmlToSphinxLink::Class, "Class"},
+ {QtXmlToSphinxLink::Attribute, "Attribute"},
+ {QtXmlToSphinxLink::Module, "Module"},
+ {QtXmlToSphinxLink::Reference, "Reference"},
+ {QtXmlToSphinxLink::External, "External"},
+ };
+
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "QtXmlToSphinxLinkContext(" << typeName.value(l.type, "") << ", ref=\""
+ << l.linkRef << '"';
+ if (!l.linkText.isEmpty())
+ d << ", text=\"" << l.linkText << '"';
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug debug, const QtXmlToSphinx::TableCell &c)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Cell(\"" << c.data << '"';
+ if (c.colSpan != 0)
+ debug << ", colSpan=" << c.colSpan;
+ if (c.rowSpan != 0)
+ debug << ", rowSpan=" << c.rowSpan;
+ debug << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const QtXmlToSphinx::Table &t)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ t.formatDebug(debug);
+ return debug;
+}
+
+static const char *linkKeyWord(QtXmlToSphinxLink::Type type)
+{
+ switch (type) {
+ case QtXmlToSphinxLink::Method:
+ return ":meth:";
+ case QtXmlToSphinxLink::Function:
+ return ":func:";
+ case QtXmlToSphinxLink::Class:
+ return ":class:";
+ case QtXmlToSphinxLink::Attribute:
+ return ":attr:";
+ case QtXmlToSphinxLink::Module:
+ return ":mod:";
+ case QtXmlToSphinxLink::Reference:
+ return ":ref:";
+ case QtXmlToSphinxLink::External:
+ break;
+ case QtXmlToSphinxLink::FunctionMask:
+ break;
+ }
+ return "";
+}
+
+TextStream &operator<<(TextStream &str, const QtXmlToSphinxLink &linkContext)
+{
+ // Temporarily turn off bold/italic since links do not work within
+ if (linkContext.flags & QtXmlToSphinxLink::InsideBold)
+ str << "**";
+ else if (linkContext.flags & QtXmlToSphinxLink::InsideItalic)
+ str << '*';
+ str << ' ' << linkKeyWord(linkContext.type) << '`';
+ const bool isExternal = linkContext.type == QtXmlToSphinxLink::External;
+ if (!linkContext.linkText.isEmpty()) {
+ writeEscapedRstText(str, linkContext.linkText);
+ if (isExternal && !linkContext.linkText.endsWith(u' '))
+ str << ' ';
+ str << '<';
+ }
+ // Convert page titles to RST labels
+ str << (linkContext.type == QtXmlToSphinxLink::Reference
+ ? toRstLabel(linkContext.linkRef) : linkContext.linkRef);
+ if (!linkContext.linkText.isEmpty())
+ str << '>';
+ str << '`';
+ if (isExternal)
+ str << '_';
+ str << ' ';
+ if (linkContext.flags & QtXmlToSphinxLink::InsideBold)
+ str << "**";
+ else if (linkContext.flags & QtXmlToSphinxLink::InsideItalic)
+ str << '*';
+ return str;
+}
+
+enum class WebXmlTag {
+ Unknown,
+ heading, brief, para, italic, bold, see_also, snippet, dots, codeline,
+ table, header, row, item, argument, teletype, link, inlineimage, image,
+ list, term, raw, underline, superscript, code, badcode, legalese,
+ rst, section, quotefile,
+ // ignored tags
+ generatedlist, tableofcontents, quotefromfile, skipto, target, page, group,
+ // useless tags
+ description, definition, printuntil, relation,
+ // Doxygen tags
+ title, ref, computeroutput, detaileddescription, name, listitem,
+ parametername, parameteritem, ulink, itemizedlist, parameternamelist,
+ parameterlist,
+ // Doxygen ignored tags
+ highlight, linebreak, programlisting, xreftitle, sp, entry, simplesect,
+ verbatim, xrefsect, xrefdescription,
+};
+
+using WebXmlTagHash = QHash<QStringView, WebXmlTag>;
+
+static const WebXmlTagHash &webXmlTagHash()
+{
+ static const WebXmlTagHash result = {
+ {u"heading", WebXmlTag::heading},
+ {u"brief", WebXmlTag::brief},
+ {u"para", WebXmlTag::para},
+ {u"italic", WebXmlTag::italic},
+ {u"bold", WebXmlTag::bold},
+ {u"see-also", WebXmlTag::see_also},
+ {u"snippet", WebXmlTag::snippet},
+ {u"dots", WebXmlTag::dots},
+ {u"codeline", WebXmlTag::codeline},
+ {u"table", WebXmlTag::table},
+ {u"header", WebXmlTag::header},
+ {u"row", WebXmlTag::row},
+ {u"item", WebXmlTag::item},
+ {u"argument", WebXmlTag::argument},
+ {u"teletype", WebXmlTag::teletype},
+ {u"link", WebXmlTag::link},
+ {u"inlineimage", WebXmlTag::inlineimage},
+ {u"image", WebXmlTag::image},
+ {u"list", WebXmlTag::list},
+ {u"term", WebXmlTag::term},
+ {u"raw", WebXmlTag::raw},
+ {u"underline", WebXmlTag::underline},
+ {u"superscript", WebXmlTag::superscript},
+ {u"code", WebXmlTag::code},
+ {u"badcode", WebXmlTag::badcode},
+ {u"legalese", WebXmlTag::legalese},
+ {u"rst", WebXmlTag::rst},
+ {u"section", WebXmlTag::section},
+ {u"quotefile", WebXmlTag::quotefile},
+ {u"generatedlist", WebXmlTag::generatedlist},
+ {u"tableofcontents", WebXmlTag::tableofcontents},
+ {u"quotefromfile", WebXmlTag::quotefromfile},
+ {u"skipto", WebXmlTag::skipto},
+ {u"target", WebXmlTag::target},
+ {u"page", WebXmlTag::page},
+ {u"group", WebXmlTag::group},
+ {u"description", WebXmlTag::description},
+ {u"definition", WebXmlTag::definition},
+ {u"printuntil", WebXmlTag::printuntil},
+ {u"relation", WebXmlTag::relation},
+ {u"title", WebXmlTag::title},
+ {u"ref", WebXmlTag::ref},
+ {u"computeroutput", WebXmlTag::computeroutput},
+ {u"detaileddescription", WebXmlTag::detaileddescription},
+ {u"name", WebXmlTag::name},
+ {u"listitem", WebXmlTag::listitem},
+ {u"parametername", WebXmlTag::parametername},
+ {u"parameteritem", WebXmlTag::parameteritem},
+ {u"ulink", WebXmlTag::ulink},
+ {u"itemizedlist", WebXmlTag::itemizedlist},
+ {u"parameternamelist", WebXmlTag::parameternamelist},
+ {u"parameterlist", WebXmlTag::parameterlist},
+ {u"highlight", WebXmlTag::highlight},
+ {u"linebreak", WebXmlTag::linebreak},
+ {u"programlisting", WebXmlTag::programlisting},
+ {u"xreftitle", WebXmlTag::xreftitle},
+ {u"sp", WebXmlTag::sp},
+ {u"entry", WebXmlTag::entry},
+ {u"simplesect", WebXmlTag::simplesect},
+ {u"verbatim", WebXmlTag::verbatim},
+ {u"xrefsect", WebXmlTag::xrefsect},
+ {u"xrefdescription", WebXmlTag::xrefdescription},
+ };
+ return result;
+}
+
+QtXmlToSphinx::QtXmlToSphinx(const QtXmlToSphinxDocGeneratorInterface *docGenerator,
+ const QtXmlToSphinxParameters &parameters,
+ const QString& doc, const QString& context)
+ : m_output(static_cast<QString *>(nullptr)),
+ m_context(context),
+ m_generator(docGenerator), m_parameters(parameters)
+{
+ m_result = transform(doc);
+}
+
+QtXmlToSphinx::~QtXmlToSphinx() = default;
+
+void QtXmlToSphinx::callHandler(WebXmlTag t, QXmlStreamReader &r)
+{
+ switch (t) {
+ case WebXmlTag::heading:
+ handleHeadingTag(r);
+ break;
+ case WebXmlTag::brief:
+ case WebXmlTag::para:
+ handleParaTag(r);
+ break;
+ case WebXmlTag::italic:
+ handleItalicTag(r);
+ break;
+ case WebXmlTag::bold:
+ handleBoldTag(r);
+ break;
+ case WebXmlTag::see_also:
+ handleSeeAlsoTag(r);
+ break;
+ case WebXmlTag::snippet:
+ handleSnippetTag(r);
+ break;
+ case WebXmlTag::dots:
+ case WebXmlTag::codeline:
+ handleDotsTag(r);
+ break;
+ case WebXmlTag::table:
+ handleTableTag(r);
+ break;
+ case WebXmlTag::header:
+ handleHeaderTag(r);
+ break;
+ case WebXmlTag::row:
+ handleRowTag(r);
+ break;
+ case WebXmlTag::item:
+ handleItemTag(r);
+ break;
+ case WebXmlTag::argument:
+ handleArgumentTag(r);
+ break;
+ case WebXmlTag::teletype:
+ handleArgumentTag(r);
+ break;
+ case WebXmlTag::link:
+ handleLinkTag(r);
+ break;
+ case WebXmlTag::inlineimage:
+ handleInlineImageTag(r);
+ break;
+ case WebXmlTag::image:
+ handleImageTag(r);
+ break;
+ case WebXmlTag::list:
+ handleListTag(r);
+ break;
+ case WebXmlTag::term:
+ handleTermTag(r);
+ break;
+ case WebXmlTag::raw:
+ handleRawTag(r);
+ break;
+ case WebXmlTag::underline:
+ handleItalicTag(r);
+ break;
+ case WebXmlTag::superscript:
+ handleSuperScriptTag(r);
+ break;
+ case WebXmlTag::code:
+ case WebXmlTag::badcode:
+ case WebXmlTag::legalese:
+ handleCodeTag(r);
+ break;
+ case WebXmlTag::rst:
+ handleRstPassTroughTag(r);
+ break;
+ case WebXmlTag::section:
+ handleAnchorTag(r);
+ break;
+ case WebXmlTag::quotefile:
+ handleQuoteFileTag(r);
+ break;
+ case WebXmlTag::generatedlist:
+ case WebXmlTag::tableofcontents:
+ case WebXmlTag::quotefromfile:
+ case WebXmlTag::skipto:
+ handleIgnoredTag(r);
+ break;
+ case WebXmlTag::target:
+ handleTargetTag(r);
+ break;
+ case WebXmlTag::page:
+ case WebXmlTag::group:
+ handlePageTag(r);
+ break;
+ case WebXmlTag::description:
+ case WebXmlTag::definition:
+ case WebXmlTag::printuntil:
+ case WebXmlTag::relation:
+ handleUselessTag(r);
+ break;
+ case WebXmlTag::title:
+ handleHeadingTag(r);
+ break;
+ case WebXmlTag::ref:
+ case WebXmlTag::computeroutput:
+ case WebXmlTag::detaileddescription:
+ case WebXmlTag::name:
+ handleParaTag(r);
+ break;
+ case WebXmlTag::listitem:
+ case WebXmlTag::parametername:
+ case WebXmlTag::parameteritem:
+ handleItemTag(r);
+ break;
+ case WebXmlTag::ulink:
+ handleLinkTag(r);
+ break;
+ case WebXmlTag::itemizedlist:
+ case WebXmlTag::parameternamelist:
+ case WebXmlTag::parameterlist:
+ handleListTag(r);
+ break;
+ case WebXmlTag::highlight:
+ case WebXmlTag::linebreak:
+ case WebXmlTag::programlisting:
+ case WebXmlTag::xreftitle:
+ case WebXmlTag::sp:
+ case WebXmlTag::entry:
+ case WebXmlTag::simplesect:
+ case WebXmlTag::verbatim:
+ case WebXmlTag::xrefsect:
+ case WebXmlTag::xrefdescription:
+ handleIgnoredTag(r);
+ break;
+ case WebXmlTag::Unknown:
+ break;
+ }
+}
+
+void QtXmlToSphinx::formatCurrentTable()
+{
+ Q_ASSERT(!m_tables.isEmpty());
+ auto &table = m_tables.back();
+ if (table.isEmpty())
+ return;
+ table.normalize();
+ m_output << '\n';
+ table.format(m_output);
+}
+
+void QtXmlToSphinx::pushOutputBuffer()
+{
+ m_buffers.append(std::make_shared<QString>());
+ m_output.setString(m_buffers.top().get());
+}
+
+QString QtXmlToSphinx::popOutputBuffer()
+{
+ Q_ASSERT(!m_buffers.isEmpty());
+ QString result(*m_buffers.top());
+ m_buffers.pop();
+ m_output.setString(m_buffers.isEmpty() ? nullptr : m_buffers.top().get());
+ return result;
+}
+
+constexpr auto autoTranslatedPlaceholder = "AUTO_GENERATED\n"_L1;
+constexpr auto autoTranslatedNote =
+R"(.. warning::
+ This section contains snippets that were automatically
+ translated from C++ to Python and may contain errors.
+
+)"_L1;
+
+void QtXmlToSphinx::setAutoTranslatedNote(QString *str) const
+{
+ if (m_containsAutoTranslations)
+ str->replace(autoTranslatedPlaceholder, autoTranslatedNote);
+ else
+ str->remove(autoTranslatedPlaceholder);
+}
+
+QString QtXmlToSphinx::transform(const QString& doc)
+{
+ Q_ASSERT(m_buffers.isEmpty());
+ if (doc.trimmed().isEmpty())
+ return doc;
+
+ pushOutputBuffer();
+
+ QXmlStreamReader reader(doc);
+
+ m_output << autoTranslatedPlaceholder;
+ Indentation indentation(m_output);
+
+ while (!reader.atEnd()) {
+ QXmlStreamReader::TokenType token = reader.readNext();
+ if (reader.hasError()) {
+ QString message;
+ QTextStream(&message) << "XML Error "
+ << reader.errorString() << " at " << reader.lineNumber()
+ << ':' << reader.columnNumber() << '\n' << doc;
+ m_output << message;
+ throw Exception(message);
+ break;
+ }
+
+ if (token == QXmlStreamReader::StartElement) {
+ WebXmlTag tag = webXmlTagHash().value(reader.name(), WebXmlTag::Unknown);
+ if (!m_tagStack.isEmpty() && tag == WebXmlTag::raw)
+ tag = WebXmlTag::Unknown;
+ m_tagStack.push(tag);
+ }
+
+ if (!m_tagStack.isEmpty())
+ callHandler(m_tagStack.top(), reader);
+
+ if (token == QXmlStreamReader::EndElement) {
+ m_tagStack.pop();
+ m_lastTagName = reader.name().toString();
+ }
+ }
+
+ if (!m_inlineImages.isEmpty()) {
+ // Write out inline image definitions stored in handleInlineImageTag().
+ m_output << '\n' << disableIndent;
+ for (const InlineImage &img : std::as_const(m_inlineImages))
+ m_output << ".. |" << img.tag << "| image:: " << img.href << '\n';
+ m_output << '\n' << enableIndent;
+ m_inlineImages.clear();
+ }
+
+ m_output.flush();
+ QString retval = popOutputBuffer();
+ Q_ASSERT(m_buffers.isEmpty());
+ setAutoTranslatedNote(&retval);
+ return retval;
+}
+
+static QString resolveFile(const QStringList &locations, const QString &path)
+{
+ for (QString location : locations) {
+ location.append(u'/');
+ location.append(path);
+ if (QFileInfo::exists(location))
+ return location;
+ }
+ return QString();
+}
+
+enum class SnippetType
+{
+ Other, // .qdoc, .qml,...
+ CppSource, CppHeader // Potentially converted to Python
+};
+
+SnippetType snippetType(const QString &path)
+{
+ if (path.endsWith(u".cpp"))
+ return SnippetType::CppSource;
+ if (path.endsWith(u".h"))
+ return SnippetType::CppHeader;
+ return SnippetType::Other;
+}
+
+// Return the name of a .cpp/.h snippet converted to Python by snippets-translate
+static QString pySnippetName(const QString &path, SnippetType type)
+{
+ switch (type) {
+ case SnippetType::CppSource:
+ return path.left(path.size() - 3) + u"py"_s;
+ break;
+ case SnippetType::CppHeader:
+ return path + u".py"_s;
+ break;
+ default:
+ break;
+ }
+ return {};
+}
+
+QtXmlToSphinx::Snippet QtXmlToSphinx::readSnippetFromLocations(const QString &path,
+ const QString &identifier,
+ const QString &fallbackPath,
+ QString *errorMessage)
+{
+ // For anything else but C++ header/sources (no conversion to Python),
+ // use existing fallback paths first.
+ const auto type = snippetType(path);
+ if (type == SnippetType::Other && !fallbackPath.isEmpty()) {
+ const QString code = readFromLocation(fallbackPath, identifier, errorMessage);
+ return {code, code.isNull() ? Snippet::Error : Snippet::Fallback};
+ }
+
+ // For C++ header/sources, try snippets converted to Python first.
+ QString resolvedPath;
+ const auto &locations = m_parameters.codeSnippetDirs;
+
+ if (type != SnippetType::Other) {
+ if (!fallbackPath.isEmpty() && !m_parameters.codeSnippetRewriteOld.isEmpty()) {
+ // Try looking up Python converted snippets by rewriting snippets paths
+ QString rewrittenPath = pySnippetName(fallbackPath, type);
+ if (!rewrittenPath.isEmpty()) {
+ rewrittenPath.replace(m_parameters.codeSnippetRewriteOld,
+ m_parameters.codeSnippetRewriteNew);
+ const QString code = readFromLocation(rewrittenPath, identifier, errorMessage);
+ m_containsAutoTranslations = true;
+ return {code, code.isNull() ? Snippet::Error : Snippet::Converted};
+ }
+ }
+
+ resolvedPath = resolveFile(locations, pySnippetName(path, type));
+ if (!resolvedPath.isEmpty()) {
+ const QString code = readFromLocation(resolvedPath, identifier, errorMessage);
+ return {code, code.isNull() ? Snippet::Error : Snippet::Converted};
+ }
+ }
+
+ resolvedPath = resolveFile(locations, path);
+ if (!resolvedPath.isEmpty()) {
+ const QString code = readFromLocation(resolvedPath, identifier, errorMessage);
+ return {code, code.isNull() ? Snippet::Error : Snippet::Resolved};
+ }
+
+ if (!fallbackPath.isEmpty()) {
+ *errorMessage = msgFallbackWarning(path, identifier, fallbackPath);
+ const QString code = readFromLocation(fallbackPath, identifier, errorMessage);
+ return {code, code.isNull() ? Snippet::Error : Snippet::Fallback};
+ }
+
+ *errorMessage = msgSnippetsResolveError(path, locations);
+ return {{}, Snippet::Error};
+}
+
+// Helpers for extracting qdoc snippets "#/// [id]"
+static QString fileNameOfDevice(const QIODevice *inputFile)
+{
+ const auto *file = qobject_cast<const QFile *>(inputFile);
+ return file ? QDir::toNativeSeparators(file->fileName()) : u"<stdin>"_s;
+}
+
+static QString msgSnippetNotFound(const QIODevice &inputFile,
+ const QString &identifier)
+{
+ return u"Code snippet file found ("_s + fileNameOfDevice(&inputFile)
+ + u"), but snippet ["_s + identifier + u"] not found."_s;
+}
+
+static QString msgEmptySnippet(const QIODevice &inputFile, int lineNo,
+ const QString &identifier)
+{
+ return u"Empty code snippet ["_s + identifier + u"] at "_s
+ + fileNameOfDevice(&inputFile) + u':' + QString::number(lineNo);
+}
+
+// Pattern to match qdoc snippet IDs with "#/// [id]" comments and helper to find ID
+static const QRegularExpression &snippetIdPattern()
+{
+ static const QRegularExpression result(uR"RX((//|#) *! *\[([^]]+)\])RX"_s);
+ Q_ASSERT(result.isValid());
+ return result;
+}
+
+static bool matchesSnippetId(QRegularExpressionMatchIterator it,
+ const QString &identifier)
+{
+ while (it.hasNext()) {
+ if (it.next().captured(2) == identifier)
+ return true;
+ }
+ return false;
+}
+
+QString QtXmlToSphinx::readSnippet(QIODevice &inputFile, const QString &identifier,
+ QString *errorMessage)
+{
+ const QByteArray identifierBA = identifier.toUtf8();
+ // Lambda that matches the snippet id
+ const auto snippetIdPred = [&identifierBA, &identifier](const QByteArray &lineBA)
+ {
+ const bool isComment = lineBA.contains('/') || lineBA.contains('#');
+ if (!isComment || !lineBA.contains(identifierBA))
+ return false;
+ const QString line = QString::fromUtf8(lineBA);
+ return matchesSnippetId(snippetIdPattern().globalMatch(line), identifier);
+ };
+
+ // Find beginning, skip over
+ int lineNo = 1;
+ for (; !inputFile.atEnd() && !snippetIdPred(inputFile.readLine());
+ ++lineNo) {
+ }
+
+ if (inputFile.atEnd()) {
+ *errorMessage = msgSnippetNotFound(inputFile, identifier);
+ return {};
+ }
+
+ QString code;
+ for (; !inputFile.atEnd(); ++lineNo) {
+ const QString line = QString::fromUtf8(inputFile.readLine());
+ auto it = snippetIdPattern().globalMatch(line);
+ if (it.hasNext()) { // Skip snippet id lines
+ if (matchesSnippetId(it, identifier))
+ break;
+ } else {
+ code += line;
+ }
+ }
+
+ if (code.isEmpty())
+ *errorMessage = msgEmptySnippet(inputFile, lineNo, identifier);
+
+ return code;
+}
+
+QString QtXmlToSphinx::readFromLocation(const QString &location, const QString &identifier,
+ QString *errorMessage)
+{
+ QFile inputFile;
+ inputFile.setFileName(location);
+ if (!inputFile.open(QIODevice::ReadOnly)) {
+ QTextStream(errorMessage) << "Could not read code snippet file: "
+ << QDir::toNativeSeparators(inputFile.fileName())
+ << ": " << inputFile.errorString();
+ return {}; // null
+ }
+
+ QString code = u""_s; // non-null
+ if (identifier.isEmpty()) {
+ while (!inputFile.atEnd())
+ code += QString::fromUtf8(inputFile.readLine());
+ return CodeSnipHelpers::fixSpaces(code);
+ }
+
+ code = readSnippet(inputFile, identifier, errorMessage);
+ return code.isEmpty() ? QString{} : CodeSnipHelpers::fixSpaces(code); // maintain isNull()
+}
+
+void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader)
+{
+ static int headingSize = 0;
+ static char type;
+ static char types[] = { '-', '^' };
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ uint typeIdx = reader.attributes().value(u"level"_s).toUInt();
+ if (typeIdx >= sizeof(types))
+ type = types[sizeof(types)-1];
+ else
+ type = types[typeIdx];
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << disableIndent << Pad(type, headingSize) << "\n\n"
+ << enableIndent;
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << "\n\n" << disableIndent;
+ headingSize = writeEscapedRstText(m_output, reader.text().trimmed());
+ m_output << '\n' << enableIndent;
+ }
+}
+
+void QtXmlToSphinx::handleParaTag(QXmlStreamReader& reader)
+{
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ handleParaTagStart();
+ break;
+ case QXmlStreamReader::EndElement:
+ handleParaTagEnd();
+ break;
+ case QXmlStreamReader::Characters:
+ handleParaTagText(reader);
+ break;
+ default:
+ break;
+ }
+}
+
+void QtXmlToSphinx::handleParaTagStart()
+{
+ pushOutputBuffer();
+}
+
+void QtXmlToSphinx::handleParaTagText(QXmlStreamReader& reader)
+{
+ const auto text = reader.text();
+ const QChar end = m_output.lastChar();
+ if (!text.isEmpty() && m_output.indentation() == 0 && !end.isNull()) {
+ QChar start = text[0];
+ if ((end == u'*' || end == u'`') && start != u' ' && !start.isPunct())
+ m_output << '\\';
+ }
+ m_output << escape(text);
+}
+
+void QtXmlToSphinx::handleParaTagEnd()
+{
+ QString result = popOutputBuffer().simplified();
+ if (result.startsWith(u"**Warning:**"))
+ result.replace(0, 12, ".. warning:: "_L1);
+ else if (result.startsWith(u"**Note:**"))
+ result.replace(0, 9, ".. note:: "_L1);
+ m_output << result << "\n\n";
+}
+
+void QtXmlToSphinx::handleItalicTag(QXmlStreamReader& reader)
+{
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (m_formattingDepth++ == 0) {
+ m_insideItalic = true;
+ m_output << rstItalic;
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ if (--m_formattingDepth == 0) {
+ m_insideItalic = false;
+ m_output << rstItalicOff;
+ }
+ break;
+ case QXmlStreamReader::Characters:
+ m_output << escape(reader.text().trimmed());
+ break;
+ default:
+ break;
+ }
+}
+
+void QtXmlToSphinx::handleBoldTag(QXmlStreamReader& reader)
+{
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (m_formattingDepth++ == 0) {
+ m_insideBold = true;
+ m_output << rstBold;
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ if (--m_formattingDepth == 0) {
+ m_insideBold = false;
+ m_output << rstBoldOff;
+ }
+ break;
+ case QXmlStreamReader::Characters:
+ m_output << escape(reader.text().trimmed());
+ break;
+ default:
+ break;
+ }
+}
+
+void QtXmlToSphinx::handleArgumentTag(QXmlStreamReader& reader)
+{
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (m_formattingDepth++ == 0)
+ m_output << rstCode;
+ break;
+ case QXmlStreamReader::EndElement:
+ if (--m_formattingDepth == 0)
+ m_output << rstCodeOff;
+ break;
+ case QXmlStreamReader::Characters:
+ m_output << reader.text().trimmed();
+ break;
+ default:
+ break;
+ }
+}
+
+constexpr auto functionLinkType = "function"_L1;
+constexpr auto classLinkType = "class"_L1;
+
+static inline QString fixLinkType(QStringView type)
+{
+ // TODO: create a flag PROPERTY-AS-FUNCTION to ask if the properties
+ // are recognized as such or not in the binding
+ if (type == u"property")
+ return functionLinkType;
+ if (type == u"typedef")
+ return classLinkType;
+ return type.toString();
+}
+
+static inline QString linkSourceAttribute(const QString &type)
+{
+ if (type == functionLinkType || type == classLinkType)
+ return u"raw"_s;
+ return type == u"enum" || type == u"page"
+ ? type : u"href"_s;
+}
+
+// "See also" links may appear as nested links:
+// <see-also>QAbstractXmlReceiver<link raw="isValid()" href="qxmlquery.html#isValid" type="function">isValid()</link>
+// which is handled in handleLinkTag
+// or direct text:
+// <see-also>rootIsDecorated()</see-also>
+// which is handled here.
+
+void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
+{
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ m_output << ".. seealso:: ";
+ break;
+ case QXmlStreamReader::Characters: {
+ // Direct embedded link: <see-also>rootIsDecorated()</see-also>
+ const auto textR = reader.text().trimmed();
+ if (!textR.isEmpty()) {
+ const QString text = textR.toString();
+ if (m_seeAlsoContext.isNull()) {
+ const QString type = text.endsWith(u"()")
+ ? functionLinkType : classLinkType;
+ m_seeAlsoContext.reset(handleLinkStart(type, text));
+ }
+ handleLinkText(m_seeAlsoContext.data(), text);
+ }
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ if (!m_seeAlsoContext.isNull()) { // direct, no nested </link> seen
+ handleLinkEnd(m_seeAlsoContext.data());
+ m_seeAlsoContext.reset();
+ }
+ m_output << "\n\n";
+ break;
+ default:
+ break;
+ }
+}
+
+constexpr auto fallbackPathAttribute = "path"_L1;
+
+template <class Indent> // const char*/class Indentor
+void formatSnippet(TextStream &str, Indent indent, const QString &snippet)
+{
+ const auto lines = QStringView{snippet}.split(u'\n');
+ for (const auto &line : lines) {
+ if (!line.trimmed().isEmpty())
+ str << indent << line;
+ str << '\n';
+ }
+}
+
+static QString msgSnippetComparison(const QString &location, const QString &identifier,
+ const QString &pythonCode, const QString &fallbackCode)
+{
+ StringStream str;
+ str.setTabWidth(2);
+ str << "Python snippet " << location;
+ if (!identifier.isEmpty())
+ str << " [" << identifier << ']';
+ str << ":\n" << indent << pythonCode << ensureEndl << outdent
+ << "Corresponding fallback snippet:\n"
+ << indent << fallbackCode << ensureEndl << outdent << "-- end --\n";
+ return str;
+}
+
+void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ const bool consecutiveSnippet = m_lastTagName == u"snippet"
+ || m_lastTagName == u"dots" || m_lastTagName == u"codeline";
+ if (consecutiveSnippet) {
+ m_output.flush();
+ m_output.string()->chop(1); // Strip newline from previous snippet
+ }
+ QString location = reader.attributes().value(u"location"_s).toString();
+ QString identifier = reader.attributes().value(u"identifier"_s).toString();
+ QString fallbackPath;
+ if (reader.attributes().hasAttribute(fallbackPathAttribute))
+ fallbackPath = reader.attributes().value(fallbackPathAttribute).toString();
+ QString errorMessage;
+
+ const Snippet snippet = readSnippetFromLocations(location, identifier,
+ fallbackPath, &errorMessage);
+ if (!errorMessage.isEmpty())
+ warn(msgTagWarning(reader, m_context, m_lastTagName, errorMessage));
+
+ if (m_parameters.snippetComparison && snippet.result == Snippet::Converted
+ && !fallbackPath.isEmpty()) {
+ const QString fallbackCode = readFromLocation(fallbackPath, identifier, &errorMessage);
+ debug(msgSnippetComparison(location, identifier, snippet.code, fallbackCode));
+ }
+
+ if (!consecutiveSnippet)
+ m_output << "::\n\n";
+
+ Indentation indentation(m_output);
+ if (snippet.result == Snippet::Error)
+ m_output << "<Code snippet \"" << location << ':' << identifier << "\" not found>\n";
+ else
+ m_output << snippet.code << ensureEndl;
+ m_output << '\n';
+ }
+}
+
+void QtXmlToSphinx::handleDotsTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ const bool consecutiveSnippet = m_lastTagName == u"snippet"
+ || m_lastTagName == u"dots" || m_lastTagName == u"codeline";
+ if (consecutiveSnippet) {
+ m_output.flush();
+ m_output.string()->chop(2);
+ } else {
+ m_output << "::\n\n";
+ }
+ pushOutputBuffer();
+ int indent = reader.attributes().value(u"indent"_s).toInt()
+ + m_output.indentation() * m_output.tabWidth();
+ for (int i = 0; i < indent; ++i)
+ m_output << ' ';
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << reader.text().toString().trimmed();
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << disableIndent << popOutputBuffer() << "\n\n\n" << enableIndent;
+ }
+}
+
+void QtXmlToSphinx::handleTableTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ if (parentTag() == WebXmlTag::para)
+ handleParaTagEnd(); // End <para> to prevent the table from being rst-escaped
+ m_tables.push({});
+ } else if (token == QXmlStreamReader::EndElement) {
+ // write the table on m_output
+ formatCurrentTable();
+ m_tables.pop();
+ if (parentTag() == WebXmlTag::para)
+ handleParaTagStart();
+ }
+}
+
+void QtXmlToSphinx::handleTermTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << reader.text().toString().replace(u"::"_s, u"."_s);
+ } else if (token == QXmlStreamReader::EndElement) {
+ TableCell cell;
+ cell.data = popOutputBuffer().trimmed();
+ m_tables.back().appendRow(TableRow(1, cell));
+ }
+}
+
+
+void QtXmlToSphinx::handleItemTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ auto &table = m_tables.back();
+ if (table.isEmpty())
+ table.appendRow({});
+ TableRow& row = table.last();
+ TableCell cell;
+ cell.colSpan = reader.attributes().value(u"colspan"_s).toShort();
+ cell.rowSpan = reader.attributes().value(u"rowspan"_s).toShort();
+ row << cell;
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::EndElement) {
+ QString data = trimLeadingNewlines(trimRight(popOutputBuffer()));
+ auto &table = m_tables.back();
+ if (!table.isEmpty()) {
+ TableRow& row = table.last();
+ if (!row.isEmpty())
+ row.last().data = data;
+ }
+ }
+}
+
+void QtXmlToSphinx::handleHeaderTag(QXmlStreamReader &reader)
+{
+ // <header> in WebXML is either a table header or a description of a
+ // C++ header with "name"/"href" attributes.
+ if (reader.tokenType() == QXmlStreamReader::StartElement
+ && !reader.attributes().hasAttribute(u"name"_s)) {
+ auto &table = m_tables.back();
+ table.setHeaderEnabled(true);
+ table.appendRow({});
+ }
+}
+
+void QtXmlToSphinx::handleRowTag(QXmlStreamReader& reader)
+{
+ if (reader.tokenType() == QXmlStreamReader::StartElement)
+ m_tables.back().appendRow({});
+}
+
+enum ListType { BulletList, OrderedList, EnumeratedList };
+
+static inline ListType webXmlListType(QStringView t)
+{
+ if (t == u"enum")
+ return EnumeratedList;
+ if (t == u"ordered")
+ return OrderedList;
+ return BulletList;
+}
+
+void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader)
+{
+ static ListType listType = BulletList;
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ m_tables.push({});
+ auto &table = m_tables.back();
+ listType = webXmlListType(reader.attributes().value(u"type"_s));
+ if (listType == EnumeratedList) {
+ table.appendRow(TableRow{TableCell(u"Constant"_s),
+ TableCell(u"Description"_s)});
+ table.setHeaderEnabled(true);
+ }
+ m_output.indent();
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output.outdent();
+ const auto &table = m_tables.back();
+ if (!table.isEmpty()) {
+ switch (listType) {
+ case BulletList:
+ case OrderedList: {
+ m_output << '\n';
+ const char *separator = listType == BulletList ? "* " : "#. ";
+ const char *indentLine = listType == BulletList ? " " : " ";
+ for (const TableCell &cell : table.constFirst()) {
+ const auto itemLines = QStringView{cell.data}.split(u'\n');
+ m_output << separator << itemLines.constFirst() << '\n';
+ for (qsizetype i = 1, max = itemLines.size(); i < max; ++i)
+ m_output << indentLine << itemLines[i] << '\n';
+ }
+ m_output << '\n';
+ }
+ break;
+ case EnumeratedList:
+ formatCurrentTable();
+ break;
+ }
+ }
+ m_tables.pop();
+ }
+}
+
+void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader)
+{
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement: {
+ // <link> embedded in <see-also> means the characters of <see-also> are no link.
+ m_seeAlsoContext.reset();
+ const QString type = fixLinkType(reader.attributes().value(u"type"_s));
+ const QString ref = reader.attributes().value(linkSourceAttribute(type)).toString();
+ m_linkContext.reset(handleLinkStart(type, ref));
+ }
+ break;
+ case QXmlStreamReader::Characters:
+ Q_ASSERT(!m_linkContext.isNull());
+ handleLinkText(m_linkContext.data(), reader.text().toString());
+ break;
+ case QXmlStreamReader::EndElement:
+ Q_ASSERT(!m_linkContext.isNull());
+ handleLinkEnd(m_linkContext.data());
+ m_linkContext.reset();
+ break;
+ default:
+ break;
+ }
+}
+
+QtXmlToSphinxLink *QtXmlToSphinx::handleLinkStart(const QString &type, QString ref) const
+{
+ ref.replace(u"::"_s, u"."_s);
+ ref.remove(u"()"_s);
+ auto *result = new QtXmlToSphinxLink(ref);
+
+ if (m_insideBold)
+ result->flags |= QtXmlToSphinxLink::InsideBold;
+ else if (m_insideItalic)
+ result->flags |= QtXmlToSphinxLink::InsideItalic;
+
+ if (type == u"external" || isHttpLink(ref)) {
+ result->type = QtXmlToSphinxLink::External;
+ } else if (type == functionLinkType && !m_context.isEmpty()) {
+ result->type = QtXmlToSphinxLink::Method;
+ const auto rawlinklist = QStringView{result->linkRef}.split(u'.');
+ if (rawlinklist.size() == 1 || rawlinklist.constFirst() == m_context) {
+ const auto lastRawLink = rawlinklist.constLast().toString();
+ QString context = m_generator->resolveContextForMethod(m_context, lastRawLink);
+ if (!result->linkRef.startsWith(context))
+ result->linkRef.prepend(context + u'.');
+ } else {
+ result->linkRef = m_generator->expandFunction(result->linkRef);
+ }
+ } else if (type == functionLinkType && m_context.isEmpty()) {
+ result->type = QtXmlToSphinxLink::Function;
+ } else if (type == classLinkType) {
+ result->type = QtXmlToSphinxLink::Class;
+ result->linkRef = m_generator->expandClass(m_context, result->linkRef);
+ } else if (type == u"enum") {
+ result->type = QtXmlToSphinxLink::Attribute;
+ } else if (type == u"page") {
+ // Module, external web page or reference
+ if (result->linkRef == m_parameters.moduleName)
+ result->type = QtXmlToSphinxLink::Module;
+ else
+ result->type = QtXmlToSphinxLink::Reference;
+ } else {
+ result->type = QtXmlToSphinxLink::Reference;
+ }
+ return result;
+}
+
+// <link raw="Model/View Classes" href="model-view-programming.html#model-view-classes"
+// type="page" page="Model/View Programming">Model/View Classes</link>
+// <link type="page" page="https://doc.qt.io/qt-5/class.html">QML types</link>
+// <link raw="Qt Quick" href="qtquick-index.html" type="page" page="Qt Quick">Qt Quick</link>
+// <link raw="QObject" href="qobject.html" type="class">QObject</link>
+// <link raw="Qt::Window" href="qt.html#WindowType-enum" type="enum" enum="Qt::WindowType">Qt::Window</link>
+// <link raw="QNetworkSession::reject()" href="qnetworksession.html#reject" type="function">QNetworkSession::reject()</link>
+
+static QString fixLinkText(const QtXmlToSphinxLink *linkContext,
+ QString linktext)
+{
+ if (linkContext->type == QtXmlToSphinxLink::External
+ || linkContext->type == QtXmlToSphinxLink::Reference) {
+ return linktext;
+ }
+ // For the language reference documentation, strip the module name.
+ // Clear the link text if that matches the function/class/enumeration name.
+ const int lastSep = linktext.lastIndexOf(u"::");
+ if (lastSep != -1)
+ linktext.remove(0, lastSep + 2);
+ else
+ QtXmlToSphinx::stripPythonQualifiers(&linktext);
+ if (linkContext->linkRef == linktext)
+ return {};
+ if ((linkContext->type & QtXmlToSphinxLink::FunctionMask) != 0
+ && (linkContext->linkRef + u"()"_s) == linktext) {
+ return {};
+ }
+ return linktext;
+}
+
+void QtXmlToSphinx::handleLinkText(QtXmlToSphinxLink *linkContext, const QString &linktext)
+{
+ linkContext->linkText = fixLinkText(linkContext, linktext);
+}
+
+void QtXmlToSphinx::handleLinkEnd(QtXmlToSphinxLink *linkContext)
+{
+ m_output << m_generator->resolveLink(*linkContext);
+}
+
+WebXmlTag QtXmlToSphinx::parentTag() const
+{
+ const auto index = m_tagStack.size() - 2;
+ return index >= 0 ? m_tagStack.at(index) : WebXmlTag::Unknown;
+}
+
+// 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 &docDataDir, const QString &relativeSourceFile,
+ const QString &outputDir, const QString &relativeTargetFile,
+ const QLoggingCategory &lc, QString *errorMessage)
+{
+ QString targetFileName = outputDir + u'/' + relativeTargetFile;
+ if (QFileInfo::exists(targetFileName))
+ return true;
+
+ 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)
+ << " under " << QDir::toNativeSeparators(outputDir);
+ return false;
+ }
+ }
+
+ 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__ << " \"" << relativeSourceFile
+ << "\"->\"" << relativeTargetFile << '"';
+ return true;
+}
+
+bool QtXmlToSphinx::copyImage(const QString &href) const
+{
+ QString 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;
+}
+
+void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader)
+{
+ if (reader.tokenType() != QXmlStreamReader::StartElement)
+ return;
+ const QString href = reader.attributes().value(u"href"_s).toString();
+ if (copyImage(href))
+ m_output << ".. image:: " << href << "\n\n";
+}
+
+void QtXmlToSphinx::handleInlineImageTag(QXmlStreamReader& reader)
+{
+ if (reader.tokenType() != QXmlStreamReader::StartElement)
+ return;
+ const QString href = reader.attributes().value(u"href"_s).toString();
+ if (!copyImage(href))
+ return;
+ // Handle inline images by substitution references. Insert a unique tag
+ // enclosed by '|' and define it further down. Determine tag from the base
+ //file name with number.
+ QString tag = href;
+ auto pos = tag.lastIndexOf(u'/');
+ if (pos != -1)
+ tag.remove(0, pos + 1);
+ pos = tag.indexOf(u'.');
+ if (pos != -1)
+ tag.truncate(pos);
+ tag += QString::number(m_inlineImages.size() + 1);
+ m_inlineImages.append(InlineImage{tag, href});
+ m_output << '|' << tag << '|' << ' ';
+}
+
+void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString format = reader.attributes().value(u"format"_s).toString();
+ m_output << ".. raw:: " << format.toLower() << "\n\n";
+ } else if (token == QXmlStreamReader::Characters) {
+ Indentation indent(m_output);
+ m_output << reader.text();
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << "\n\n";
+ }
+}
+
+void QtXmlToSphinx::handleCodeTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ m_output << "::\n\n" << indent;
+ } else if (token == QXmlStreamReader::Characters) {
+ Indentation indent(m_output);
+ m_output << reader.text();
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << outdent << "\n\n";
+ }
+}
+
+void QtXmlToSphinx::handleUnknownTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ qCDebug(m_generator->loggingCategory()).noquote().nospace()
+ << "Unknown QtDoc tag: \"" << reader.name().toString() << "\".";
+ }
+}
+
+void QtXmlToSphinx::handleSuperScriptTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ m_output << " :sup:`";
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << reader.text().toString();
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << popOutputBuffer();
+ m_output << '`';
+ }
+}
+
+void QtXmlToSphinx::handlePageTag(QXmlStreamReader &reader)
+{
+ if (reader.tokenType() != QXmlStreamReader::StartElement)
+ return;
+
+ m_output << disableIndent;
+
+ const auto title = reader.attributes().value("title");
+ if (!title.isEmpty())
+ m_output << rstLabel(title.toString());
+
+ const auto fullTitle = reader.attributes().value("fulltitle");
+ const int size = fullTitle.isEmpty()
+ ? writeEscapedRstText(m_output, title)
+ : writeEscapedRstText(m_output, fullTitle);
+
+ m_output << '\n' << Pad('*', size) << "\n\n"
+ << enableIndent;
+}
+
+void QtXmlToSphinx::handleTargetTag(QXmlStreamReader &reader)
+{
+ if (reader.tokenType() != QXmlStreamReader::StartElement)
+ return;
+ const auto name = reader.attributes().value("name");
+ if (!name.isEmpty())
+ m_output << rstLabel(name.toString());
+}
+
+void QtXmlToSphinx::handleIgnoredTag(QXmlStreamReader&)
+{
+}
+
+void QtXmlToSphinx::handleUselessTag(QXmlStreamReader&)
+{
+ // Tag "description" just marks the init of "Detailed description" title.
+ // Tag "definition" just marks enums. We have a different way to process them.
+}
+
+void QtXmlToSphinx::handleAnchorTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString anchor;
+ if (reader.attributes().hasAttribute(u"id"_s))
+ anchor = reader.attributes().value(u"id"_s).toString();
+ else if (reader.attributes().hasAttribute(u"name"_s))
+ anchor = reader.attributes().value(u"name"_s).toString();
+ if (!anchor.isEmpty() && m_opened_anchor != anchor) {
+ m_opened_anchor = anchor;
+ if (!m_context.isEmpty())
+ anchor.prepend(m_context + u'_');
+ m_output << rstLabel(anchor);
+ }
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_opened_anchor.clear();
+ }
+}
+
+void QtXmlToSphinx::handleRstPassTroughTag(QXmlStreamReader& reader)
+{
+ if (reader.tokenType() == QXmlStreamReader::Characters)
+ m_output << reader.text();
+}
+
+void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::Characters) {
+ QString location = reader.text().toString();
+ location.prepend(m_parameters.libSourceDir + u'/');
+ QString errorMessage;
+ QString code = readFromLocation(location, QString(), &errorMessage);
+ if (!errorMessage.isEmpty())
+ warn(msgTagWarning(reader, m_context, m_lastTagName, errorMessage));
+ m_output << "::\n\n";
+ Indentation indentation(m_output);
+ if (code.isEmpty())
+ m_output << "<Code snippet \"" << location << "\" not found>\n";
+ else
+ m_output << code << ensureEndl;
+ m_output << '\n';
+ }
+}
+
+bool QtXmlToSphinx::Table::hasEmptyLeadingRow() const
+{
+ return !m_rows.isEmpty() && m_rows.constFirst().isEmpty();
+}
+
+bool QtXmlToSphinx::Table::hasEmptyTrailingRow() const
+{
+ return !m_rows.isEmpty() && m_rows.constLast().isEmpty();
+}
+
+void QtXmlToSphinx::Table::normalize()
+{
+ if (m_normalized)
+ return;
+
+ // Empty leading/trailing rows have been observed with nested tables
+ if (hasEmptyLeadingRow() || hasEmptyLeadingRow()) {
+ qWarning() << "QtXmlToSphinx: Table with leading/trailing empty columns found: " << *this;
+ while (hasEmptyTrailingRow())
+ m_rows.pop_back();
+ while (hasEmptyLeadingRow())
+ m_rows.pop_front();
+ }
+
+ if (isEmpty())
+ return;
+
+ //QDoc3 generates tables with wrong number of columns. We have to
+ //check and if necessary, merge the last columns.
+ qsizetype maxCols = -1;
+ for (const auto &row : std::as_const(m_rows)) {
+ if (row.size() > maxCols)
+ maxCols = row.size();
+ }
+ if (maxCols <= 0)
+ return;
+ // add col spans
+ for (qsizetype row = 0; row < m_rows.size(); ++row) {
+ for (qsizetype col = 0; col < m_rows.at(row).size(); ++col) {
+ QtXmlToSphinx::TableCell& cell = m_rows[row][col];
+ bool mergeCols = (col >= maxCols);
+ if (cell.colSpan > 0) {
+ QtXmlToSphinx::TableCell newCell;
+ newCell.colSpan = -1;
+ for (int i = 0, max = cell.colSpan-1; i < max; ++i)
+ m_rows[row].insert(col + 1, newCell);
+ cell.colSpan = 0;
+ col++;
+ } else if (mergeCols) {
+ m_rows[row][maxCols - 1].data += u' ' + cell.data;
+ }
+ }
+ }
+
+ // row spans
+ const qsizetype numCols = m_rows.constFirst().size();
+ for (qsizetype col = 0; col < numCols; ++col) {
+ for (qsizetype row = 0; row < m_rows.size(); ++row) {
+ if (col < m_rows[row].size()) {
+ QtXmlToSphinx::TableCell& cell = m_rows[row][col];
+ if (cell.rowSpan > 0) {
+ QtXmlToSphinx::TableCell newCell;
+ newCell.rowSpan = -1;
+ qsizetype targetRow = row + 1;
+ const qsizetype targetEndRow =
+ std::min(targetRow + cell.rowSpan - 1, m_rows.size());
+ cell.rowSpan = 0;
+ for ( ; targetRow < targetEndRow; ++targetRow)
+ m_rows[targetRow].insert(col, newCell);
+ row++;
+ }
+ }
+ }
+ }
+ m_normalized = true;
+}
+
+void QtXmlToSphinx::Table::format(TextStream& s) const
+{
+ if (isEmpty())
+ return;
+
+ Q_ASSERT(isNormalized());
+
+ // calc width and height of each column and row
+ const qsizetype headerColumnCount = m_rows.constFirst().size();
+ QList<qsizetype> colWidths(headerColumnCount, 0);
+ QList<qsizetype> rowHeights(m_rows.size(), 0);
+ for (qsizetype i = 0, maxI = m_rows.size(); i < maxI; ++i) {
+ const QtXmlToSphinx::TableRow& row = m_rows.at(i);
+ for (qsizetype j = 0, maxJ = std::min(row.size(), colWidths.size()); j < maxJ; ++j) {
+ // cache this would be a good idea
+ const auto rowLines = QStringView{row[j].data}.split(u'\n');
+ for (const auto &str : rowLines)
+ colWidths[j] = std::max(colWidths[j], str.size());
+ rowHeights[i] = std::max(rowHeights[i], rowLines.size());
+ }
+ }
+
+ if (!*std::max_element(colWidths.begin(), colWidths.end()))
+ return; // empty table (table with empty cells)
+
+ // create a horizontal line to be used later.
+ QString horizontalLine = u"+"_s;
+ for (auto colWidth : colWidths)
+ horizontalLine += QString(colWidth, u'-') + u'+';
+
+ // write table rows
+ for (qsizetype i = 0, maxI = m_rows.size(); i < maxI; ++i) { // for each row
+ const QtXmlToSphinx::TableRow& row = m_rows.at(i);
+
+ // print line
+ s << '+';
+ for (qsizetype col = 0; col < headerColumnCount; ++col) {
+ char c = '-';
+ if (col >= row.size() || row[col].rowSpan == -1)
+ c = ' ';
+ else if (i == 1 && hasHeader())
+ c = '=';
+ s << Pad(c, colWidths.at(col)) << '+';
+ }
+ s << '\n';
+
+
+ // Print the table cells
+ for (qsizetype rowLine = 0; rowLine < rowHeights.at(i); ++rowLine) { // for each line in a row
+ qsizetype j = 0;
+ for (qsizetype maxJ = std::min(row.size(), headerColumnCount); j < maxJ; ++j) { // for each column
+ const QtXmlToSphinx::TableCell& cell = row[j];
+ // FIXME: Cache this!!!
+ const auto rowLines = QStringView{cell.data}.split(u'\n');
+
+ if (!j || !cell.colSpan)
+ s << '|';
+ else
+ s << ' ';
+ const auto width = int(colWidths.at(j));
+ if (rowLine < rowLines.size())
+ s << AlignedField(rowLines.at(rowLine), width);
+ else
+ s << Pad(' ', width);
+ }
+ for ( ; j < headerColumnCount; ++j) // pad
+ s << '|' << Pad(' ', colWidths.at(j));
+ s << "|\n";
+ }
+ }
+ s << horizontalLine << "\n\n";
+}
+
+void QtXmlToSphinx::Table::formatDebug(QDebug &debug) const
+{
+ const auto rowCount = m_rows.size();
+ debug << "Table(" <<rowCount << " rows";
+ if (m_hasHeader)
+ debug << ", [header]";
+ if (m_normalized)
+ debug << ", [normalized]";
+ for (qsizetype r = 0; r < rowCount; ++r) {
+ const auto &row = m_rows.at(r);
+ const auto &colCount = row.size();
+ debug << ", row " << r << " [" << colCount << "]={";
+ for (qsizetype c = 0; c < colCount; ++c) {
+ if (c > 0)
+ debug << ", ";
+ debug << row.at(c);
+ }
+ debug << '}';
+ }
+ debug << ')';
+}
+
+void QtXmlToSphinx::stripPythonQualifiers(QString *s)
+{
+ const int lastSep = s->lastIndexOf(u'.');
+ if (lastSep != -1)
+ s->remove(0, lastSep + 1);
+}
+
+void QtXmlToSphinx::warn(const QString &message) const
+{
+ qCWarning(m_generator->loggingCategory(), "%s", qPrintable(message));
+}
+
+void QtXmlToSphinx::debug(const QString &message) const
+{
+ qCDebug(m_generator->loggingCategory(), "%s", qPrintable(message));
+}
diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h
new file mode 100644
index 000000000..398c5bc97
--- /dev/null
+++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h
@@ -0,0 +1,216 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QTXMLTOSPHINX_H
+#define QTXMLTOSPHINX_H
+
+#include <textstream.h>
+
+#include <QtCore/QList>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QStack>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+class QXmlStreamReader;
+QT_END_NAMESPACE
+
+class QtXmlToSphinxDocGeneratorInterface;
+struct QtXmlToSphinxParameters;
+struct QtXmlToSphinxLink;
+
+enum class WebXmlTag;
+
+class QtXmlToSphinx
+{
+public:
+ Q_DISABLE_COPY_MOVE(QtXmlToSphinx)
+
+ struct InlineImage
+ {
+ QString tag;
+ QString href;
+ };
+
+ struct TableCell
+ {
+ short rowSpan = 0;
+ short colSpan = 0;
+ QString data;
+
+ TableCell(const QString& text = QString()) : data(text) {}
+ TableCell(const char* text) : data(QString::fromLatin1(text)) {}
+ };
+
+ using TableRow = QList<TableCell>;
+
+ class Table
+ {
+ public:
+ Table() = default;
+
+ bool isEmpty() const { return m_rows.isEmpty(); }
+
+ void setHeaderEnabled(bool enable)
+ {
+ m_hasHeader = enable;
+ }
+
+ bool hasHeader() const
+ {
+ return m_hasHeader;
+ }
+
+ void normalize();
+
+ bool isNormalized() const
+ {
+ return m_normalized;
+ }
+
+ void appendRow(const TableRow &row) { m_rows.append(row); }
+
+ const TableRow &constFirst() const { return m_rows.constFirst(); }
+ TableRow &first() { return m_rows.first(); }
+ TableRow &last() { return m_rows.last(); }
+
+ void format(TextStream& s) const;
+ void formatDebug(QDebug &debug) const;
+
+ private:
+ bool hasEmptyLeadingRow() const;
+ bool hasEmptyTrailingRow() const;
+
+ QList<TableRow> m_rows;
+ bool m_hasHeader = false;
+ bool m_normalized = false;
+ };
+
+ explicit QtXmlToSphinx(const QtXmlToSphinxDocGeneratorInterface *docGenerator,
+ const QtXmlToSphinxParameters &parameters,
+ const QString& doc,
+ const QString& context = QString());
+ ~QtXmlToSphinx();
+
+ QString result() const
+ {
+ return m_result;
+ }
+
+ static void stripPythonQualifiers(QString *s);
+
+ // For testing
+ static QString readSnippet(QIODevice &inputFile, const QString &identifier,
+ QString *errorMessage);
+
+private:
+ using StringSharedPtr = std::shared_ptr<QString>;
+
+ QString transform(const QString& doc);
+
+ void handleHeadingTag(QXmlStreamReader& reader);
+ void handleParaTag(QXmlStreamReader& reader);
+ void handleParaTagStart();
+ void handleParaTagText(QXmlStreamReader &reader);
+ void handleParaTagEnd();
+ void handleItalicTag(QXmlStreamReader& reader);
+ void handleBoldTag(QXmlStreamReader& reader);
+ void handleArgumentTag(QXmlStreamReader& reader);
+ void handleSeeAlsoTag(QXmlStreamReader& reader);
+ void handleSnippetTag(QXmlStreamReader& reader);
+ void handleDotsTag(QXmlStreamReader& reader);
+ void handleLinkTag(QXmlStreamReader& reader);
+ void handleImageTag(QXmlStreamReader& reader);
+ void handleInlineImageTag(QXmlStreamReader& reader);
+ void handleListTag(QXmlStreamReader& reader);
+ void handleTermTag(QXmlStreamReader& reader);
+ void handleSuperScriptTag(QXmlStreamReader& reader);
+ void handleQuoteFileTag(QXmlStreamReader& reader);
+
+ // table tagsvoid QtXmlToSphinx::handleValueTag(QXmlStreamReader& reader)
+
+ void handleTableTag(QXmlStreamReader& reader);
+ void handleHeaderTag(QXmlStreamReader& reader);
+ void handleRowTag(QXmlStreamReader& reader);
+ void handleItemTag(QXmlStreamReader& reader);
+ void handleRawTag(QXmlStreamReader& reader);
+ void handleCodeTag(QXmlStreamReader& reader);
+ void handlePageTag(QXmlStreamReader&);
+ void handleTargetTag(QXmlStreamReader&);
+
+ void handleIgnoredTag(QXmlStreamReader& reader);
+ void handleUnknownTag(QXmlStreamReader& reader);
+ void handleUselessTag(QXmlStreamReader& reader);
+ void handleAnchorTag(QXmlStreamReader& reader);
+ void handleRstPassTroughTag(QXmlStreamReader& reader);
+
+ QtXmlToSphinxLink *handleLinkStart(const QString &type, QString ref) const;
+ static void handleLinkText(QtXmlToSphinxLink *linkContext, const QString &linktext) ;
+ void handleLinkEnd(QtXmlToSphinxLink *linkContext);
+ WebXmlTag parentTag() const;
+
+ void warn(const QString &message) const;
+ void debug(const QString &message) const;
+
+ QStack<WebXmlTag> m_tagStack;
+ TextStream m_output;
+ QString m_result;
+
+ QStack<StringSharedPtr> m_buffers; // Maintain address stability since it used in TextStream
+
+ QStack<Table> m_tables; // Stack of tables, used for <table><list> with nested <item>
+ QScopedPointer<QtXmlToSphinxLink> m_linkContext; // for <link>
+ QScopedPointer<QtXmlToSphinxLink> m_seeAlsoContext; // for <see-also>foo()</see-also>
+ QString m_context;
+ const QtXmlToSphinxDocGeneratorInterface *m_generator;
+ const QtXmlToSphinxParameters &m_parameters;
+ int m_formattingDepth = 0;
+ bool m_insideBold = false;
+ bool m_insideItalic = false;
+ QString m_lastTagName;
+ QString m_opened_anchor;
+ QList<InlineImage> m_inlineImages;
+
+ bool m_containsAutoTranslations = false;
+
+ struct Snippet
+ {
+ enum Result {
+ Converted, // C++ converted to Python
+ Resolved, // Otherwise resolved in snippet paths
+ Fallback, // Fallback from XML
+ Error
+ };
+
+ QString code;
+ Result result;
+ };
+
+ void setAutoTranslatedNote(QString *str) const;
+
+ Snippet readSnippetFromLocations(const QString &path,
+ const QString &identifier,
+ const QString &fallbackPath,
+ QString *errorMessage);
+ static QString readFromLocation(const QString &location, const QString &identifier,
+ QString *errorMessage);
+ void pushOutputBuffer();
+ QString popOutputBuffer();
+ void writeTable(Table& table);
+ bool copyImage(const QString &href) const;
+ void callHandler(WebXmlTag t, QXmlStreamReader &);
+ void formatCurrentTable();
+};
+
+inline TextStream& operator<<(TextStream& s, const QtXmlToSphinx& xmlToSphinx)
+{
+ return s << xmlToSphinx.result();
+}
+
+QDebug operator<<(QDebug d, const QtXmlToSphinxLink &l);
+QDebug operator<<(QDebug debug, const QtXmlToSphinx::Table &t);
+QDebug operator<<(QDebug debug, const QtXmlToSphinx::TableCell &c);
+
+#endif // QTXMLTOSPHINX_H
diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h b/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h
new file mode 100644
index 000000000..d4a098a12
--- /dev/null
+++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QTXMLTOSPHINXINTERFACE_H
+#define QTXMLTOSPHINXINTERFACE_H
+
+#include <QtCore/QStringList>
+
+QT_FORWARD_DECLARE_CLASS(QLoggingCategory)
+
+struct QtXmlToSphinxParameters
+{
+ QString moduleName;
+ QString docDataDir;
+ QString outputDirectory;
+ QString libSourceDir;
+ QStringList codeSnippetDirs;
+ QString codeSnippetRewriteOld;
+ QString codeSnippetRewriteNew;
+ bool snippetComparison = false;
+};
+
+struct QtXmlToSphinxLink
+{
+ enum Type
+ {
+ Method = 0x1, Function = 0x2,
+ FunctionMask = Method | Function,
+ Class = 0x4, Attribute = 0x8, Module = 0x10,
+ Reference = 0x20, External= 0x40
+ };
+
+ enum Flags { InsideBold = 0x1, InsideItalic = 0x2 };
+
+ explicit QtXmlToSphinxLink(const QString &ref) : linkRef(ref) {}
+
+ QString linkRef;
+ QString linkText;
+ Type type = Reference;
+ int flags = 0;
+};
+
+class QtXmlToSphinxDocGeneratorInterface
+{
+public:
+ virtual QString expandFunction(const QString &function) const = 0;
+ virtual QString expandClass(const QString &context,
+ const QString &name) const = 0;
+ virtual QString resolveContextForMethod(const QString &context,
+ const QString &methodName) const = 0;
+
+ virtual const QLoggingCategory &loggingCategory() const = 0;
+
+ 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;
+};
+
+#endif // QTXMLTOSPHINXINTERFACE_H
diff --git a/sources/shiboken6/generator/qtdoc/rstformat.h b/sources/shiboken6/generator/qtdoc/rstformat.h
new file mode 100644
index 000000000..8af7671fb
--- /dev/null
+++ b/sources/shiboken6/generator/qtdoc/rstformat.h
@@ -0,0 +1,99 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef RSTFORMAT_H
+#define RSTFORMAT_H
+
+#include <textstream.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QString>
+#include <QtCore/QTextStream>
+#include <QtCore/QVersionNumber>
+
+struct rstVersionAdded
+{
+ explicit rstVersionAdded(const QVersionNumber &v) : m_version(v) {}
+
+ const QVersionNumber m_version;
+};
+
+inline TextStream &operator<<(TextStream &s, const rstVersionAdded &v)
+{
+ s << ".. versionadded:: "<< v.m_version.toString() << "\n\n";
+ return s;
+}
+
+inline QByteArray rstDeprecationNote(const char *what)
+{
+ return QByteArrayLiteral(".. note:: This ")
+ + what + QByteArrayLiteral(" is deprecated.\n\n");
+}
+
+template <class String>
+inline int writeEscapedRstText(TextStream &str, const String &s)
+{
+ int escaped = 0;
+ for (const QChar &c : s) {
+ switch (c.unicode()) {
+ case '*':
+ case '`':
+ case '_':
+ case '\\':
+ str << '\\';
+ ++escaped;
+ break;
+ }
+ str << c;
+ }
+ return s.size() + escaped;
+}
+
+class escape
+{
+public:
+ explicit escape(QStringView s) : m_string(s) {}
+
+ void write(TextStream &str) const { writeEscapedRstText(str, m_string); }
+
+private:
+ const QStringView m_string;
+};
+
+inline TextStream &operator<<(TextStream &str, const escape &e)
+{
+ e.write(str);
+ return str;
+}
+
+// RST anchor string: Anything else but letters, numbers, '_' or '.' replaced by '-'
+inline bool isValidRstLabelChar(QChar c)
+{
+ return c.isLetterOrNumber() || c == u'_' || c == u'.';
+}
+
+inline QString toRstLabel(QString s)
+{
+ for (int i = 0, size = s.size(); i < size; ++i) {
+ if (!isValidRstLabelChar(s.at(i)))
+ s[i] = u'-';
+ }
+ return s;
+}
+
+class rstLabel
+{
+public:
+ explicit rstLabel(const QString &l) : m_label(l) {}
+
+ friend TextStream &operator<<(TextStream &str, const rstLabel &a)
+ {
+ str << ".. _" << toRstLabel(a.m_label) << ":\n\n";
+ return str;
+ }
+
+private:
+ const QString &m_label;
+};
+
+#endif // RSTFORMAT_H
diff --git a/sources/shiboken6/generator/shiboken/configurablescope.h b/sources/shiboken6/generator/shiboken/configurablescope.h
new file mode 100644
index 000000000..9040c7ad9
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/configurablescope.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CONFIGURABLESCOPE_H
+#define CONFIGURABLESCOPE_H
+
+#include <textstream.h>
+#include <configurabletypeentry.h>
+
+/// Enclose a scope within preprocessor conditions for configurable entries
+class ConfigurableScope
+{
+public:
+ explicit ConfigurableScope(TextStream &s, const ConfigurableTypeEntryCPtr &t) :
+ m_stream(s),
+ m_hasConfigCondition(t->hasConfigCondition())
+ {
+ if (m_hasConfigCondition)
+ m_stream << t->configCondition() << '\n';
+ }
+
+ ~ConfigurableScope()
+ {
+ if (m_hasConfigCondition)
+ m_stream << "#endif\n";
+ }
+
+private:
+ TextStream &m_stream;
+ const bool m_hasConfigCondition;
+};
+
+#endif // CONFIGURABLESCOPE_H
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
new file mode 100644
index 000000000..97a38a08d
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
@@ -0,0 +1,6819 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "cppgenerator.h"
+#include "configurablescope.h"
+#include "generatorargument.h"
+#include "generatorstrings.h"
+#include "defaultvalue.h"
+#include "generatorcontext.h"
+#include "codesnip.h"
+#include "customconversion.h"
+#include "headergenerator.h"
+#include "apiextractorresult.h"
+#include "ctypenames.h"
+#include <exception.h>
+#include "pytypenames.h"
+#include "fileout.h"
+#include "overloaddata.h"
+#include "pymethoddefentry.h"
+#include <abstractmetaenum.h>
+#include <abstractmetafield.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetalang_helpers.h>
+#include <messages.h>
+#include <modifications.h>
+#include <propertyspec.h>
+#include <reporthandler.h>
+#include <sourcelocation.h>
+#include <textstream.h>
+#include <typedatabase.h>
+#include <containertypeentry.h>
+#include <enumtypeentry.h>
+#include <flagstypeentry.h>
+#include <functiontypeentry.h>
+#include <namespacetypeentry.h>
+#include <primitivetypeentry.h>
+#include <smartpointertypeentry.h>
+#include <typesystemtypeentry.h>
+#include <valuetypeentry.h>
+#include <parser/enumvalue.h>
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QMetaObject>
+#include <QtCore/QMetaType>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QTextStream>
+
+#include <algorithm>
+#include <cstring>
+#include <memory>
+#include <set>
+
+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";
+
+static QString mangleName(QString name)
+{
+ if (name == u"None" || name == u"False" || name == u"True" || name == u"from")
+ name += u'_';
+ return name;
+}
+
+struct sbkUnusedVariableCast
+{
+ explicit sbkUnusedVariableCast(QAnyStringView name) : m_name(name) {}
+
+ const QAnyStringView m_name;
+};
+
+TextStream &operator<<(TextStream &str, const sbkUnusedVariableCast &c)
+{
+ str << "SBK_UNUSED(" << c.m_name << ")\n";
+ return str;
+}
+
+struct pyTypeGetSlot
+{
+ explicit pyTypeGetSlot(QAnyStringView funcType, QAnyStringView typeObject,
+ QAnyStringView aSlot) :
+ m_funcType(funcType), m_typeObject(typeObject), m_slot(aSlot) {}
+
+ const QAnyStringView m_funcType;
+ const QAnyStringView m_typeObject;
+ const QAnyStringView m_slot;
+};
+
+TextStream &operator<<(TextStream &str, const pyTypeGetSlot &p)
+{
+ str << "reinterpret_cast<" << p.m_funcType << ">(PepType_GetSlot("
+ << p.m_typeObject << ", " << p.m_slot << "));\n";
+ return str;
+}
+
+TextStream &operator<<(TextStream &s, CppGenerator::ErrorReturn r)
+{
+ s << "return";
+ switch (r) {
+ case CppGenerator::ErrorReturn::Default:
+ s << " {}";
+ break;
+ case CppGenerator::ErrorReturn::Zero:
+ s << " 0";
+ break;
+ case CppGenerator::ErrorReturn::MinusOne:
+ s << " -1";
+ break;
+ case CppGenerator::ErrorReturn::Void:
+ break;
+ }
+ s << ";\n";
+ return s;
+}
+
+static constexpr auto converterVar = "converter"_L1;
+
+struct registerConverterName
+{
+ explicit registerConverterName(QAnyStringView typeName,
+ QAnyStringView varName = converterVar) :
+ m_typeName(typeName), m_varName(varName) {}
+
+ QAnyStringView m_typeName;
+ QAnyStringView m_varName;
+};
+
+TextStream &operator<<(TextStream &s, const registerConverterName &r)
+{
+ s << "Shiboken::Conversions::registerConverterName(" << r.m_varName
+ << ", \"" << r.m_typeName << "\");\n";
+ return s;
+}
+
+// Protocol function name / function parameters / return type
+struct ProtocolEntry
+{
+ QString name;
+ QString arguments;
+ QString returnType;
+};
+
+using ProtocolEntries = QList<ProtocolEntry>;
+
+static bool contains(const ProtocolEntries &l, const QString &needle)
+{
+ for (const auto &m : l) {
+ if (m.name == needle)
+ return true;
+ }
+ return false;
+}
+
+// Maps special function names to function parameters and return types
+// used by CPython API in the mapping protocol.
+const ProtocolEntries &mappingProtocols()
+{
+ static const ProtocolEntries result = {
+ {u"__mlen__"_s,
+ u"PyObject *self"_s,
+ u"Py_ssize_t"_s},
+ {u"__mgetitem__"_s,
+ u"PyObject *self, PyObject *_key"_s,
+ u"PyObject*"_s},
+ {u"__msetitem__"_s,
+ u"PyObject *self, PyObject *_key, PyObject *_value"_s,
+ intT}};
+ return result;
+}
+
+// Maps special function names to function parameters and return types
+// used by CPython API in the sequence protocol.
+const ProtocolEntries &sequenceProtocols()
+{
+ static const ProtocolEntries result = {
+ {u"__len__"_s,
+ u"PyObject *self"_s,
+ u"Py_ssize_t"_s},
+ {u"__getitem__"_s,
+ u"PyObject *self, Py_ssize_t _i"_s,
+ u"PyObject*"_s},
+ {u"__setitem__"_s,
+ u"PyObject *self, Py_ssize_t _i, PyObject *_value"_s,
+ intT},
+ {u"__getslice__"_s,
+ u"PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2"_s,
+ u"PyObject*"_s},
+ {u"__setslice__"_s,
+ u"PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2, PyObject *_value"_s,
+ intT},
+ {u"__contains__"_s,
+ u"PyObject *self, PyObject *_value"_s,
+ intT},
+ {u"__concat__"_s,
+ u"PyObject *self, PyObject *_other"_s,
+ u"PyObject*"_s}
+ };
+ return result;
+}
+
+// Return name of function to create PyObject wrapping a container
+static QString opaqueContainerCreationFunc(const AbstractMetaType &type)
+{
+ const auto containerTypeEntry =
+ std::static_pointer_cast<const ContainerTypeEntry>(type.typeEntry());
+ const auto instantiationTypeEntry =
+ type.instantiations().constFirst().typeEntry();
+ QString result = u"create"_s;
+ if (type.isConstant())
+ result += u"Const"_s;
+ result += containerTypeEntry->opaqueContainerName(type.instantiationCppSignatures());
+ return result;
+}
+
+// Write declaration of the function to create PyObject wrapping a container
+static void writeOpaqueContainerCreationFuncDecl(TextStream &s, const QString &name,
+ AbstractMetaType type)
+{
+ type.setReferenceType(NoReference);
+ // Maintain const
+ s << "PyObject *" << name << '(' << type.cppSignature() << "*);\n";
+}
+
+CppGenerator::CppGenerator() = default;
+
+QString CppGenerator::fileNameForContext(const GeneratorContext &context) const
+{
+ return fileNameForContextHelper(context, u"_wrapper.cpp"_s);
+}
+
+void CppGenerator::clearTpFuncs()
+{
+ // Functions that should not be registered under a name in PyMethodDef,
+ // but under a special constant under slots.
+ m_tpFuncs = {
+ {u"__str__"_s, {}}, {u"__str__"_s, {}},
+ {REPR_FUNCTION, {}}, {u"__iter__"_s, {}},
+ {u"__next__"_s, {}}
+ };
+ m_nbFuncs = { {u"__abs__"_s, {}}, {u"__pow__"_s, {} }};
+}
+
+// Prevent ELF symbol qt_version_tag from being generated into the source
+static const char includeQDebug[] =
+"#ifndef QT_NO_VERSION_TAGGING\n"
+"# define QT_NO_VERSION_TAGGING\n"
+"#endif\n"
+"#include <QtCore/QDebug>\n";
+
+QString CppGenerator::chopType(QString s)
+{
+ if (s.endsWith(u"_Type"))
+ s.chop(5);
+ else if (s.endsWith(u"_TypeF()"))
+ s.chop(8);
+ return s;
+}
+
+static bool isStdSetterName(QString setterName, QString propertyName)
+{
+ return setterName.size() == propertyName.size() + 3
+ && setterName.startsWith(u"set")
+ && setterName.endsWith(QStringView{propertyName}.right(propertyName.size() - 1))
+ && setterName.at(3) == propertyName.at(0).toUpper();
+}
+
+static QString buildPropertyString(const QPropertySpec &spec)
+{
+ QString text = u'"' + spec.name() + u':';
+
+ if (spec.read() != spec.name())
+ text += spec.read();
+
+ if (!spec.write().isEmpty()) {
+ text += u':';
+ if (!isStdSetterName(spec.write(), spec.name()))
+ text += spec.write();
+ }
+
+ text += u'"';
+ return text;
+}
+
+static QString _plainName(const QString &s)
+{
+ auto cutPos = s.lastIndexOf(u"::"_s);
+ return cutPos < 0 ? s : s.right(s.length() - (cutPos + 2));
+}
+
+/**********************************************************************
+ *
+ * Decision whether to use an IntEnum/IntFlag
+ * ------------------------------------------
+ *
+ * Unfortunately, all attempts to drive this decision automagically
+ * did not work out. We therefore compile a list in with known
+ * IntEnum and IntFlag.
+ */
+
+/*
+ * This function is now unused and replaced by TypeSystem::PythonEnumType
+ */
+#if 0
+static QSet<QString> useIntSet()
+{
+ static const QSet<QString> result{
+ /* IntEnum */ u"PySide6.QtCore.QDataStream.Version"_s,
+ /* IntEnum */ u"PySide6.QtCore.QEvent.Type"_s,
+ /* IntEnum */ u"PySide6.QtCore.QLocale.FloatingPointPrecisionOption"_s,
+ /* IntFlag */ u"PySide6.QtCore.QLocale.LanguageCodeType"_s,
+ /* IntFlag */ u"PySide6.QtCore.QUrl.ComponentFormattingOption"_s,
+ // note: "QUrl::UrlFormattingOption" is set as IntFlag without flags
+ /* IntFlag */ u"PySide6.QtCore.QUrl.UrlFormattingOption"_s,
+ /* IntFlag */ u"PySide6.QtCore.Qt.AlignmentFlag"_s,
+ /* IntFlag */ u"PySide6.QtCore.Qt.FocusPolicy"_s,
+ /* IntEnum */ u"PySide6.QtCore.Qt.GestureType"_s,
+ /* IntEnum */ u"PySide6.QtCore.Qt.ItemDataRole"_s,
+ /* IntEnum */ u"PySide6.QtCore.Qt.Key"_s,
+ /* Flag */ u"PySide6.QtCore.Qt.Modifier"_s,
+ // note: "Qt::TextFlag" is set as IntFlag without flags
+ /* IntFlag */ u"PySide6.QtCore.Qt.TextFlag"_s,
+ /* IntFlag */ u"PySide6.QtCore.Qt.WindowType"_s,
+ // This is found in QtWidgets but should be in QtGui.
+ /* IntEnum */ u"PySide6.QtGui.QFileSystemModel.Roles"_s,
+ /* IntEnum */ u"PySide6.QtGui.QFont.Stretch"_s,
+ /* IntEnum */ u"PySide6.QtGui.QFont.Weight"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextDocument.ResourceType"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextFormat.FormatType"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextFormat.ObjectTypes"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextFormat.Property"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QDialog.DialogCode"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QFrame.Shadow"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QFrame.Shape"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QListWidgetItem.ItemType"_s,
+ /* IntFlag */ u"PySide6.QtWidgets.QMessageBox.StandardButton"_s,
+ // note: "QSizePolicy::PolicyFlag" is set as IntFlag without flags
+ /* IntFlag */ u"PySide6.QtWidgets.QSizePolicy.PolicyFlag"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.ComplexControl"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.ContentsType"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.ControlElement"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.PixelMetric"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.PrimitiveElement"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.StandardPixmap"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.StyleHint"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.SubElement"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QTableWidgetItem.ItemType"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QTreeWidgetItem.ItemType"_s,
+ /* IntEnum */ u"PySide6.QtCharts.QBoxSet.ValuePositions"_s,
+ /* IntEnum */ u"PySide6.QtMultimedia.QMediaPlayer.Loops"_s,
+ /* IntEnum */ u"PySide6.QtQuick.QSGGeometry.DrawingMode"_s,
+ /* IntEnum */ u"PySide6.QtWebEngineCore.QWebEngineScript.ScriptWorldId"_s,
+ // Added because it should really be used as number
+ /* IntEnum */ u"PySide6.QtCore.QMetaType.Type"_s,
+ /* IntEnum */ u"PySide6.QtSerialPort.QSerialPort.BaudRate"_s,
+ };
+ return result;
+}
+#endif
+
+static bool _shouldInheritInt(const AbstractMetaEnum &cppEnum)
+{
+ return !cppEnum.fullName().startsWith(u"PySide6."_s);
+}
+
+static QString BuildEnumFlagInfo(const AbstractMetaEnum &cppEnum)
+{
+ auto enumType = cppEnum.typeEntry();
+ QString result = _plainName(enumType->name());
+ auto flags = enumType->flags();
+ auto decision = enumType->pythonEnumType();
+ bool _int = _shouldInheritInt(cppEnum);
+ bool _flag = bool(flags);
+
+ if (decision != TypeSystem::PythonEnumType::Unspecified) {
+ _int = decision == TypeSystem::PythonEnumType::IntEnum ||
+ decision == TypeSystem::PythonEnumType::IntFlag;
+ _flag = decision == TypeSystem::PythonEnumType::Flag ||
+ decision == TypeSystem::PythonEnumType::IntFlag;
+ }
+ result += _flag ? (_int ? u":IntFlag"_s : u":Flag"_s)
+ : (_int ? u":IntEnum"_s : u":Enum"_s);
+ if (flags)
+ result += u':' + _plainName(flags->flagsName());
+ return u'"' + result + u'"';
+}
+
+static void writePyGetSetDefEntry(TextStream &s, const QString &name,
+ const QString &getFunc, const QString &setFunc)
+{
+ s << "{const_cast<char *>(\"" << mangleName(name) << "\"), " << getFunc << ", "
+ << (setFunc.isEmpty() ? NULL_PTR : setFunc) << ", nullptr, nullptr},\n";
+}
+
+static bool generateRichComparison(const GeneratorContext &c)
+{
+ const auto metaClass = c.metaClass();
+ if (c.forSmartPointer()) {
+ auto te = std::static_pointer_cast<const SmartPointerTypeEntry>(metaClass->typeEntry());
+ return te->smartPointerType() == TypeSystem::SmartPointerType::Shared;
+ }
+
+ return !metaClass->isNamespace() && metaClass->hasComparisonOperatorOverload();
+}
+
+void CppGenerator::generateIncludes(TextStream &s, const GeneratorContext &classContext,
+ const IncludeGroupList &includes,
+ const AbstractMetaClassCList &innerClasses) const
+{
+ const auto metaClass = classContext.metaClass();
+
+ // write license comment
+ s << licenseComment() << '\n';
+
+ const bool normalClass = !classContext.forSmartPointer();
+ // Normally only required for classes for which we want to generate protected API,
+ // but it needs to be generated into all files to ensure ODR for Unity builds.
+ if (!avoidProtectedHack())
+ s << HeaderGenerator::protectedHackDefine;
+
+ QByteArrayList cppIncludes{"typeinfo", "iterator", // for containers
+ "cctype", "cstring"};
+ // headers
+ s << "// default includes\n";
+ s << "#include <shiboken.h>\n";
+ if (wrapperDiagnostics()) {
+ s << "#include <helper.h>\n";
+ cppIncludes << "iostream";
+ }
+
+ if (normalClass && usePySideExtensions()) {
+ s << includeQDebug;
+ if (metaClass->hasToStringCapability())
+ s << "#include <QtCore/QBuffer>\n";
+ if (isQObject(metaClass)) {
+ s << "#include <pysideqobject.h>\n"
+ << "#include <pysidesignal.h>\n"
+ << "#include <pysideproperty.h>\n"
+ << "#include <signalmanager.h>\n"
+ << "#include <pysidemetafunction.h>\n";
+ }
+ s << "#include <pysideqenum.h>\n"
+ << "#include <pysideqmetatype.h>\n"
+ << "#include <pysideutils.h>\n"
+ << "#include <feature_select.h>\n"
+ << "QT_WARNING_DISABLE_DEPRECATED\n\n";
+ }
+
+ // The multiple inheritance initialization function
+ // needs the 'set' class from C++ STL.
+ if (normalClass && getMultipleInheritingClass(metaClass) != nullptr)
+ cppIncludes << "algorithm" << "set";
+ if (normalClass && metaClass->generateExceptionHandling())
+ cppIncludes << "exception";
+
+ s << "\n// module include\n" << "#include \"" << getModuleHeaderFileName() << "\"\n";
+ if (hasPrivateClasses())
+ s << "#include \"" << getPrivateModuleHeaderFileName() << "\"\n";
+
+ s << "\n// main header\n" << "#include \""
+ << HeaderGenerator::headerFileNameForContext(classContext) << "\"\n";
+
+ if (!innerClasses.isEmpty()) {
+ s << "\n// inner classes\n";
+ for (const auto &innerClass : innerClasses) {
+ GeneratorContext innerClassContext = contextForClass(innerClass);
+ s << "#include \""
+ << HeaderGenerator::headerFileNameForContext(innerClassContext) << "\"\n";
+ }
+ }
+
+ if (avoidProtectedHack())
+ s << baseWrapperIncludes(classContext);
+
+ for (const auto &g : includes)
+ s << g;
+
+ // C++ includes
+ std::sort(cppIncludes.begin(), cppIncludes.end());
+ s << '\n';
+ for (const auto &i : std::as_const(cppIncludes))
+ s << "#include <" << i << ">\n";
+}
+
+// Write methods definition
+void CppGenerator::writePyMethodDefs(TextStream &s, const QString &className,
+ const QString &methodsDefinitions)
+{
+ s << "static PyMethodDef " << className << "_methods[] = {\n" << indent
+ << methodsDefinitions << METHOD_DEF_SENTINEL << outdent << "};\n\n";
+}
+
+void CppGenerator::writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const
+{
+ if (!codeSnips.isEmpty()) {
+ try {
+ writeCodeSnips(s, codeSnips, position, language);
+ } catch (const std::exception &e) {
+ throw Exception(msgSnippetError("module source of "_L1 + moduleName(), e.what()));
+ }
+ }
+}
+
+bool CppGenerator::hasHashFunction(const AbstractMetaClassCPtr &c)
+{
+ return !c->typeEntry()->hashFunction().isEmpty()
+ || c->hasHashFunction();
+}
+
+static bool needsTypeDiscoveryFunction(const AbstractMetaClassCPtr &c)
+{
+ return c->baseClass() != nullptr
+ && (c->isPolymorphic() || !c->typeEntry()->polymorphicIdValue().isEmpty());
+}
+
+static void writeAddedTypeSignatures(TextStream &s, const ComplexTypeEntryCPtr &te)
+{
+ for (const auto &e : te->addedPyMethodDefEntrys()) {
+ if (auto count = e.signatures.size()) {
+ for (qsizetype i = 0; i < count; ++i) {
+ if (count > 1)
+ s << i << ':';
+ s << e.signatures.at(i) << '\n';
+ }
+ }
+ }
+}
+
+/// Function used to write the class generated binding code on the buffer
+/// \param s the output buffer
+/// \param classContext the pointer to metaclass information
+void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classContext)
+{
+ if (classContext.forSmartPointer()) {
+ generateSmartPointerClass(s, classContext);
+ return;
+ }
+
+ s.setLanguage(TextStream::Language::Cpp);
+ AbstractMetaClassCPtr metaClass = classContext.metaClass();
+ const auto typeEntry = metaClass->typeEntry();
+
+ auto innerClasses = metaClass->innerClasses();
+ for (auto it = innerClasses.begin(); it != innerClasses.end(); ) {
+ auto innerTypeEntry = (*it)->typeEntry();
+ if (shouldGenerate(innerTypeEntry) && !innerTypeEntry->isSmartPointer())
+ ++it;
+ else
+ it = innerClasses.erase(it);
+ }
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ metaClass->getEnumsFromInvisibleNamespacesToBeGenerated(&classEnums);
+
+ IncludeGroupList includeGroups;
+ if (!classContext.useWrapper() || !avoidProtectedHack())
+ includeGroups.append(classIncludes(metaClass));
+ generateIncludes(s, classContext, includeGroups, innerClasses);
+
+ if (typeEntry->typeFlags().testFlag(ComplexTypeEntry::Deprecated))
+ s << "#Deprecated\n";
+
+ // Use class base namespace
+ {
+ AbstractMetaClassCPtr context = metaClass->enclosingClass();
+ while (context) {
+ if (context->isNamespace() && !context->enclosingClass()
+ && std::static_pointer_cast<const NamespaceTypeEntry>(context->typeEntry())->generateUsing()) {
+ s << "\nusing namespace " << context->qualifiedCppName() << ";\n";
+ break;
+ }
+ context = context->enclosingClass();
+ }
+ }
+
+ s << '\n';
+
+ // class inject-code native/beginning
+ if (!typeEntry->codeSnips().isEmpty()) {
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
+ TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode,
+ classContext);
+ s << '\n';
+ }
+
+ // python conversion rules
+ if (typeEntry->isValue()) {
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry);
+ if (vte->hasTargetConversionRule()) {
+ s << "// Python Conversion\n";
+ s << vte->targetConversionRule() << '\n';
+ }
+ }
+
+ if (classContext.useWrapper()) {
+ s << "// Native ---------------------------------------------------------\n\n";
+
+ if (avoidProtectedHack() && usePySideExtensions()) {
+ s << "void " << classContext.wrapperName() << "::pysideInitQtMetaTypes()\n{\n"
+ << indent;
+ writeInitQtMetaTypeFunctionBody(s, classContext);
+ s << outdent << "}\n\n";
+ }
+
+ int maxOverrides = 0;
+ writeCacheResetNative(s, classContext);
+ for (const auto &func : metaClass->functions()) {
+ const auto generation = functionGeneration(func);
+ if (generation.testFlag(FunctionGenerationFlag::WrapperConstructor))
+ writeConstructorNative(s, classContext, func);
+ else if (generation.testFlag(FunctionGenerationFlag::VirtualMethod))
+ writeVirtualMethodNative(s, func, maxOverrides++);
+ }
+
+ if (shouldGenerateMetaObjectFunctions(metaClass))
+ writeMetaObjectMethod(s, classContext);
+ if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
+ writeDestructorNative(s, classContext);
+ }
+
+ for (const auto &f : metaClass->userAddedPythonOverrides())
+ writeUserAddedPythonOverride(s, f);
+
+ StringStream smd(TextStream::Language::Cpp);
+ StringStream md(TextStream::Language::Cpp);
+ StringStream signatureStream(TextStream::Language::Cpp);
+
+ s << openTargetExternC;
+
+ const auto &functionGroups = getFunctionGroups(metaClass);
+ for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ if (contains(sequenceProtocols(), it.key()) || contains(mappingProtocols(), it.key()))
+ continue;
+ const AbstractMetaFunctionCList &overloads = it.value();
+ if (overloads.isEmpty())
+ continue;
+
+ const auto rfunc = overloads.constFirst();
+ OverloadData overloadData(overloads, api());
+
+ if (rfunc->isConstructor()) {
+ writeConstructorWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ }
+ // call operators
+ else if (rfunc->name() == u"operator()") {
+ writeMethodWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ }
+ else if (!rfunc->isOperatorOverload()) {
+ writeMethodWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ // For a mixture of static and member function overloads,
+ // a separate PyMethodDef entry is written which is referenced
+ // in the PyMethodDef list and later in getattro() for handling
+ // the non-static case.
+ const auto defEntries = methodDefinitionEntries(overloadData);
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
+ QString methDefName = cpythonMethodDefinitionName(rfunc);
+ smd << "static PyMethodDef " << methDefName << " = " << indent
+ << defEntries.constFirst() << outdent << ";\n\n";
+ }
+ const auto &fname = rfunc->name();
+ if (!m_tpFuncs.contains(fname) && !m_nbFuncs.contains(fname))
+ md << defEntries;
+ }
+ }
+ for (const auto &pyMethodDef : typeEntry->addedPyMethodDefEntrys())
+ md << pyMethodDef << ",\n";
+
+ if (typeEntry->isValue())
+ writeCopyFunction(s, md, signatureStream, classContext);
+
+ const QString methodsDefinitions = md.toString();
+ const QString singleMethodDefinitions = smd.toString();
+
+ const QString className = chopType(cpythonTypeName(metaClass));
+
+ // Write single method definitions
+ s << singleMethodDefinitions;
+
+ if (usePySideExtensions()) {
+ // PYSIDE-1019: Write a compressed list of all properties `name:getter[:setter]`.
+ // Default values are suppressed.
+ QStringList sorter;
+ for (const auto &spec : metaClass->propertySpecs()) {
+ if (!spec.generateGetSetDef())
+ sorter.append(buildPropertyString(spec));
+ }
+ sorter.sort();
+
+ s << '\n';
+ s << "static const char *" << className << "_PropertyStrings[] = {\n" << indent;
+ for (const auto &entry : std::as_const(sorter))
+ s << entry << ",\n";
+ s << NULL_PTR << " // Sentinel\n"
+ << outdent << "};\n\n";
+
+ }
+ // PYSIDE-1735: Write an EnumFlagInfo structure
+ QStringList sorter;
+ for (const auto &entry : std::as_const(classEnums))
+ sorter.append(BuildEnumFlagInfo(entry));
+ sorter.sort();
+ if (!sorter.empty()) {
+ s << "static const char *" << className << "_EnumFlagInfo[] = {\n" << indent;
+ for (const auto &entry : std::as_const(sorter))
+ s << entry << ",\n";
+ s << NULL_PTR << " // Sentinel\n"
+ << outdent << "};\n\n";
+ }
+
+ // Write methods definition
+ writePyMethodDefs(s, className, methodsDefinitions);
+
+ // Write tp_s/getattro function
+ const AttroCheck attroCheck = checkAttroFunctionNeeds(metaClass);
+ if ((attroCheck & AttroCheckFlag::GetattroMask) != 0)
+ writeGetattroFunction(s, attroCheck, classContext);
+ if ((attroCheck & AttroCheckFlag::SetattroMask) != 0)
+ writeSetattroFunction(s, attroCheck, classContext);
+
+ if (const auto f = boolCast(metaClass) ; f.has_value())
+ writeNbBoolFunction(classContext, f.value(), s);
+
+ if (supportsNumberProtocol(metaClass)) {
+ const auto numberProtocolOps = numberProtocolOperators(metaClass);
+ for (const auto &overloads : numberProtocolOps) {
+ OverloadData overloadData(overloads, api());
+ writeMethodWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ }
+ }
+
+ if (supportsSequenceProtocol(metaClass)) {
+ writeSequenceMethods(s, metaClass, classContext);
+ }
+
+ if (supportsMappingProtocol(metaClass)) {
+ writeMappingMethods(s, metaClass, classContext);
+ }
+
+ if (generateRichComparison(classContext)) {
+ s << "// Rich comparison\n";
+ writeRichCompareFunction(s, classContext);
+ }
+
+ if (shouldGenerateGetSetList(metaClass)) {
+ const AbstractMetaFieldList &fields = metaClass->fields();
+ for (const AbstractMetaField &metaField : fields) {
+ if (metaField.canGenerateGetter())
+ writeGetterFunction(s, metaField, classContext);
+ if (metaField.canGenerateSetter())
+ writeSetterFunction(s, metaField, classContext);
+ s << '\n';
+ }
+
+ for (const QPropertySpec &property : metaClass->propertySpecs()) {
+ if (property.generateGetSetDef() || !usePySideExtensions()) {
+ writeGetterFunction(s, property, classContext);
+ if (property.hasWrite())
+ writeSetterFunction(s, property, classContext);
+ }
+ }
+
+ s << "// Getters and Setters for " << metaClass->name() << '\n';
+ s << "static PyGetSetDef " << cpythonGettersSettersDefinitionName(metaClass)
+ << "[] = {\n" << indent;
+ for (const AbstractMetaField &metaField : fields) {
+ const bool canGenerateGetter = metaField.canGenerateGetter();
+ const bool canGenerateSetter = metaField.canGenerateSetter();
+ if (canGenerateGetter || canGenerateSetter) {
+ const QString getter = canGenerateGetter
+ ? cpythonGetterFunctionName(metaField) : QString();
+ const QString setter = canGenerateSetter
+ ? cpythonSetterFunctionName(metaField) : QString();
+ const auto names = metaField.definitionNames();
+ for (const auto &name : names)
+ writePyGetSetDefEntry(s, name, getter, setter);
+ }
+ }
+
+ for (const QPropertySpec &property : metaClass->propertySpecs()) {
+ if (property.generateGetSetDef() || !usePySideExtensions()) {
+ const QString setter = property.hasWrite()
+ ? cpythonSetterFunctionName(property, metaClass) : QString();
+ writePyGetSetDefEntry(s, property.name(),
+ cpythonGetterFunctionName(property, metaClass), setter);
+ }
+ }
+ s << "{nullptr, nullptr, nullptr, nullptr, nullptr} // Sentinel\n"
+ << outdent << "};\n\n";
+ }
+
+ s << closeExternC;
+
+ if (hasHashFunction(metaClass))
+ writeHashFunction(s, classContext);
+
+ // Write tp_traverse and tp_clear functions.
+ writeTpTraverseFunction(s, metaClass);
+ writeTpClearFunction(s, metaClass);
+
+ writeClassDefinition(s, metaClass, classContext);
+ s << '\n';
+
+ if (needsTypeDiscoveryFunction(metaClass)) {
+ writeTypeDiscoveryFunction(s, metaClass);
+ s << '\n';
+ }
+
+ writeConverterFunctions(s, metaClass, classContext);
+ writeAddedTypeSignatures(signatureStream, typeEntry);
+ writeClassRegister(s, metaClass, classContext, signatureStream);
+
+ if (metaClass->hasStaticFields())
+ writeStaticFieldInitialization(s, metaClass);
+
+ // class inject-code native/end
+ if (!typeEntry->codeSnips().isEmpty()) {
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
+ TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode,
+ classContext);
+ s << '\n';
+ }
+}
+
+void CppGenerator::writeMethodWrapper(TextStream &s, TextStream &definitionStream,
+ TextStream &signatureStream,
+ const AbstractMetaFunctionCList &overloads,
+ const GeneratorContext &classContext) const
+{
+ OverloadData overloadData(overloads, api());
+ writeMethodWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ definitionStream << methodDefinitionEntries(overloadData);
+}
+
+void CppGenerator::writeCacheResetNative(TextStream &s, const GeneratorContext &classContext)
+{
+ s << "void " << classContext.wrapperName()
+ << "::resetPyMethodCache()\n{\n" << indent
+ << "std::fill_n(m_PyMethodCache, sizeof(m_PyMethodCache) / sizeof(m_PyMethodCache[0]), false);\n"
+ << outdent << "}\n\n";
+}
+
+void CppGenerator::writeConstructorNative(TextStream &s, const GeneratorContext &classContext,
+ const AbstractMetaFunctionCPtr &func) const
+{
+ const QString qualifiedName = classContext.wrapperName() + u"::"_s;
+ s << functionSignature(func, qualifiedName, QString(),
+ OriginalTypeDescription | SkipDefaultValues);
+ s << " : ";
+ writeFunctionCall(s, func);
+ s << "\n{\n" << indent;
+ if (wrapperDiagnostics())
+ s << R"(std::cerr << __FUNCTION__ << ' ' << this << '\n';)" << '\n';
+ const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : &func->arguments().constLast();
+ s << "resetPyMethodCache();\n";
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionBeginning,
+ TypeSystem::NativeCode, func, false, lastArg);
+ s << "// ... middle\n";
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd,
+ TypeSystem::NativeCode, func, false, lastArg);
+ s << outdent << "}\n\n";
+}
+
+void CppGenerator::writeDestructorNative(TextStream &s,
+ const GeneratorContext &classContext)
+{
+ s << classContext.wrapperName() << "::~"
+ << classContext.wrapperName() << "()\n{\n" << indent;
+ if (wrapperDiagnostics())
+ s << R"(std::cerr << __FUNCTION__ << ' ' << this << '\n';)" << '\n';
+ // kill pyobject
+ s << R"(SbkObject *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(this);
+Shiboken::Object::destroy(wrapper, this);
+)" << outdent << "}\n";
+}
+
+// Return type for error messages when getting invalid types from virtual
+// methods implemented in Python in C++ wrappers
+QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunctionCPtr &func) const
+{
+ if (func->type().isVoid())
+ return u"\"\""_s;
+
+ if (func->isTypeModified())
+ return u'"' + func->modifiedTypeName() + u'"';
+
+ // SbkType would return null when the type is a container.
+ auto typeEntry = func->type().typeEntry();
+ if (typeEntry->isContainer()) {
+ const auto cte = std::static_pointer_cast<const ContainerTypeEntry>(typeEntry);
+ switch (cte->containerKind()) {
+ case ContainerTypeEntry::ListContainer:
+ case ContainerTypeEntry::SpanContainer:
+ break;
+ case ContainerTypeEntry::SetContainer:
+ return uR"("set")"_s;
+ break;
+ case ContainerTypeEntry::MapContainer:
+ case ContainerTypeEntry::MultiMapContainer:
+ return uR"("dict")"_s;
+ break;
+ case ContainerTypeEntry::PairContainer:
+ return uR"("tuple")"_s;
+ break;
+ }
+ return uR"("list")"_s;
+ }
+ if (typeEntry->isSmartPointer())
+ return u'"' + typeEntry->qualifiedCppName() + u'"';
+
+ if (avoidProtectedHack()) {
+ auto metaEnum = api().findAbstractMetaEnum(func->type().typeEntry());
+ if (metaEnum.has_value() && metaEnum->isProtected())
+ return u'"' + protectedEnumSurrogateName(metaEnum.value()) + u'"';
+ }
+
+ if (func->type().isPrimitive())
+ return u'"' + func->type().name() + u'"';
+
+ return u"Shiboken::SbkType< "_s
+ + typeEntry->qualifiedCppName() + u" >()->tp_name"_s;
+}
+
+// When writing an overridden method of a wrapper class, write the part
+// calling the C++ function in case no overload in Python exists.
+void CppGenerator::writeVirtualMethodCppCall(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const QString &funcName,
+ const CodeSnipList &snips,
+ const AbstractMetaArgument *lastArg,
+ const TypeEntryCPtr &retType,
+ const QString &returnStatement, bool hasGil) const
+{
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning,
+ TypeSystem::ShellCode, func, false, lastArg);
+ }
+
+ if (func->isAbstract()) {
+ if (!hasGil)
+ s << "Shiboken::GilState gil;\n";
+ s << "Shiboken::Errors::setPureVirtualMethodError(\""
+ << func->ownerClass()->name() << '.' << funcName << "\");\n"
+ << returnStatement << '\n';
+ return;
+ }
+
+ if (hasGil)
+ s << "gil.release();\n";
+
+ if (retType)
+ s << "return ";
+ s << "this->::" << func->implementingClass()->qualifiedCppName() << "::";
+ writeFunctionCall(s, func, Generator::VirtualCall);
+ s << ";\n";
+ if (retType)
+ return;
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd,
+ TypeSystem::ShellCode, func, false, lastArg);
+ }
+ s << "return;\n";
+}
+
+// Determine the return statement (void or a result value).
+
+CppGenerator::VirtualMethodReturn
+ CppGenerator::virtualMethodReturn(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func,
+ const FunctionModificationList &functionModifications)
+{
+ VirtualMethodReturn result;
+ if (func->isVoid()) {
+ result.statement = "return;"_L1;
+ return result;
+ }
+
+ result.statement = "return "_L1;
+ const AbstractMetaType &returnType = func->type();
+ for (const FunctionModification &mod : functionModifications) {
+ for (const ArgumentModification &argMod : mod.argument_mods()) {
+ if (argMod.index() == 0 && !argMod.replacedDefaultExpression().isEmpty()) {
+ static const QRegularExpression regex("%(\\d+)"_L1);
+ Q_ASSERT(regex.isValid());
+ QString expr = argMod.replacedDefaultExpression();
+ for (int offset = 0; ; ) {
+ const QRegularExpressionMatch match = regex.match(expr, offset);
+ if (!match.hasMatch())
+ break;
+ const int argId = match.capturedView(1).toInt() - 1;
+ if (argId < 0 || argId > func->arguments().size()) {
+ qCWarning(lcShiboken, "The expression used in return value contains an invalid index.");
+ break;
+ }
+ expr.replace(match.captured(0), func->arguments().at(argId).name());
+ offset = match.capturedStart(1);
+ }
+ DefaultValue defaultReturnExpr(DefaultValue::Custom, expr);
+ result.statement += defaultReturnExpr.returnValue() + u';';
+ return result;
+ }
+ }
+ }
+ QString errorMessage;
+ const auto defaultReturnExpr = minimalConstructor(api, returnType, &errorMessage);
+ if (!defaultReturnExpr.has_value()) {
+ QString errorMsg = QLatin1StringView(__FUNCTION__) + u": "_s
+ + func->classQualifiedSignature();
+ errorMsg = msgCouldNotFindMinimalConstructor(errorMsg,
+ func->type().cppSignature(),
+ errorMessage);
+ throw Exception(errorMsg);
+ }
+
+ result.needsReference = returnType.referenceType() == LValueReference;
+ result.statement += (result.needsReference
+ ? virtualMethodStaticReturnVar : defaultReturnExpr->returnValue()) + u';';
+ return result;
+}
+
+// Create an argument for Py_BuildValue() when writing virtual methods.
+// Return a pair of (argument, format-char).
+std::pair<QString, QChar> CppGenerator::virtualMethodNativeArg(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &arg)
+{
+ if (func->hasConversionRule(TypeSystem::TargetLangCode, arg.argumentIndex() + 1))
+ return {arg.name() + CONV_RULE_OUT_VAR_SUFFIX, u'N'};
+
+ const auto &type = arg.type();
+ auto argTypeEntry = type.typeEntry();
+ // Check for primitive types convertible by Py_BuildValue()
+ if (argTypeEntry->isPrimitive() && !type.isCString()) {
+ const auto pte = basicReferencedTypeEntry(argTypeEntry);
+ auto it = formatUnits().constFind(pte->name());
+ if (it != formatUnits().constEnd())
+ return {arg.name(), it.value()};
+ }
+
+ // Rest: convert
+ StringStream ac(TextStream::Language::Cpp);
+ writeToPythonConversion(ac, type, func->ownerClass(), arg.name());
+ return {ac.toString(), u'N'};
+}
+
+static const char PYTHON_ARGS_ARRAY[] = "pyArgArray";
+
+void CppGenerator::writeVirtualMethodNativeVectorCallArgs(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgumentList &arguments,
+ const QList<int> &invalidateArgs)
+{
+ Q_ASSERT(!arguments.isEmpty());
+ s << "PyObject *" << PYTHON_ARGS_ARRAY <<'[' << arguments.size() << "] = {\n" << indent;
+ const qsizetype last = arguments.size() - 1;
+ for (qsizetype i = 0; i <= last; ++i) {
+ const AbstractMetaArgument &arg = arguments.at(i);
+ if (func->hasConversionRule(TypeSystem::TargetLangCode, arg.argumentIndex() + 1)) {
+ s << arg.name() + CONV_RULE_OUT_VAR_SUFFIX;
+ } else {
+ writeToPythonConversion(s, arg.type(), func->ownerClass(), arg.name());
+ }
+ if (i < last)
+ s << ',';
+ s << '\n';
+ }
+ s << outdent << "};\n";
+
+ if (!invalidateArgs.isEmpty())
+ s << '\n';
+ for (int index : invalidateArgs) {
+ s << "const bool invalidateArg" << index << " = Py_REFCNT(" << PYTHON_ARGS_ARRAY <<
+ '[' << index - 1 << "]) == 1;\n";
+ }
+}
+
+void CppGenerator::writeVirtualMethodNativeArgs(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgumentList &arguments,
+ const QList<int> &invalidateArgs)
+{
+ s << "Shiboken::AutoDecRef " << PYTHON_ARGS << '(';
+ if (arguments.isEmpty()) {
+ s << "PyTuple_New(0));\n";
+ return;
+ }
+
+ QString format;
+ QStringList argConversions;
+ for (const AbstractMetaArgument &arg : arguments) {
+ auto argPair = virtualMethodNativeArg(func, arg);
+ argConversions.append(argPair.first);
+ format += argPair.second;
+ }
+
+ s << "Py_BuildValue(\"(" << format << ")\",\n"
+ << indent << argConversions.join(u",\n"_s) << outdent << "\n));\n";
+
+ for (int index : std::as_const(invalidateArgs)) {
+ s << "bool invalidateArg" << index << " = Py_REFCNT(PyTuple_GET_ITEM(" << PYTHON_ARGS
+ << ", " << index - 1 << ")) == 1;\n";
+ }
+}
+
+static bool isArgumentNotRemoved(const AbstractMetaArgument &a)
+{
+ return !a.isModifiedRemoved();
+}
+
+// PyObject_Vectorcall(): since 3.9
+static const char vectorCallCondition[] =
+ "#if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API)\n";
+
+// PyObject_CallNoArgs(): since 3.9, stable API since 3.10
+static const char noArgsCallCondition[] =
+ "#if !defined(PYPY_VERSION) && ((defined(Py_LIMITED_API) && Py_LIMITED_API >= 0x030A0000) || !defined(Py_LIMITED_API))\n";
+static const char inverseNoArgsCallCondition[] =
+ "#if defined(PYPY_VERSION) || (defined(Py_LIMITED_API) && Py_LIMITED_API < 0x030A0000)\n";
+
+static inline void writeVirtualMethodStaticReturnVar(TextStream &s, const AbstractMetaFunctionCPtr &func)
+{
+ s << "static " << func->type().typeEntry()->qualifiedCppName() << ' '
+ << virtualMethodStaticReturnVar << ";\n";
+}
+
+static void writeFuncNameVar(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const QString &funcName)
+{
+ // PYSIDE-1019: Add info about properties
+ int propFlag = 0;
+ if (func->isPropertyReader())
+ propFlag |= 1;
+ if (func->isPropertyWriter())
+ propFlag |= 2;
+ if (propFlag && func->isStatic())
+ propFlag |= 4;
+ QString propStr;
+ if (propFlag != 90)
+ propStr = QString::number(propFlag) + u':';
+
+ if (propFlag != 0)
+ s << "// This method belongs to a property.\n";
+ s << "static const char *funcName = \"";
+ if (propFlag != 0)
+ s << propFlag << ':';
+ s << funcName << "\";\n";
+}
+
+void CppGenerator::writeVirtualMethodNative(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ int cacheIndex) const
+{
+ TypeEntryCPtr retType = func->type().typeEntry();
+ const QString funcName = func->isOperatorOverload()
+ ? pythonOperatorFunctionName(func) : func->definitionNames().constFirst();
+
+ QString prefix = wrapperName(func->ownerClass()) + u"::"_s;
+ s << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues |
+ Generator::OriginalTypeDescription)
+ << "\n{\n" << indent;
+
+ const auto returnStatement = virtualMethodReturn(api(), func,
+ func->modifications());
+
+ if (returnStatement.needsReference)
+ writeVirtualMethodStaticReturnVar(s, func);
+
+ const bool isAbstract = func->isAbstract();
+ if (isAbstract && func->isModifiedRemoved()) {
+ qCWarning(lcShiboken, "%s", qPrintable(msgPureVirtualFunctionRemoved(func.get())));
+ s << returnStatement.statement << '\n' << outdent << "}\n\n";
+ return;
+ }
+
+ const CodeSnipList snips = func->hasInjectedCode()
+ ? func->injectedCodeSnips() : CodeSnipList();
+ const AbstractMetaArgument *lastArg = func->arguments().isEmpty()
+ ? nullptr : &func->arguments().constLast();
+
+ // Write declaration/native injected code.
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionDeclaration,
+ TypeSystem::ShellCode, func, false, lastArg);
+ }
+
+ if (wrapperDiagnostics()) {
+ s << "std::cerr << ";
+#ifndef Q_CC_MSVC // g++ outputs __FUNCTION__ unqualified
+ s << '"' << prefix << R"(" << )";
+#endif
+ s << R"(__FUNCTION__ << ' ' << this << " m_PyMethodCache[" << )"
+ << cacheIndex << R"( << "]=" << m_PyMethodCache[)" << cacheIndex
+ << R"(] << '\n';)" << '\n';
+ }
+ // PYSIDE-803: Build a boolean cache for unused overrides
+ const bool multi_line = func->isVoid() || !snips.isEmpty() || isAbstract;
+ s << "if (m_PyMethodCache[" << cacheIndex << "])" << (multi_line ? " {\n" : "\n")
+ << indent;
+ writeVirtualMethodCppCall(s, func, funcName, snips, lastArg, retType,
+ returnStatement.statement, false);
+ s << outdent;
+ if (multi_line)
+ s << "}\n";
+
+ s << "Shiboken::GilState gil;\n";
+
+ // Get out of virtual method call if someone already threw an error.
+ s << "if (" << shibokenErrorsOccurred << ")\n" << indent
+ << returnStatement.statement << '\n' << outdent;
+
+ s << "static PyObject *nameCache[2] = {};\n";
+ writeFuncNameVar(s, func, funcName);
+ s << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR
+ << "(Shiboken::BindingManager::instance().getOverride(this, nameCache, funcName));\n"
+ << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {\n" << indent;
+ if (useOverrideCaching(func->ownerClass()))
+ s << "m_PyMethodCache[" << cacheIndex << "] = true;\n";
+ writeVirtualMethodCppCall(s, func, funcName, snips, lastArg, retType,
+ returnStatement.statement, true);
+ s << outdent << "}\n\n"; //WS
+
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionPyOverride,
+ TypeSystem::ShellCode, func, false, lastArg);
+ }
+
+ writeVirtualMethodPythonOverride(s, func, snips, returnStatement);
+}
+
+void CppGenerator::writeVirtualMethodPythonOverride(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const CodeSnipList &snips,
+ const VirtualMethodReturn &returnStatement) const
+{
+ writeConversionRule(s, func, TypeSystem::TargetLangCode, false);
+
+ bool invalidateReturn = false;
+ QList<int> invalidateArgs;
+ for (const FunctionModification &funcMod : func->modifications()) {
+ for (const ArgumentModification &argMod : funcMod.argument_mods()) {
+ const int index = argMod.index();
+ if (index == 0) {
+ if (argMod.targetOwnerShip() == TypeSystem::CppOwnership)
+ invalidateReturn = true;
+ } else {
+ const int actualIndex = func->actualArgumentIndex(index - 1) + 1;
+ if (argMod.resetAfterUse() && !invalidateArgs.contains(actualIndex))
+ invalidateArgs.append(actualIndex);
+ }
+ }
+ }
+ std::sort(invalidateArgs.begin(), invalidateArgs.end());
+
+ auto arguments = func->arguments();
+ auto removedEnd = std::stable_partition(arguments.begin(), arguments.end(),
+ isArgumentNotRemoved);
+ if (func->isAbstract()) { // Base function is not called, indicate unused arguments.
+ for (auto it = removedEnd; it != arguments.end(); ++it)
+ s << sbkUnusedVariableCast(it->name());
+ }
+ arguments.erase(removedEnd, arguments.end());
+
+ // FIXME PYSIDE-7: new functions PyObject_Vectorcall() (since 3.9) and
+ // PyObject_CallNoArgs() (since 3.9, stable API since 3.10) might have
+ // become part of the stable API?
+
+ // Code snips might expect the args tuple, don't generate new code
+ const bool generateNewCall = snips.isEmpty();
+ const qsizetype argCount = arguments.size();
+ const char *newCallCondition = argCount == 0 ? noArgsCallCondition : vectorCallCondition;
+ if (generateNewCall) {
+ if (argCount > 0) {
+ s << newCallCondition;
+ writeVirtualMethodNativeVectorCallArgs(s, func, arguments, invalidateArgs);
+ s << "#else\n";
+ } else {
+ s << inverseNoArgsCallCondition;
+ }
+ }
+ writeVirtualMethodNativeArgs(s, func, arguments, invalidateArgs);
+ if (generateNewCall)
+ s << "#endif\n";
+ s << '\n';
+
+ if (!snips.isEmpty()) {
+ if (func->injectedCodeUsesPySelf())
+ s << "PyObject *pySelf = BindingManager::instance().retrieveWrapper(this);\n";
+
+ const AbstractMetaArgument *lastArg = func->arguments().isEmpty()
+ ? nullptr : &func->arguments().constLast();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning,
+ TypeSystem::NativeCode, func, false, lastArg);
+ }
+
+ qsizetype returnIndirections = 0;
+
+ if (!func->injectedCodeCallsPythonOverride()) {
+ if (generateNewCall) {
+ s << newCallCondition << "Shiboken::AutoDecRef " << PYTHON_RETURN_VAR << '(';
+ if (argCount > 0) {
+ s << "PyObject_Vectorcall(" << PYTHON_OVERRIDE_VAR << ", "
+ << PYTHON_ARGS_ARRAY << ", " << argCount << ", nullptr));\n";
+ for (int argIndex : std::as_const(invalidateArgs)) {
+ s << "if (invalidateArg" << argIndex << ")\n" << indent
+ << "Shiboken::Object::invalidate(" << PYTHON_ARGS_ARRAY
+ << '[' << (argIndex - 1) << "]);\n" << outdent;
+ }
+ for (qsizetype i = 0, size = arguments.size(); i < size; ++i)
+ s << "Py_DECREF(" << PYTHON_ARGS_ARRAY << '[' << i << "]);\n";
+ } else {
+ s << "PyObject_CallNoArgs(" << PYTHON_OVERRIDE_VAR << "));\n";
+ }
+ s << "#else\n";
+ }
+ s << "Shiboken::AutoDecRef " << PYTHON_RETURN_VAR << "(PyObject_Call("
+ << PYTHON_OVERRIDE_VAR << ", " << PYTHON_ARGS << ", nullptr));\n";
+
+ for (int argIndex : std::as_const(invalidateArgs)) {
+ s << "if (invalidateArg" << argIndex << ")\n" << indent
+ << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" << PYTHON_ARGS
+ << ", " << (argIndex - 1) << "));\n" << outdent;
+ }
+ if (generateNewCall)
+ s << "#endif\n";
+
+ s << "if (" << PYTHON_RETURN_VAR << ".isNull()) {\n" << indent
+ << "// An error happened in python code!\n"
+ << "Shiboken::Errors::storePythonOverrideErrorOrPrint(\""
+ << func->ownerClass()->name() << "\", funcName);\n"
+ << returnStatement.statement << "\n" << outdent
+ << "}\n";
+
+ if (invalidateReturn) {
+ s << "bool invalidateArg0 = Py_REFCNT(" << PYTHON_RETURN_VAR << ") == 1;\n"
+ << "if (invalidateArg0)\n" << indent
+ << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR
+ << ".object());\n" << outdent;
+ }
+
+ if (!func->isVoid()) {
+
+ if (func->modifiedTypeName() != cPyObjectT) {
+
+ s << "// Check return type\n";
+
+ if (!func->isTypeModified()) {
+
+ s << PYTHON_TO_CPPCONVERSION_STRUCT << ' '
+ << PYTHON_TO_CPP_VAR << " =\n" << indent
+ << cpythonIsConvertibleFunction(func->type())
+ << PYTHON_RETURN_VAR << ");\n" << outdent
+ << "if (!" << PYTHON_TO_CPP_VAR << ") {\n" << indent
+ << "Shiboken::Warnings::warnInvalidReturnValue(\""
+ << func->ownerClass()->name() << "\", funcName, "
+ << getVirtualFunctionReturnTypeName(func) << ", "
+ << "Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n"
+ << returnStatement.statement << '\n' << outdent
+ << "}\n";
+
+ } else {
+
+ s << "bool typeIsValid = ";
+ if (func->isTypeModified()) {
+ writeTypeCheck(s, func->modifiedTypeName(), PYTHON_RETURN_VAR);
+ } else {
+ const bool numberType = isNumber(func->type().typeEntry());
+ writeTypeCheck(s, func->type(), PYTHON_RETURN_VAR, numberType);
+ }
+
+ s << ";\n";
+ s << "if (!typeIsValid";
+ if (func->type().isPointerToWrapperType())
+ s << " && " << PYTHON_RETURN_VAR << " != Py_None";
+ s << ") {\n" << indent
+ << "Shiboken::Warnings::warnInvalidReturnValue(\""
+ << func->ownerClass()->name() << "\", funcName, "
+ << getVirtualFunctionReturnTypeName(func) << ", "
+ << "Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n"
+ << returnStatement.statement << '\n' << outdent
+ << "}\n";
+
+ }
+ }
+
+ if (func->hasConversionRule(TypeSystem::NativeCode, 0)) {
+ writeConversionRule(s, func, TypeSystem::NativeCode, CPP_RETURN_VAR);
+ } else if (!func->injectedCodeHasReturnValueAttribution(TypeSystem::NativeCode)) {
+ returnIndirections = writePythonToCppTypeConversion(
+ s, func->type(), PYTHON_RETURN_VAR,
+ CPP_RETURN_VAR, func->implementingClass(), {});
+ }
+ }
+ }
+
+ for (const FunctionModification &funcMod : func->modifications()) {
+ for (const ArgumentModification &argMod : funcMod.argument_mods()) {
+ if (argMod.index() == 0
+ && argMod.nativeOwnership() == TypeSystem::CppOwnership) {
+ s << "if (Shiboken::Object::checkType(" << PYTHON_RETURN_VAR << "))\n" << indent
+ << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ");\n"
+ << outdent;
+ }
+ }
+ }
+
+ if (func->hasInjectedCode()) {
+ s << '\n';
+ const AbstractMetaArgument *lastArg = func->arguments().isEmpty()
+ ? nullptr : &func->arguments().constLast();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd,
+ TypeSystem::NativeCode, func, false, lastArg);
+ }
+
+ if (!func->isVoid()) {
+ s << "return ";
+ TypeEntryCPtr retType = func->type().typeEntry();
+ if (avoidProtectedHack() && retType->isEnum()) {
+ auto metaEnum = api().findAbstractMetaEnum(retType);
+ bool isProtectedEnum = metaEnum.has_value() && metaEnum->isProtected();
+ if (isProtectedEnum) {
+ QString typeCast;
+ if (metaEnum->enclosingClass())
+ typeCast += getFullTypeName(metaEnum->enclosingClass());
+ typeCast += u"::"_s + metaEnum->name();
+ s << '(' << typeCast << ')';
+ }
+ }
+
+ if (returnIndirections > 0)
+ s << QByteArray(returnIndirections, '*');
+ s << CPP_RETURN_VAR << ";\n";
+ }
+
+ s << outdent << "}\n\n";
+}
+
+void CppGenerator::writeUserAddedPythonOverride(TextStream &s,
+ const AbstractMetaFunctionCPtr &func) const
+{
+ TypeEntryCPtr retType = func->type().typeEntry();
+ const QString funcName = func->isOperatorOverload()
+ ? pythonOperatorFunctionName(func) : func->definitionNames().constFirst();
+
+ const CodeSnipList snips = func->hasInjectedCode()
+ ? func->injectedCodeSnips() : CodeSnipList();
+
+ QString prefix = wrapperName(func->ownerClass()) + u"::"_s;
+ s << '\n' << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues |
+ Generator::OriginalTypeDescription)
+ << "\n{\n" << indent << sbkUnusedVariableCast("gil");
+
+ writeFuncNameVar(s, func, funcName);
+
+ const auto returnStatement = virtualMethodReturn(api(), func,
+ func->modifications());
+ writeVirtualMethodPythonOverride(s, func, snips, returnStatement);
+}
+
+void CppGenerator::writeMetaObjectMethod(TextStream &s,
+ const GeneratorContext &classContext) const
+{
+
+ const QString wrapperClassName = classContext.wrapperName();
+ const QString qualifiedCppName = classContext.metaClass()->qualifiedCppName();
+ s << "const QMetaObject *" << wrapperClassName << "::metaObject() const\n{\n";
+ s << indent << "if (QObject::d_ptr->metaObject != nullptr)\n"
+ << indent << "return QObject::d_ptr->dynamicMetaObject();\n" << outdent
+ << "SbkObject *pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);\n"
+ << "if (pySelf == nullptr)\n"
+ << indent << "return " << qualifiedCppName << "::metaObject();\n" << outdent
+ << "return PySide::SignalManager::retrieveMetaObject("
+ "reinterpret_cast<PyObject *>(pySelf));\n"
+ << outdent << "}\n\n";
+
+ // qt_metacall function
+ s << "int " << wrapperClassName
+ << "::qt_metacall(QMetaObject::Call call, int id, void **args)\n";
+ s << "{\n" << indent;
+
+ const auto list = classContext.metaClass()->queryFunctionsByName(u"qt_metacall"_s);
+
+ CodeSnipList snips;
+ if (list.size() == 1) {
+ const auto &func = list.constFirst();
+ snips = func->injectedCodeSnips();
+ if (func->isUserAdded()) {
+ CodeSnipList snips = func->injectedCodeSnips();
+ const bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(func);
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny,
+ TypeSystem::NativeCode, func, usePyArgs, nullptr);
+ }
+ }
+
+ s << "int result = " << qualifiedCppName << "::qt_metacall(call, id, args);\n"
+ << "return result < 0 ? result : PySide::SignalManager::qt_metacall("
+ "this, call, id, args);\n"
+ << outdent << "}\n\n";
+
+ // qt_metacast function
+ writeMetaCast(s, classContext);
+}
+
+void CppGenerator::writeMetaCast(TextStream &s,
+ const GeneratorContext &classContext)
+{
+ const QString wrapperClassName = classContext.wrapperName();
+ const QString qualifiedCppName = classContext.metaClass()->qualifiedCppName();
+ s << "void *" << wrapperClassName << "::qt_metacast(const char *_clname)\n{\n"
+ << indent << "if (_clname == nullptr)\n" << indent << "return {};\n" << outdent
+ << "SbkObject *pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);\n"
+ << "if (pySelf != nullptr && PySide::inherits(Py_TYPE(pySelf), _clname))\n"
+ << indent << "return static_cast<void *>(const_cast< "
+ << wrapperClassName << " *>(this));\n" << outdent
+ << "return " << qualifiedCppName << "::qt_metacast(_clname);\n"
+ << outdent << "}\n\n";
+}
+
+static void generateDeprecatedValueWarnings(TextStream &c,
+ const AbstractMetaEnum &metaEnum,
+ bool useSurrogateName)
+{
+ EnumTypeEntryCPtr enumType = metaEnum.typeEntry();
+ const QString prefix = enumType->qualifiedCppName() + u"::"_s;
+ c << "switch (value) {\n";
+ const auto &deprecatedValues = metaEnum.deprecatedValues();
+ for (const auto &v : deprecatedValues) {
+ c << "case ";
+ if (useSurrogateName)
+ c << v.value().toString(); // Protected, use int representation
+ else
+ c << prefix << v.name();
+ c << ":\n" << indent
+ << "Shiboken::Warnings::warnDeprecatedEnumValue(\"" << enumType->name()
+ << "\", \"" << v.name() << "\");\nbreak;\n" << outdent;
+ }
+ if (deprecatedValues.size() < metaEnum.values().size())
+ c << "default:\n" << indent << "break;\n" << outdent;
+ c << "}\n";
+}
+
+void CppGenerator::writeEnumConverterFunctions(TextStream &s, const AbstractMetaEnum &metaEnum) const
+{
+ if (metaEnum.isPrivate() || metaEnum.isAnonymous())
+ return;
+ EnumTypeEntryCPtr enumType = metaEnum.typeEntry();
+ Q_ASSERT(enumType);
+ QString typeName = fixedCppTypeName(enumType);
+ QString enumPythonType = cpythonTypeNameExt(enumType);
+ const bool useSurrogateName = avoidProtectedHack() && metaEnum.isProtected();
+ QString cppTypeName = useSurrogateName
+ ? protectedEnumSurrogateName(metaEnum) : getFullTypeName(enumType).trimmed();
+
+ StringStream c(TextStream::Language::Cpp);
+ if (metaEnum.isDeprecated())
+ c << "Shiboken::Warnings::warnDeprecatedEnum(\"" << enumType->name() << "\");\n";
+
+ c << "const auto value = static_cast<" << cppTypeName
+ << ">(Shiboken::Enum::getValue(pyIn));\n";
+
+ // Warn about deprecated values unless it is protected+scoped (inaccessible values)
+ const bool valuesAcccessible = !useSurrogateName || metaEnum.enumKind() != EnumClass;
+ if (valuesAcccessible && metaEnum.hasDeprecatedValues())
+ generateDeprecatedValueWarnings(c, metaEnum, useSurrogateName);
+
+ c << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) = value;\n";
+
+ ConfigurableScope configScope(s, enumType);
+ writePythonToCppFunction(s, c.toString(), typeName, typeName);
+
+ QString pyTypeCheck = u"PyObject_TypeCheck(pyIn, "_s + enumPythonType + u')';
+ writeIsPythonConvertibleToCppFunction(s, typeName, typeName, pyTypeCheck);
+
+ c.clear();
+
+ c << "const int castCppIn = int(*reinterpret_cast<const "
+ << cppTypeName << " *>(cppIn));\n" << "return "
+ << "Shiboken::Enum::newItem(" << enumPythonType << ", castCppIn);\n";
+ writeCppToPythonFunction(s, c.toString(), typeName, typeName);
+ 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
+{
+ s << "// Type conversion functions.\n\n";
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ auto typeEntry = metaClass->typeEntry();
+ metaClass->getEnumsFromInvisibleNamespacesToBeGenerated(&classEnums);
+ if (!classEnums.isEmpty())
+ s << "// Python to C++ enum conversion.\n";
+ for (const AbstractMetaEnum &metaEnum : std::as_const(classEnums))
+ writeEnumConverterFunctions(s, metaEnum);
+
+ if (metaClass->isNamespace())
+ return;
+
+ QString typeName;
+ if (!classContext.forSmartPointer())
+ typeName = getFullTypeName(metaClass);
+ else
+ typeName = getFullTypeName(classContext.preciseType());
+
+ QString cpythonType = cpythonTypeName(metaClass);
+
+ // Returns the C++ pointer of the Python wrapper.
+ s << "// Python to C++ pointer conversion - returns the C++ object of the Python wrapper (keeps object identity).\n";
+
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = metaClass->name() + u"_PTR"_s;
+ StringStream c(TextStream::Language::Cpp);
+ c << "Shiboken::Conversions::pythonToCppPointer(" << cpythonType << ", pyIn, cppOut);";
+ writePythonToCppFunction(s, c.toString(), sourceTypeName, targetTypeName);
+
+ // "Is convertible" function for the Python object to C++ pointer conversion.
+ const QString pyTypeCheck = u"PyObject_TypeCheck(pyIn, "_s + cpythonType + u")"_s;
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true);
+ s << '\n';
+
+ // C++ pointer to a Python wrapper, keeping identity.
+ s << "// C++ to Python pointer conversion - tries to find the Python wrapper for the C++ object (keeps object identity).\n";
+ c.clear();
+ if (usePySideExtensions() && isQObject(metaClass)) {
+ c << "return PySide::getWrapperForQObject(reinterpret_cast<"
+ << typeName << " *>(const_cast<void *>(cppIn)), " << cpythonType << ");\n";
+ } else {
+ writePointerToPythonConverter(c, metaClass, typeName, cpythonType);
+ }
+ std::swap(targetTypeName, sourceTypeName);
+ writeCppToPythonFunction(s, c.toString(), sourceTypeName, targetTypeName);
+
+ // The conversions for an Object Type end here.
+ if (!typeEntry->isValue() && !typeEntry->isSmartPointer()) {
+ s << '\n';
+ return;
+ }
+
+ // Always copies C++ value (not pointer, and not reference) to a new Python wrapper.
+ s << '\n' << "// C++ to Python copy conversion.\n";
+ targetTypeName = metaClass->name();
+
+ sourceTypeName = targetTypeName + u"_COPY"_s;
+
+ c.clear();
+
+ const bool isUniquePointer = classContext.forSmartPointer()
+ && typeEntry->isUniquePointer();
+
+ if (isUniquePointer) {
+ c << "auto *source = reinterpret_cast<" << typeName
+ << " *>(const_cast<void *>(cppIn));\n";
+ } else {
+ c << "auto *source = reinterpret_cast<const " << typeName << " *>(cppIn);\n";
+ }
+ c << "return Shiboken::Object::newObject(" << cpythonType
+ << ", new " << globalScopePrefix(classContext) << classContext.effectiveClassName() << '('
+ << (isUniquePointer ? "std::move(*source)" : "*source")
+ << "), true, true);";
+ writeCppToPythonFunction(s, c.toString(), sourceTypeName, targetTypeName);
+ s << '\n';
+
+ // Python to C++ copy conversion.
+ s << "// Python to C++ copy conversion.\n";
+ sourceTypeName = metaClass->name();
+
+ targetTypeName = sourceTypeName + "_COPY"_L1;
+ c.clear();
+
+ QString pyInVariable = u"pyIn"_s;
+ const QString outPtr = u"reinterpret_cast<"_s + typeName + u" *>(cppOut)"_s;
+ if (!classContext.forSmartPointer()) {
+ c << '*' << outPtr << " = *"
+ << cpythonWrapperCPtr(typeEntry, pyInVariable) << ';';
+ } else {
+ auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(typeEntry);
+ const QString resetMethod = ste->resetMethod();
+ c << "auto *ptr = " << outPtr << ";\n";
+ c << "if (" << pyInVariable << " == Py_None)\n" << indent;
+ if (resetMethod.isEmpty())
+ c << "*ptr = {};\n";
+ else
+ c << "ptr->" << resetMethod << "();\n";
+ const QString value = u'*' + cpythonWrapperCPtr(classContext.preciseType(), pyInVariable);
+ c << outdent << "else\n" << indent
+ << "*ptr = " << (isUniquePointer ? stdMove(value) : value) << ';';
+ }
+
+ writePythonToCppFunction(s, c.toString(), sourceTypeName, targetTypeName);
+
+ // "Is convertible" function for the Python object to C++ value copy conversion.
+ QString copyTypeCheck = pyTypeCheck;
+ if (classContext.forSmartPointer())
+ copyTypeCheck.prepend(pyInVariable + u" == Py_None || "_s);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, copyTypeCheck);
+ s << '\n';
+
+ // User provided implicit conversions.
+ // Implicit conversions.
+ const AbstractMetaFunctionCList implicitConvs = implicitConversions(typeEntry);
+
+ if (!implicitConvs.isEmpty())
+ s << "// Implicit conversions.\n";
+
+ AbstractMetaType targetType = AbstractMetaType::fromAbstractMetaClass(metaClass);
+ for (const auto &conv : std::as_const(implicitConvs)) {
+ if (conv->isModifiedRemoved())
+ continue;
+
+ QString typeCheck;
+ QString toCppConv;
+ QString toCppPreConv;
+ if (conv->isConversionOperator()) {
+ const auto sourceClass = conv->ownerClass();
+ typeCheck = u"PyObject_TypeCheck(pyIn, "_s
+ + cpythonTypeNameExt(sourceClass->typeEntry()) + u')';
+ toCppConv = u'*' + cpythonWrapperCPtr(sourceClass->typeEntry(),
+ pyInVariable);
+ } else {
+ // Constructor that does implicit conversion.
+ const auto &firstArg = conv->arguments().constFirst();
+ if (firstArg.isTypeModified() || conv->isModifiedToArray(1))
+ continue;
+ const AbstractMetaType &sourceType = firstArg.type();
+ if (sourceType.isWrapperType()) {
+ if (sourceType.referenceType() == LValueReference
+ || !sourceType.isPointerToWrapperType()) {
+ toCppConv = u" *"_s;
+ }
+ toCppConv += cpythonWrapperCPtr(sourceType.typeEntry(), pyInVariable);
+ }
+
+ typeCheck = cpythonCheckFunction(sourceType);
+ if (typeCheck.endsWith(u", ")) {
+ typeCheck += pyInVariable + u')';
+ } else if (typeCheck != u"true" && typeCheck != u"false") {
+ typeCheck += u'(' + pyInVariable + u')';
+ }
+
+ if (sourceType.isUserPrimitive()
+ || sourceType.isExtendedCppPrimitive()
+ || sourceType.typeEntry()->isContainer()
+ || sourceType.typeEntry()->isEnum()
+ || sourceType.typeEntry()->isFlags()) {
+ StringStream pc(TextStream::Language::Cpp);
+ pc << getFullTypeNameWithoutModifiers(sourceType) << " cppIn"
+ << minimalConstructorExpression(api(), sourceType) << ";\n";
+ writeToCppConversion(pc, sourceType, pyInVariable,
+ u"cppIn"_s);
+ pc << ';';
+ toCppPreConv = pc.toString();
+ toCppConv.append(u"cppIn"_s);
+ } else if (!sourceType.isWrapperType()) {
+ StringStream tcc(TextStream::Language::Cpp);
+ writeToCppConversion(tcc, sourceType, pyInVariable,
+ u"/*BOZO-1061*/"_s);
+ toCppConv = tcc.toString();
+ }
+ }
+ const AbstractMetaType sourceType = conv->isConversionOperator()
+ ? AbstractMetaType::fromAbstractMetaClass(conv->ownerClass())
+ : conv->arguments().constFirst().type();
+ writePythonToCppConversionFunctions(s, sourceType, targetType, typeCheck, toCppConv, toCppPreConv);
+ }
+
+ if (typeEntry->isValue()) {
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry);
+ writeCustomConverterFunctions(s, vte->customConversion());
+ }
+}
+
+void CppGenerator::writeCustomConverterFunctions(TextStream &s,
+ const CustomConversionPtr &customConversion) const
+{
+ if (!customConversion)
+ return;
+ const TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+ auto ownerType = customConversion->ownerType();
+ s << "// Python to C++ conversions for type '" << ownerType->qualifiedCppName() << "'.\n";
+ for (const auto &toNative : toCppConversions)
+ writePythonToCppConversionFunctions(s, toNative, ownerType);
+ s << '\n';
+}
+
+void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext) const
+{
+ const auto typeEntry = metaClass->typeEntry();
+ if (typeEntry->isNamespace())
+ return;
+ s << "// Register Converter\n"
+ << "SbkConverter *converter = Shiboken::Conversions::createConverter(pyType,\n"
+ << indent;
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = sourceTypeName + u"_PTR"_s;
+ s << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << '\n'
+ << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << '\n';
+ std::swap(targetTypeName, sourceTypeName);
+ s << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ if (typeEntry->isValue() || typeEntry->isSmartPointer()) {
+ s << ',' << '\n';
+ sourceTypeName = metaClass->name() + u"_COPY"_s;
+ s << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ }
+ s << outdent << ");\n\n";
+
+ auto writeConversions = [&s](const QString &signature)
+ {
+ s << registerConverterName(signature) << registerConverterName(signature + u'*')
+ << registerConverterName(signature + u'&');
+ };
+
+ auto writeConversionsForType = [writeConversions](const QString &fullTypeName)
+ {
+ QStringList lst = fullTypeName.split(u"::"_s,
+ Qt::SkipEmptyParts);
+ while (!lst.isEmpty()) {
+ QString signature = lst.join(u"::"_s);
+ writeConversions(signature);
+ lst.removeFirst();
+ }
+ };
+
+
+ if (!classContext.forSmartPointer()) {
+ writeConversionsForType(metaClass->qualifiedCppName());
+ } else {
+ const QString &smartPointerType = classContext.preciseType().instantiations().at(0).cppSignature();
+ const QString &smartPointerName = classContext.preciseType().typeEntry()->name();
+
+ QStringList lst = smartPointerType.split(u"::"_s,
+ Qt::SkipEmptyParts);
+ while (!lst.isEmpty()) {
+ QString signature = lst.join(u"::"_s);
+ writeConversions(smartPointerName + u'<' + signature + u'>');
+ lst.removeFirst();
+ }
+
+ writeConversionsForType(smartPointerType);
+ }
+
+ s << "Shiboken::Conversions::registerConverterName(converter, typeid(" << m_gsp;
+ QString qualifiedCppNameInvocation;
+ if (!classContext.forSmartPointer())
+ qualifiedCppNameInvocation = metaClass->qualifiedCppName();
+ else
+ qualifiedCppNameInvocation = classContext.preciseType().cppSignature();
+
+ s << qualifiedCppNameInvocation << ").name());\n";
+
+ if (classContext.useWrapper()) {
+ s << "Shiboken::Conversions::registerConverterName(converter, typeid("
+ << classContext.wrapperName() << ").name());\n";
+ }
+
+ if (!typeEntry->isValue() && !typeEntry->isSmartPointer())
+ return;
+
+ // Python to C++ copy (value, not pointer neither reference) conversion.
+ s << "\n// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter.\n";
+ sourceTypeName = metaClass->name();
+ targetTypeName = sourceTypeName + u"_COPY"_s;
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ writeAddPythonToCppConversion(s, u"converter"_s, toCpp, isConv);
+
+ // User provided implicit conversions.
+
+ // Add implicit conversions.
+ const AbstractMetaFunctionCList implicitConvs = implicitConversions(typeEntry);
+
+ if (!implicitConvs.isEmpty())
+ s << "// Add implicit conversions to type converter.\n";
+
+ AbstractMetaType targetType = AbstractMetaType::fromAbstractMetaClass(metaClass);
+ for (const auto &conv : std::as_const(implicitConvs)) {
+ if (conv->isModifiedRemoved())
+ continue;
+ AbstractMetaType sourceType;
+ if (conv->isConversionOperator()) {
+ sourceType = AbstractMetaType::fromAbstractMetaClass(conv->ownerClass());
+ } else {
+ // Constructor that does implicit conversion.
+ const auto &firstArg = conv->arguments().constFirst();
+ if (firstArg.isTypeModified() || conv->isModifiedToArray(1))
+ continue;
+ sourceType = firstArg.type();
+ }
+ QString toCpp = pythonToCppFunctionName(sourceType, targetType);
+ QString isConv = convertibleToCppFunctionName(sourceType, targetType);
+ writeAddPythonToCppConversion(s, u"converter"_s, toCpp, isConv);
+ }
+
+ if (typeEntry->isValue()) {
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry);
+ writeCustomConverterRegister(s, vte->customConversion(), u"converter"_s);
+ }
+}
+
+void CppGenerator::writeCustomConverterRegister(TextStream &s,
+ const CustomConversionPtr &customConversion,
+ const QString &converterVar)
+{
+ if (!customConversion)
+ return;
+ const TargetToNativeConversions &toCppConversions =
+ customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+ s << "// Add user defined implicit conversions to type converter.\n";
+ for (const auto &toNative : toCppConversions) {
+ QString toCpp = pythonToCppFunctionName(toNative, customConversion->ownerType());
+ QString isConv = convertibleToCppFunctionName(toNative, customConversion->ownerType());
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+ }
+}
+
+void CppGenerator::writeContainerConverterFunctions(TextStream &s,
+ const AbstractMetaType &containerType) const
+{
+ writeCppToPythonFunction(s, containerType);
+ writePythonToCppConversionFunctions(s, containerType);
+}
+
+bool CppGenerator::needsArgumentErrorHandling(const OverloadData &overloadData)
+{
+ if (overloadData.maxArgs() > 0)
+ return true;
+ // QObject constructors need error handling when passing properties as kwarg.
+ if (!usePySideExtensions())
+ return false;
+ auto rfunc = overloadData.referenceFunction();
+ return rfunc->functionType() == AbstractMetaFunction::ConstructorFunction
+ && isQObject(rfunc->ownerClass());
+}
+
+void CppGenerator::writeMethodWrapperPreamble(TextStream &s,
+ const OverloadData &overloadData,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn)
+{
+ const auto rfunc = overloadData.referenceFunction();
+ const auto ownerClass = rfunc->targetLangOwner();
+ Q_ASSERT(ownerClass == context.metaClass());
+ int minArgs = overloadData.minArgs();
+ int maxArgs = overloadData.maxArgs();
+ bool initPythonArguments;
+
+ // If method is a constructor...
+ if (rfunc->isConstructor()) {
+ // Check if the right constructor was called.
+ if (!ownerClass->hasPrivateDestructor()) {
+ s << "if (Shiboken::Object::isUserType(self) && "
+ << "!Shiboken::ObjectType::canCallConstructor(self->ob_type, Shiboken::SbkType< "
+ << m_gsp;
+ QString qualifiedCppName;
+ if (!context.forSmartPointer())
+ qualifiedCppName = ownerClass->qualifiedCppName();
+ else
+ qualifiedCppName = context.preciseType().cppSignature();
+
+ s << qualifiedCppName << " >()))\n" << indent << errorReturn << outdent << '\n';
+ }
+ // Declare pointer for the underlying C++ object.
+ s << globalScopePrefix(context) << context.effectiveClassName() << " *cptr{};\n";
+
+ initPythonArguments = maxArgs > 0;
+
+ } else {
+ if (rfunc->implementingClass() &&
+ (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) {
+ CppSelfDefinitionFlags flags;
+ if (overloadData.hasStaticFunction())
+ flags.setFlag(CppSelfDefinitionFlag::HasStaticOverload);
+ if (overloadData.hasClassMethod())
+ flags.setFlag(CppSelfDefinitionFlag::HasClassMethodOverload);
+ writeCppSelfDefinition(s, rfunc, context, errorReturn, flags);
+ }
+ if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType())
+ s << "PyObject *" << PYTHON_RETURN_VAR << "{};\n";
+
+ initPythonArguments = minArgs != maxArgs || maxArgs > 1;
+ }
+
+ if (needsArgumentErrorHandling(overloadData))
+ s << "Shiboken::AutoDecRef errInfo{};\n";
+
+ s << "static const char fullName[] = \"" << fullPythonFunctionName(rfunc, true)
+ << "\";\nSBK_UNUSED(fullName)\n"
+ << "Shiboken::PythonContextMarker pcm;\n";
+ // PYSIDE-2335: Mark blocking calls like `exec` or `run` as such.
+ bool isBlockingFunction = rfunc->name() == u"exec"_s || rfunc->name() == u"exec_"_s
+ || rfunc->name() == u"run"_s;
+ if (isBlockingFunction)
+ s << "pcm.setBlocking();\n";
+
+ if (maxArgs > 0) {
+ s << "int overloadId = -1;\n"
+ << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR;
+ if (overloadData.pythonFunctionWrapperUsesListOfArguments())
+ s << '[' << maxArgs << ']';
+ s << ";\n" << sbkUnusedVariableCast(PYTHON_TO_CPP_VAR);
+ }
+
+ if (initPythonArguments) {
+ s << "const Py_ssize_t numArgs = ";
+ if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor()
+ && !overloadData.pythonFunctionWrapperUsesListOfArguments()) {
+ s << "(" << PYTHON_ARG << " == 0 ? 0 : 1);\n";
+ } else {
+ writeArgumentsInitializer(s, overloadData, errorReturn);
+ }
+ }
+}
+
+void CppGenerator::writeConstructorWrapper(TextStream &s, const OverloadData &overloadData,
+ const GeneratorContext &classContext) const
+{
+ const ErrorReturn errorReturn = ErrorReturn::MinusOne;
+
+ const auto rfunc = overloadData.referenceFunction();
+ const auto metaClass = rfunc->ownerClass();
+
+ s << "static int\n";
+ s << cpythonFunctionName(rfunc)
+ << "(PyObject *self, PyObject *args, PyObject *kwds)\n{\n" << indent;
+ if (overloadData.maxArgs() == 0 || metaClass->isAbstract())
+ s << sbkUnusedVariableCast("args");
+ s << sbkUnusedVariableCast("kwds");
+
+ const bool needsMetaObject = usePySideExtensions() && isQObject(metaClass);
+ if (needsMetaObject)
+ s << "const QMetaObject *metaObject;\n";
+
+ s << "auto *sbkSelf = reinterpret_cast<SbkObject *>(self);\n";
+
+ if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) {
+ s << "PyTypeObject *type = self->ob_type;\n"
+ << "PyTypeObject *myType = "
+ << cpythonTypeNameExt(metaClass->typeEntry()) << ";\n";
+ }
+
+ if (metaClass->isAbstract()) {
+ // C++ Wrapper disabled: Abstract C++ class cannot be instantiated.
+ if (metaClass->typeEntry()->typeFlags().testFlag(ComplexTypeEntry::DisableWrapper)) {
+ s << sbkUnusedVariableCast("sbkSelf")
+ << sbkUnusedVariableCast("type")
+ << sbkUnusedVariableCast("myType");
+ if (needsMetaObject)
+ s << sbkUnusedVariableCast("metaObject");
+ s << "Shiboken::Errors::setInstantiateAbstractClassDisabledWrapper(\""
+ << metaClass->qualifiedCppName() << "\");\n" << errorReturn << outdent
+ << "}\n\n";
+ return;
+ }
+
+ // Refuse to instantiate Abstract C++ class (via C++ Wrapper) unless it is
+ // a Python-derived class for which type != myType.
+ s << "if (type == myType) {\n" << indent
+ << "Shiboken::Errors::setInstantiateAbstractClass(\"" << metaClass->qualifiedCppName()
+ << "\");\n" << errorReturn << outdent
+ << "}\n\n";
+ }
+
+ if (metaClass->baseClassNames().size() > 1) {
+ if (!metaClass->isAbstract())
+ s << "if (type != myType)\n" << indent;
+ s << "Shiboken::ObjectType::copyMultipleInheritance(type, myType);\n";
+ if (!metaClass->isAbstract())
+ s << outdent << '\n';
+ }
+
+ // PYSIDE-1478: Switching must also happen at object creation time.
+ if (usePySideExtensions() && !classContext.forSmartPointer())
+ s << "PySide::Feature::Select(self);\n";
+
+ writeMethodWrapperPreamble(s, overloadData, classContext, errorReturn);
+
+ s << '\n';
+
+ if (overloadData.maxArgs() > 0)
+ writeOverloadedFunctionDecisor(s, overloadData, errorReturn);
+
+ // Handles Python Multiple Inheritance
+ QString pre = needsMetaObject ? u"bool usesPyMI = "_s : u""_s;
+ s << "\n// PyMI support\n"
+ << pre << "Shiboken::callInheritedInit(self, args, kwds, fullName);\n"
+ << "if (" << shibokenErrorsOccurred << ")\n"
+ << indent << errorReturn << outdent << "\n";
+
+ writeFunctionCalls(s, overloadData, classContext, errorReturn);
+ s << '\n';
+
+ const QString typeName = classContext.forSmartPointer()
+ ? classContext.preciseType().cppSignature() : metaClass->qualifiedCppName();
+ s << "if (" << shibokenErrorsOccurred
+ << " || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< "
+ << globalScopePrefix(classContext) << typeName << " >(), cptr)) {\n"
+ << indent << "delete cptr;\n" << errorReturn << outdent
+ << "}\n";
+ if (overloadData.maxArgs() > 0)
+ s << "if (cptr == nullptr)\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n\n"
+ << outdent;
+
+ s << "Shiboken::Object::setValidCpp(sbkSelf, true);\n";
+ // If the created C++ object has a C++ wrapper the ownership is assigned to Python
+ // (first "1") and the flag indicating that the Python wrapper holds an C++ wrapper
+ // is marked as true (the second "1"). Otherwise the default values apply:
+ // Python owns it and C++ wrapper is false.
+ if (shouldGenerateCppWrapper(overloadData.referenceFunction()->ownerClass()))
+ s << "Shiboken::Object::setHasCppWrapper(sbkSelf, true);\n";
+ // Need to check if a wrapper for same pointer is already registered
+ // Caused by bug PYSIDE-217, where deleted objects' wrappers are not released
+ s << "if (Shiboken::BindingManager::instance().hasWrapper(cptr)) {\n" << indent
+ << "Shiboken::BindingManager::instance().releaseWrapper("
+ "Shiboken::BindingManager::instance().retrieveWrapper(cptr));\n" << outdent
+ << "}\nShiboken::BindingManager::instance().registerWrapper(sbkSelf, cptr);\n";
+
+ // Create metaObject and register signal/slot
+ if (needsMetaObject) {
+ s << "\n// QObject setup\n"
+ << "PySide::Signal::updateSourceObject(self);\n"
+ << "metaObject = cptr->metaObject(); // <- init python qt properties\n"
+ << "if (!errInfo.isNull() && PyDict_Check(errInfo.object())) {\n" << indent
+ << "if (!PySide::fillQtProperties(self, metaObject, errInfo, usesPyMI))\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent << outdent
+ << "};\n";
+ }
+
+ // Constructor code injections, position=end
+ bool hasCodeInjectionsAtEnd = false;
+ for (const auto &func : overloadData.overloads()) {
+ const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips();
+ for (const CodeSnip &cs : injectedCodeSnips) {
+ if (cs.position == TypeSystem::CodeSnipPositionEnd) {
+ hasCodeInjectionsAtEnd = true;
+ break;
+ }
+ }
+ }
+ if (hasCodeInjectionsAtEnd) {
+ // FIXME: C++ arguments are not available in code injection on constructor when position = end.
+ s << "switch (overloadId) {\n";
+ for (const auto &func : overloadData.overloads()) {
+ s << indent;
+ const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips();
+ for (const CodeSnip &cs : injectedCodeSnips) {
+ if (cs.position == TypeSystem::CodeSnipPositionEnd) {
+ s << "case " << metaClass->functions().indexOf(func) << ':' << '\n'
+ << "{\n" << indent;
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd,
+ TypeSystem::TargetLangCode, func,
+ true /* usesPyArgs */, nullptr);
+ s << outdent << "}\nbreak;\n";
+ break;
+ }
+ }
+ s << outdent;
+ }
+ s << "}\n";
+ }
+
+ s << "\n\nreturn 1;\n";
+ s<< outdent << "}\n\n";
+}
+
+void CppGenerator::writeMethodWrapper(TextStream &s, const OverloadData &overloadData,
+ const GeneratorContext &classContext) const
+{
+ const auto rfunc = overloadData.referenceFunction();
+
+ int maxArgs = overloadData.maxArgs();
+
+ s << "static PyObject *";
+ s << cpythonFunctionName(rfunc) << "(PyObject *self";
+ bool hasKwdArgs = false;
+ if (maxArgs > 0) {
+ s << ", PyObject *"
+ << (overloadData.pythonFunctionWrapperUsesListOfArguments() ? u"args"_s : PYTHON_ARG);
+ hasKwdArgs = overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator();
+ if (hasKwdArgs)
+ s << ", PyObject *kwds";
+ }
+ s << ")\n{\n" << indent;
+ if (rfunc->ownerClass() == nullptr || overloadData.hasStaticFunction())
+ s << sbkUnusedVariableCast(PYTHON_SELF_VAR);
+ if (hasKwdArgs)
+ s << sbkUnusedVariableCast("kwds");
+
+ writeMethodWrapperPreamble(s, overloadData, classContext);
+
+ s << '\n';
+
+ // This code is intended for shift operations only: Make sure reverse <</>>
+ // operators defined in other classes (specially from other modules)
+ // are called. A proper and generic solution would require an reengineering
+ // in the operator system like the extended converters.
+ // Solves #119 - QDataStream <</>> operators not working for QPixmap.
+ const bool hasReturnValue = overloadData.hasNonVoidReturnType();
+
+ if (hasReturnValue && rfunc->functionType() == AbstractMetaFunction::ShiftOperator
+ && rfunc->isBinaryOperator()) {
+ // For custom classes, operations like __radd__ and __rmul__
+ // will enter an infinite loop.
+ const QString pythonOp = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ s << "static PyObject *attrName = Shiboken::PyMagicName::r"
+ << pythonOp.mid(2, pythonOp.size() -4) << "();\n" // Strip __
+ << "if (!isReverse\n" << indent
+ << "&& Shiboken::Object::checkType(" << PYTHON_ARG << ")\n"
+ << "&& !PyObject_TypeCheck(" << PYTHON_ARG << ", self->ob_type)\n"
+ << "&& PyObject_HasAttr(" << PYTHON_ARG << ", attrName)) {\n"
+ << "PyObject *revOpMethod = PyObject_GetAttr(" << PYTHON_ARG << ", attrName);\n"
+ << "if (revOpMethod && PyCallable_Check(revOpMethod)) {\n" << indent
+ << PYTHON_RETURN_VAR << " = PyObject_CallFunction(revOpMethod, \"O\", self);\n"
+ << "if (" << shibokenErrorsOccurred
+ << " && (PyErr_ExceptionMatches(PyExc_NotImplementedError)"
+ << " || PyErr_ExceptionMatches(PyExc_AttributeError))) {\n" << indent
+ << "PyErr_Clear();\n"
+ << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");\n"
+ << PYTHON_RETURN_VAR << " = " << NULL_PTR << ";\n"
+ << outdent << "}\n"
+ << outdent << "}\n"
+ << "Py_XDECREF(revOpMethod);\n\n"
+ << outdent << "}\n\n"
+ << "// Do not enter here if other object has implemented a reverse operator.\n"
+ << "if (" << PYTHON_RETURN_VAR << " == nullptr) {\n" << indent;
+ if (maxArgs > 0)
+ writeOverloadedFunctionDecisor(s, overloadData, ErrorReturn::Default);
+ writeFunctionCalls(s, overloadData, classContext, ErrorReturn::Default);
+ s << outdent << '\n' << "} // End of \"if (!" << PYTHON_RETURN_VAR << ")\"\n";
+ } else { // binary shift operator
+ if (maxArgs > 0)
+ writeOverloadedFunctionDecisor(s, overloadData, ErrorReturn::Default);
+ writeFunctionCalls(s, overloadData, classContext, ErrorReturn::Default);
+ }
+
+ s << '\n';
+
+ writeFunctionReturnErrorCheckSection(s, ErrorReturn::Default,
+ hasReturnValue && !rfunc->isInplaceOperator());
+
+ if (hasReturnValue) {
+ if (rfunc->isInplaceOperator()) {
+ s << "Py_INCREF(self);\nreturn self;\n";
+ } else {
+ s << "return " << PYTHON_RETURN_VAR << ";\n";
+ }
+ } else {
+ s << "Py_RETURN_NONE;\n";
+ }
+
+ s<< outdent << "}\n\n";
+}
+
+void CppGenerator::writeArgumentsInitializer(TextStream &s, const OverloadData &overloadData,
+ ErrorReturn errorReturn)
+{
+ const auto rfunc = overloadData.referenceFunction();
+ s << "PyTuple_GET_SIZE(args);\n" << sbkUnusedVariableCast("numArgs");
+
+ int minArgs = overloadData.minArgs();
+ int maxArgs = overloadData.maxArgs();
+
+ s << "PyObject *";
+ s << PYTHON_ARGS << "[] = {"
+ << QByteArrayList(maxArgs, "nullptr").join(", ")
+ << "};\n\n";
+
+ if (overloadData.hasVarargs()) {
+ maxArgs--;
+ if (minArgs > maxArgs)
+ minArgs = maxArgs;
+
+ s << "PyObject *nonvarargs = PyTuple_GetSlice(args, 0, " << maxArgs << ");\n"
+ << "Shiboken::AutoDecRef auto_nonvarargs(nonvarargs);\n"
+ << PYTHON_ARGS << '[' << maxArgs << "] = PyTuple_GetSlice(args, "
+ << maxArgs << ", numArgs);\n"
+ << "Shiboken::AutoDecRef auto_varargs(" << PYTHON_ARGS << "["
+ << maxArgs << "]);\n\n";
+ }
+
+ bool usesNamedArguments = overloadData.hasArgumentWithDefaultValue();
+
+ s << "// invalid argument lengths\n";
+
+ // Disable argument count checks for QObject constructors to allow for
+ // passing properties as KW args.
+ const auto owner = rfunc->ownerClass();
+ bool isQObjectConstructor = owner && isQObject(owner)
+ && rfunc->functionType() == AbstractMetaFunction::ConstructorFunction;
+
+ if (usesNamedArguments && !isQObjectConstructor) {
+ s << "errInfo.reset(Shiboken::checkInvalidArgumentCount(numArgs, "
+ << minArgs << ", " << maxArgs << "));\n"
+ << "if (!errInfo.isNull())\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent;
+ }
+
+ const QList<int> invalidArgsLength = overloadData.invalidArgumentLengths();
+ if (!invalidArgsLength.isEmpty()) {
+ s << "if (";
+ for (qsizetype i = 0, size = invalidArgsLength.size(); i < size; ++i) {
+ if (i)
+ s << " || ";
+ s << "numArgs == " << invalidArgsLength.at(i);
+ }
+ s << ")\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent;
+ }
+ s << '\n';
+
+ QString funcName;
+ if (rfunc->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ else
+ funcName = rfunc->name();
+
+ QString argsVar = overloadData.hasVarargs() ? u"nonvarargs"_s : u"args"_s;
+ s << "if (";
+ if (usesNamedArguments) {
+ s << "PyArg_ParseTuple(" << argsVar << ", \"|" << QByteArray(maxArgs, 'O')
+ << ':' << funcName << '"';
+ } else {
+ s << "PyArg_UnpackTuple(" << argsVar << ", \"" << funcName << "\", "
+ << minArgs << ", " << maxArgs;
+ }
+ for (int i = 0; i < maxArgs; i++)
+ s << ", &(" << PYTHON_ARGS << '[' << i << "])";
+ s << ") == 0)\n" << indent << errorReturn << outdent << '\n';
+}
+
+void CppGenerator::writeCppSelfConversion(TextStream &s, const GeneratorContext &context,
+ const QString &className, bool useWrapperClass)
+{
+ if (context.forSmartPointer()) {
+ writeSmartPointerCppSelfConversion(s, context);
+ return;
+ }
+
+ if (useWrapperClass)
+ s << "static_cast<" << className << " *>(";
+ s << cpythonWrapperCPtr(context.metaClass(), PYTHON_SELF_VAR);
+ if (useWrapperClass)
+ s << ')';
+}
+
+void CppGenerator::writeCppSelfVarDef(TextStream &s,
+ CppSelfDefinitionFlags flags)
+{
+ if (flags.testFlag(CppGenerator::CppSelfAsReference))
+ s << "auto &" << CPP_SELF_VAR << " = *";
+ else
+ s << "auto *" << CPP_SELF_VAR << " = ";
+}
+
+void CppGenerator::writeCppSelfDefinition(TextStream &s,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn,
+ CppSelfDefinitionFlags flags)
+{
+ Q_ASSERT(!(flags.testFlag(CppSelfAsReference) && flags.testFlag(HasStaticOverload)));
+ if (context.forSmartPointer()) {
+ writeSmartPointerCppSelfDefinition(s, context, errorReturn, flags);
+ return;
+ }
+
+ AbstractMetaClassCPtr metaClass = context.metaClass();
+ const auto cppWrapper = context.metaClass()->cppWrapper();
+ // In the Python method, use the wrapper to access the protected
+ // functions.
+ const bool useWrapperClass = avoidProtectedHack()
+ && cppWrapper.testFlag(AbstractMetaClass::CppProtectedHackWrapper);
+ Q_ASSERT(!useWrapperClass || context.useWrapper());
+ const QString className = useWrapperClass
+ ? context.wrapperName() : getFullTypeName(metaClass);
+
+ writeInvalidPyObjectCheck(s, PYTHON_SELF_VAR, errorReturn);
+
+ if (flags.testFlag(CppSelfAsReference)) {
+ writeCppSelfVarDef(s, flags);
+ writeCppSelfConversion(s, context, className, useWrapperClass);
+ s << ";\n";
+ return;
+ }
+
+ if (!flags.testFlag(HasStaticOverload)) {
+ if (!flags.testFlag(HasClassMethodOverload)) {
+ // PYSIDE-131: The single case of a class method for now: tr().
+ writeCppSelfVarDef(s, flags);
+ writeCppSelfConversion(s, context, className, useWrapperClass);
+ s << ";\n" << sbkUnusedVariableCast(CPP_SELF_VAR);
+ }
+ return;
+ }
+
+ s << className << " *" << CPP_SELF_VAR << " = nullptr;\n"
+ << sbkUnusedVariableCast(CPP_SELF_VAR);
+
+ // Checks if the underlying C++ object is valid.
+ s << "if (self)\n" << indent
+ << CPP_SELF_VAR << " = ";
+ writeCppSelfConversion(s, context, className, useWrapperClass);
+ s << ";\n"<< outdent;
+}
+
+void CppGenerator::writeCppSelfDefinition(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn,
+ CppSelfDefinitionFlags flags)
+{
+ if (!func->ownerClass() || func->isConstructor())
+ return;
+
+ if (func->isOperatorOverload() && func->isBinaryOperator()) {
+ QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry());
+ s << "bool isReverse = " << checkFunc << PYTHON_ARG << ")\n"
+ << " && !" << checkFunc << "self);\n"
+ << "if (isReverse)\n" << indent
+ << "std::swap(self, " << PYTHON_ARG << ");\n" << outdent;
+ }
+
+ writeCppSelfDefinition(s, context, errorReturn, flags);
+}
+
+QString CppGenerator::returnErrorWrongArguments(const OverloadData &overloadData,
+ ErrorReturn errorReturn)
+{
+ const auto rfunc = overloadData.referenceFunction();
+ QString argsVar = overloadData.pythonFunctionWrapperUsesListOfArguments()
+ ? u"args"_s : PYTHON_ARG;
+ switch (errorReturn) {
+ case ErrorReturn::Default:
+ return u"Shiboken::returnWrongArguments("_s + argsVar + u", fullName, errInfo)"_s;
+ case ErrorReturn::Zero:
+ return u"Shiboken::returnWrongArguments_Zero("_s + argsVar + u", fullName, errInfo)"_s;
+ case ErrorReturn::MinusOne:
+ return u"Shiboken::returnWrongArguments_MinusOne("_s + argsVar + u", fullName, errInfo)"_s;
+ case ErrorReturn::Void:
+ Q_ASSERT(false);
+ }
+ return {};
+}
+
+void CppGenerator::writeFunctionReturnErrorCheckSection(TextStream &s,
+ ErrorReturn errorReturn,
+ bool hasReturnValue)
+{
+ s << "if (" << shibokenErrorsOccurred;
+ if (hasReturnValue)
+ s << " || " << PYTHON_RETURN_VAR << " == nullptr";
+ s << ") {\n" << indent;
+ if (hasReturnValue)
+ s << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");\n";
+ s << errorReturn << outdent << "}\n";
+}
+
+void CppGenerator::writeInvalidPyObjectCheck(TextStream &s, const QString &pyObj,
+ ErrorReturn errorReturn)
+{
+ s << "if (!Shiboken::Object::isValid(" << pyObj << "))\n"
+ << indent << errorReturn << outdent;
+}
+
+static QString pythonToCppConverterForArgumentName(const QString &argumentName)
+{
+ static const QRegularExpression pyArgsRegex(PYTHON_ARGS
+ + uR"((\[\d+[-]?\d*\]))"_s);
+ Q_ASSERT(pyArgsRegex.isValid());
+ const QRegularExpressionMatch match = pyArgsRegex.match(argumentName);
+ QString result = PYTHON_TO_CPP_VAR;
+ if (match.hasMatch())
+ result += match.captured(1);
+ return result;
+}
+
+void CppGenerator::writeTypeCheck(TextStream &s, const QString &customType,
+ const QString &argumentName)
+{
+ QString errorMessage;
+ const auto metaTypeOpt = AbstractMetaType::fromString(customType, &errorMessage);
+ if (!metaTypeOpt.has_value())
+ throw Exception(errorMessage);
+ writeTypeCheck(s, metaTypeOpt.value(), argumentName,
+ ShibokenGenerator::isNumber(metaTypeOpt.value()));
+}
+
+void CppGenerator::writeTypeCheck(TextStream &s, const AbstractMetaType &argType,
+ const QString &argumentName, bool isNumber,
+ bool rejectNull)
+{
+ // TODO-CONVERTER: merge this with the code below.
+ QString typeCheck = cpythonIsConvertibleFunction(argType);
+ if (typeCheck != u"true") // For PyObject, which is always true
+ typeCheck.append(u'(' +argumentName + u')');
+
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (!argType.typeEntry()->isCustom()) {
+ typeCheck = u'(' + pythonToCppConverterForArgumentName(argumentName)
+ + u" = "_s + typeCheck + u"))"_s;
+ if (!isNumber && isCppPrimitive(argType.typeEntry())) {
+ typeCheck.prepend(cpythonCheckFunction(argType) + u'('
+ + argumentName + u") && "_s);
+ }
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
+ if (rejectNull)
+ typeCheck = u'(' + argumentName + u" != Py_None && "_s + typeCheck + u')';
+
+ s << typeCheck;
+}
+
+static void checkTypeViability(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaType &type, int argIdx)
+{
+ const bool modified = argIdx == 0
+ ? func->isTypeModified()
+ : func->arguments().at(argIdx -1).isTypeModified();
+ const bool isRemoved = argIdx == 0
+ ? func->argumentRemoved(0)
+ : func->arguments().at(argIdx -1).isModifiedRemoved();
+ if (type.isVoid()
+ || !type.typeEntry()->isPrimitive()
+ || type.indirections() == 0
+ || (type.indirections() == 1 && type.typeUsagePattern() == AbstractMetaType::NativePointerAsArrayPattern)
+ || type.isCString()
+ || isRemoved
+ || modified
+ || func->hasConversionRule(TypeSystem::All, argIdx)
+ || func->hasInjectedCode())
+ return;
+ QString message;
+ QTextStream str(&message);
+ str << func->sourceLocation()
+ << "There's no user provided way (conversion rule, argument"
+ " removal, custom code, etc) to handle the primitive ";
+ if (argIdx == 0)
+ str << "return type '" << type.cppSignature() << '\'';
+ else
+ str << "type '" << type.cppSignature() << "' of argument " << argIdx;
+ str << " in function '";
+ if (func->ownerClass())
+ str << func->ownerClass()->qualifiedCppName() << "::";
+ str << func->signature() << "'.";
+ qCWarning(lcShiboken).noquote().nospace() << message;
+}
+
+static void checkTypeViability(const AbstractMetaFunctionCPtr &func)
+{
+ if (func->isUserAdded())
+ return;
+ checkTypeViability(func, func->type(), 0);
+ for (qsizetype i = 0; i < func->arguments().size(); ++i)
+ checkTypeViability(func, func->arguments().at(i).type(), int(i + 1));
+}
+
+void CppGenerator::writeTypeCheck(TextStream &s,
+ const std::shared_ptr<OverloadDataNode> &overloadData,
+ const QString &argumentName)
+{
+ QSet<TypeEntryCPtr> numericTypes;
+ const OverloadDataList &siblings = overloadData->parent()->children();
+ for (const auto &sibling : siblings) {
+ for (const auto &func : sibling->overloads()) {
+ checkTypeViability(func);
+ const AbstractMetaType &argType = sibling->overloadArgument(func)->type();
+ if (!argType.isPrimitive())
+ continue;
+ if (ShibokenGenerator::isNumber(argType.typeEntry()))
+ numericTypes << argType.typeEntry();
+ }
+ }
+
+ // This condition trusts that the OverloadData object will arrange for
+ // PyLong type to come after the more precise numeric types (e.g. float and bool)
+ AbstractMetaType argType = overloadData->modifiedArgType();
+ if (auto viewOn = argType.viewOn())
+ argType = *viewOn;
+ const bool numberType = numericTypes.size() == 1 || ShibokenGenerator::isPyInt(argType);
+ bool rejectNull =
+ shouldRejectNullPointerArgument(overloadData->referenceFunction(), overloadData->argPos());
+ writeTypeCheck(s, argType, argumentName, numberType, rejectNull);
+}
+
+qsizetype CppGenerator::writeArgumentConversion(TextStream &s,
+ const AbstractMetaType &argType,
+ const QString &argName,
+ const QString &pyArgName,
+ ErrorReturn errorReturn,
+ const AbstractMetaClassCPtr &context,
+ const QString &defaultValue,
+ bool castArgumentAsUnused) const
+{
+ qsizetype result = 0;
+ if (argType.typeEntry()->isCustom() || argType.typeEntry()->isVarargs())
+ return result;
+ if (argType.isWrapperType())
+ writeInvalidPyObjectCheck(s, pyArgName, errorReturn);
+ result = writePythonToCppTypeConversion(s, argType, pyArgName, argName, context, defaultValue);
+ if (castArgumentAsUnused)
+ s << sbkUnusedVariableCast(argName);
+ return result;
+}
+
+AbstractMetaType
+ CppGenerator::getArgumentType(const AbstractMetaFunctionCPtr &func, int index)
+{
+ if (index < 0 || index >= func->arguments().size()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Argument index for function '" << func->signature() << "' out of range.";
+ return {};
+ }
+
+ auto argType = func->arguments().at(index).modifiedType();
+ return argType.viewOn() ? *argType.viewOn() : argType;
+}
+
+static inline QString arrayHandleType(const AbstractMetaTypeList &nestedArrayTypes)
+{
+ switch (nestedArrayTypes.size()) {
+ case 1:
+ return "Shiboken::Conversions::ArrayHandle<"_L1
+ + nestedArrayTypes.constLast().minimalSignature() + u'>';
+ case 2:
+ return "Shiboken::Conversions::Array2Handle<"_L1
+ + nestedArrayTypes.constLast().minimalSignature()
+ + ", "_L1
+ + QString::number(nestedArrayTypes.constFirst().arrayElementCount())
+ + u'>';
+ }
+ return QString();
+}
+
+// Helper to write argument initialization code for a function argument
+// in case it has a default value.
+template <class Type> // AbstractMetaType/TypeEntry
+static void writeMinimalConstructorExpression(TextStream &s,
+ const ApiExtractorResult &api,
+ Type type,
+ bool isPrimitive,
+ const QString &defaultValue)
+{
+ if (defaultValue.isEmpty()) {
+ s << ShibokenGenerator::minimalConstructorExpression(api, type);
+ return;
+ }
+ // Use assignment to avoid "Most vexing parse" if it looks like
+ // a function call, or for primitives/pointers
+ const bool isDefault = defaultValue == u"{}";
+ if ((isPrimitive && !isDefault)
+ || defaultValue == u"nullptr" || defaultValue.contains(u'(')) {
+ s << " = " << defaultValue;
+ return;
+ }
+ if (isDefault) {
+ s << defaultValue;
+ return;
+ }
+ s << '(' << defaultValue << ')';
+}
+
+qsizetype CppGenerator::writePythonToCppTypeConversion(TextStream &s,
+ const AbstractMetaType &type,
+ const QString &pyIn,
+ const QString &cppOut,
+ const AbstractMetaClassCPtr &context,
+ const QString &defaultValue) const
+{
+ TypeEntryCPtr typeEntry = type.typeEntry();
+ if (typeEntry->isCustom() || typeEntry->isVarargs())
+ return 0;
+
+ const auto arg = GeneratorArgument::fromMetaType(type);
+ const bool isPrimitive = arg.type == GeneratorArgument::Type::Primitive;
+
+ QString cppOutAux = cppOut + u"_local"_s;
+
+ QString typeName = arg.type == GeneratorArgument::Type::CppPrimitiveArray
+ ? arrayHandleType(type.nestedArrayTypes())
+ : getFullTypeNameWithoutModifiers(type);
+
+ bool isProtectedEnum = false;
+ if (arg.type == GeneratorArgument::Type::Enum && avoidProtectedHack()) {
+ auto metaEnum = api().findAbstractMetaEnum(type.typeEntry());
+ if (metaEnum.has_value() && metaEnum->isProtected()) {
+ typeName = wrapperName(context) + u"::"_s
+ + metaEnum.value().name();
+ isProtectedEnum = true;
+ }
+ }
+
+ s << typeName;
+ switch (arg.conversion) {
+ case GeneratorArgument::Conversion::CppPrimitiveArray:
+ s << ' ' << cppOut;
+ break;
+ case GeneratorArgument::Conversion::ValueOrPointer: {
+ // Generate either value conversion for &cppOutAux or pointer
+ // conversion for &cppOut
+ s << ' ' << cppOutAux;
+ // No default value for containers which can also be passed by pointer.
+ if (arg.type != GeneratorArgument::Type::Container || type.indirections() == 0)
+ writeMinimalConstructorExpression(s, api(), type, isPrimitive, defaultValue);
+ s << ";\n" << typeName << " *" << cppOut << " = &" << cppOutAux;
+ }
+ break;
+ case GeneratorArgument::Conversion::Pointer: {
+ s << " *" << cppOut;
+ if (!defaultValue.isEmpty()) {
+ const bool needsConstCast = !isNullPtr(defaultValue)
+ && type.indirections() == 1 && type.isConstant()
+ && type.referenceType() == NoReference;
+ s << " = ";
+ if (needsConstCast)
+ s << "const_cast<" << typeName << " *>(";
+ s << defaultValue;
+ if (needsConstCast)
+ s << ')';
+ }
+ }
+ break;
+ case GeneratorArgument::Conversion::Default:
+ s << ' ' << cppOut;
+ if (isProtectedEnum && avoidProtectedHack()) {
+ s << " = ";
+ if (defaultValue.isEmpty())
+ s << "{}";
+ else
+ s << defaultValue;
+ } else if (type.isUserPrimitive()
+ || arg.type == GeneratorArgument::Type::Enum
+ || arg.type == GeneratorArgument::Type::Flags) {
+ writeMinimalConstructorExpression(s, api(), typeEntry, isPrimitive, defaultValue);
+ } else if ((!type.isContainer() || type.indirections() == 0) && !type.isSmartPointer()) {
+ writeMinimalConstructorExpression(s, api(), type, isPrimitive, defaultValue);
+ }
+ break;
+ }
+ s << ";\n";
+
+ QString pythonToCppFunc = pythonToCppConverterForArgumentName(pyIn);
+
+ QString pythonToCppCall = pythonToCppFunc + u'(' + pyIn + u", &"_s
+ + cppOut + u')';
+ if (arg.conversion != GeneratorArgument::Conversion::ValueOrPointer) {
+ // pythonToCppFunc may be 0 when less parameters are passed and
+ // the defaultValue takes effect.
+ if (!defaultValue.isEmpty())
+ s << "if (" << pythonToCppFunc << ")\n" << indent;
+ s << pythonToCppCall << ";\n";
+ if (!defaultValue.isEmpty())
+ s << outdent;
+ return arg.indirections;
+ }
+
+ // pythonToCppFunc may be 0 when less parameters are passed and
+ // the defaultValue takes effect.
+ if (!defaultValue.isEmpty())
+ s << "if (" << pythonToCppFunc << ") {\n" << indent;
+
+ s << "if (" << pythonToCppFunc << ".isValue())\n"
+ << indent << pythonToCppFunc << '(' << pyIn << ", &" << cppOutAux << ");\n"
+ << outdent << "else\n" << indent
+ << pythonToCppCall << ";\n" << outdent;
+
+ if (defaultValue.isEmpty())
+ s << '\n';
+ else
+ s << "}\n" << outdent;
+
+ return arg.indirections;
+}
+
+static void addConversionRuleCodeSnippet(CodeSnipList &snippetList, QString &rule,
+ TypeSystem::Language /* conversionLanguage */,
+ TypeSystem::Language snippetLanguage,
+ const QString &outputName = QString(),
+ const QString &inputName = QString())
+{
+ if (rule.isEmpty())
+ return;
+ if (snippetLanguage == TypeSystem::TargetLangCode) {
+ rule.replace(u"%in"_s, inputName);
+ rule.replace(u"%out"_s, outputName + u"_out"_s);
+ } else {
+ rule.replace(u"%out"_s, outputName);
+ }
+ CodeSnip snip(snippetLanguage);
+ snip.position = (snippetLanguage == TypeSystem::NativeCode) ? TypeSystem::CodeSnipPositionAny : TypeSystem::CodeSnipPositionBeginning;
+ snip.addCode(rule);
+ snippetList << snip;
+}
+
+void CppGenerator::writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ TypeSystem::Language language, bool usesPyArgs) const
+{
+
+ CodeSnipList snippets;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument &arg : arguments) {
+ QString rule = func->conversionRule(language, arg.argumentIndex() + 1);
+ addConversionRuleCodeSnippet(snippets, rule, language, TypeSystem::TargetLangCode,
+ arg.name(), arg.name());
+ }
+ writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode,
+ func, usesPyArgs, nullptr);
+}
+
+void CppGenerator::writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ TypeSystem::Language language, const QString &outputVar) const
+{
+ CodeSnipList snippets;
+ QString rule = func->conversionRule(language, 0);
+ addConversionRuleCodeSnippet(snippets, rule, language, language, outputVar);
+ writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionAny, language,
+ func, false /* uses PyArgs */, nullptr);
+}
+
+void CppGenerator::writeNoneReturn(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ bool thereIsReturnValue)
+{
+ if (thereIsReturnValue && (func->isVoid() || func->argumentRemoved(0))
+ && !func->injectedCodeHasReturnValueAttribution()) {
+ s << PYTHON_RETURN_VAR << " = Py_None;\n"
+ << "Py_INCREF(Py_None);\n";
+ }
+}
+
+void CppGenerator::writeOverloadedFunctionDecisor(TextStream &s,
+ const OverloadData &overloadData,
+ ErrorReturn errorReturn) const
+{
+ s << "// Overloaded function decisor\n";
+ const auto rfunc = overloadData.referenceFunction();
+ const AbstractMetaFunctionCList &functionOverloads = overloadData.overloads();
+ for (qsizetype i = 0; i < functionOverloads.size(); ++i) {
+ const auto func = functionOverloads.at(i);
+ s << "// " << i << ": ";
+ if (func->isStatic())
+ s << "static ";
+ if (const auto &decl = func->declaringClass())
+ s << decl->name() << "::";
+ s << func->signatureComment() << '\n';
+ }
+ writeOverloadedFunctionDecisorEngine(s, overloadData, &overloadData);
+ s << '\n';
+
+ // Ensure that the direct overload that called this reverse
+ // is called.
+ if (rfunc->isOperatorOverload() && !rfunc->isCallOperator()) {
+ s << "if (isReverse && overloadId == -1) {\n" << indent
+ << "Shiboken::Errors::setReverseOperatorNotImplemented();\n"
+ << "return {};\n" << outdent
+ << "}\n\n";
+ }
+
+ s << "// Function signature not found.\n"
+ << "if (overloadId == -1)\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n\n"
+ << outdent;
+}
+
+void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
+ const OverloadData &overloadData,
+ const OverloadDataRootNode *node) const
+{
+ bool hasDefaultCall = node->nextArgumentHasDefaultValue();
+ auto referenceFunction = node->referenceFunction();
+
+ // If the next argument has not an argument with a default value, it is still possible
+ // that one of the overloads for the current overload data has its final occurrence here.
+ // If found, the final occurrence of a method is attributed to the referenceFunction
+ // variable to be used further on this method on the conditional that identifies default
+ // method calls.
+ if (!hasDefaultCall) {
+ for (const auto &func : node->overloads()) {
+ if (node->isFinalOccurrence(func)) {
+ referenceFunction = func;
+ hasDefaultCall = true;
+ break;
+ }
+ }
+ }
+
+ const int maxArgs = overloadData.maxArgs();
+ // Python constructors always receive multiple arguments.
+ const bool usePyArgs = overloadData.pythonFunctionWrapperUsesListOfArguments();
+
+ // Functions without arguments are identified right away.
+ if (maxArgs == 0) {
+ s << "overloadId = " << overloadData.functionNumber(referenceFunction)
+ << "; // " << referenceFunction->minimalSignature() << '\n';
+ return;
+
+ }
+ // To decide if a method call is possible at this point the current overload
+ // data object cannot be the head, since it is just an entry point, or a root,
+ // for the tree of arguments and it does not represent a valid method call.
+ if (!node->isRoot()) {
+ const bool isLastArgument = node->children().isEmpty();
+ const bool signatureFound = node->overloads().size() == 1;
+
+ // The current overload data describes the last argument of a signature,
+ // so the method can be identified right now.
+ if (isLastArgument || (signatureFound && !hasDefaultCall)) {
+ const auto func = node->referenceFunction();
+ s << "overloadId = " << overloadData.functionNumber(func)
+ << "; // " << func->minimalSignature() << '\n';
+ return;
+ }
+ }
+
+ bool isFirst = true;
+
+ // If the next argument has a default value the decisor can perform a method call;
+ // it just need to check if the number of arguments received from Python are equal
+ // to the number of parameters preceding the argument with the default value.
+ const OverloadDataList &children = node->children();
+ if (hasDefaultCall) {
+ isFirst = false;
+ int numArgs = node->argPos() + 1;
+ s << "if (numArgs == " << numArgs << ") {\n" << indent;
+ auto func = referenceFunction;
+ for (const auto &child : children) {
+ const auto defValFunc = child->getFunctionWithDefaultValue();
+ if (defValFunc) {
+ func = defValFunc;
+ break;
+ }
+ }
+ s << "overloadId = " << overloadData.functionNumber(func)
+ << "; // " << func->minimalSignature() << '\n' << outdent << '}';
+ }
+
+ for (auto child : children) {
+ bool signatureFound = child->overloads().size() == 1
+ && !child->getFunctionWithDefaultValue()
+ && !child->findNextArgWithDefault();
+
+ const auto refFunc = child->referenceFunction();
+
+ QStringList typeChecks;
+
+ QString pyArgName = (usePyArgs && maxArgs > 1)
+ ? pythonArgsAt(child->argPos())
+ : PYTHON_ARG;
+ auto od = child;
+ int startArg = od->argPos();
+ int sequenceArgCount = 0;
+ while (od && !od->argType().isVarargs()) {
+ const bool typeReplacedByPyObject = od->isTypeModified()
+ && od->modifiedArgType().name() == cPyObjectT;
+ if (!typeReplacedByPyObject) {
+ if (usePyArgs)
+ pyArgName = pythonArgsAt(od->argPos());
+ StringStream tck(TextStream::Language::Cpp);
+ auto func = od->referenceFunction();
+
+ if (func->isConstructor() && func->arguments().size() == 1) {
+ AbstractMetaClassCPtr ownerClass = func->ownerClass();
+ ComplexTypeEntryCPtr baseContainerType = ownerClass->typeEntry()->baseContainerType();
+ if (baseContainerType && baseContainerType == func->arguments().constFirst().type().typeEntry()
+ && ownerClass->isCopyable()) {
+ tck << '!' << cpythonCheckFunction(ownerClass->typeEntry())
+ << pyArgName << ")\n" << indent << "&& " << outdent;
+ }
+ }
+ writeTypeCheck(tck, od, pyArgName);
+ typeChecks << tck.toString();
+ }
+
+ sequenceArgCount++;
+
+ if (od->children().isEmpty()
+ || od->nextArgumentHasDefaultValue()
+ || od->children().size() != 1
+ || od->overloads().size() != od->children().constFirst()->overloads().size()) {
+ child = od;
+ od = nullptr;
+ } else {
+ od = od->children().constFirst();
+ }
+ }
+
+ if (usePyArgs && signatureFound) {
+ AbstractMetaArgumentList args = refFunc->arguments();
+ const bool isVarargs = args.size() > 1 && args.constLast().type().isVarargs();
+ int numArgs = args.size() - OverloadData::numberOfRemovedArguments(refFunc);
+ if (isVarargs)
+ --numArgs;
+ QString check = (isVarargs ? u"numArgs >= "_s : u"numArgs == "_s)
+ + QString::number(numArgs);
+ typeChecks.prepend(check);
+ } else if (usePyArgs && sequenceArgCount > 0) {
+ typeChecks.prepend(u"numArgs >= "_s + QString::number(startArg + sequenceArgCount));
+ } else if (refFunc->isOperatorOverload() && !refFunc->isCallOperator()) {
+ QString check;
+ if (!refFunc->isReverseOperator())
+ check.append(u'!');
+ check.append(u"isReverse"_s);
+ typeChecks.prepend(check);
+ }
+
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ s << " else ";
+ }
+ s << "if (";
+ if (typeChecks.isEmpty()) {
+ s << "true";
+ } else {
+ s << indent << typeChecks.join(u"\n&& "_s) << outdent;
+ }
+ s << ") {\n" << indent;
+ writeOverloadedFunctionDecisorEngine(s, overloadData, child.get());
+ s << outdent << '}';
+ }
+ s << '\n';
+}
+
+void CppGenerator::writeFunctionCalls(TextStream &s, const OverloadData &overloadData,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn) const
+{
+ const AbstractMetaFunctionCList &overloads = overloadData.overloads();
+ s << "// Call function/method\n"
+ << (overloads.size() > 1 ? "switch (overloadId) " : "") << "{\n" << indent;
+ if (overloads.size() == 1) {
+ writeSingleFunctionCall(s, overloadData, overloads.constFirst(), context,
+ errorReturn);
+ } else {
+ for (qsizetype i = 0; i < overloads.size(); ++i) {
+ const auto func = overloads.at(i);
+ s << "case " << i << ": // " << func->signature() << "\n{\n" << indent;
+ writeSingleFunctionCall(s, overloadData, func, context, errorReturn);
+ s << "break;\n" << outdent << "}\n";
+ }
+ }
+ s << outdent << "}\n";
+}
+
+static void writeDeprecationWarning(TextStream &s,
+ const GeneratorContext &context,
+ const AbstractMetaFunctionCPtr &func,
+ CppGenerator::ErrorReturn errorReturn)
+{
+ s << "Shiboken::Warnings::warnDeprecated(\"";
+ if (const auto cls = context.metaClass())
+ s << cls->name() << "\", ";
+ // Check error in case "warning-as-error" is set.
+ s << '"' << func->signature().replace(u"::"_s, u"."_s) << "\");\n"
+ << "if (" << shibokenErrorsOccurred << ")\n"
+ << indent << errorReturn << outdent;
+}
+
+void CppGenerator::writeSingleFunctionCall(TextStream &s,
+ const OverloadData &overloadData,
+ const AbstractMetaFunctionCPtr &func,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn) const
+{
+ if (func->isDeprecated())
+ writeDeprecationWarning(s, context, func, errorReturn);
+
+ if (func->functionType() == AbstractMetaFunction::EmptyFunction) {
+ s << "Shiboken::Errors::setPrivateMethod(\""
+ << func->signature().replace(u"::"_s, u"."_s) << "\");\n"
+ << errorReturn;
+ return;
+ }
+
+ const bool usePyArgs = overloadData.pythonFunctionWrapperUsesListOfArguments();
+
+ // Handle named arguments.
+ writeNamedArgumentResolution(s, func, usePyArgs, overloadData, errorReturn);
+
+ bool injectCodeCallsFunc = injectedCodeCallsCppFunction(context, func);
+ bool mayHaveUnunsedArguments = !func->isUserAdded() && func->hasInjectedCode() && injectCodeCallsFunc;
+ int removedArgs = 0;
+
+ const auto argCount = func->arguments().size();
+ QList<qsizetype> indirections(argCount, 0);
+ for (qsizetype argIdx = 0; argIdx < argCount; ++argIdx) {
+ const bool hasConversionRule =
+ func->hasConversionRule(TypeSystem::NativeCode, int(argIdx + 1));
+ const AbstractMetaArgument &arg = func->arguments().at(argIdx);
+ if (arg.isModifiedRemoved()) {
+ if (!arg.defaultValueExpression().isEmpty()) {
+ const QString cppArgRemoved = CPP_ARG_REMOVED(argIdx);
+ s << getFullTypeName(arg.type()) << ' ' << cppArgRemoved;
+ s << " = " << arg.defaultValueExpression() << ";\n"
+ << sbkUnusedVariableCast(cppArgRemoved);
+ } else if (!injectCodeCallsFunc && !func->isUserAdded() && !hasConversionRule) {
+ // When an argument is removed from a method signature and no other means of calling
+ // the method are provided (as with code injection) the generator must abort.
+ QString m;
+ QTextStream(&m) << "No way to call '" << func->ownerClass()->name()
+ << "::" << func->signature()
+ << "' with the modifications described in the type system.";
+ throw Exception(m);
+ }
+ removedArgs++;
+ continue;
+ }
+ if (hasConversionRule)
+ continue;
+ if (mayHaveUnunsedArguments && !func->injectedCodeUsesArgument(argIdx))
+ continue;
+ auto argType = getArgumentType(func, argIdx);
+ int argPos = argIdx - removedArgs;
+ QString pyArgName = usePyArgs ? pythonArgsAt(argPos) : PYTHON_ARG;
+ indirections[argIdx] =
+ writeArgumentConversion(s, argType, CPP_ARG_N(argPos), pyArgName, errorReturn,
+ func->implementingClass(), arg.defaultValueExpression(),
+ func->isUserAdded());
+ }
+
+ s << '\n';
+
+ int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
+
+ s << "if (Shiboken::Errors::occurred() == nullptr) {\n" << indent;
+ writeMethodCall(s, func, context,
+ overloadData.pythonFunctionWrapperUsesListOfArguments(),
+ func->arguments().size() - numRemovedArgs, indirections, errorReturn);
+
+ if (!func->isConstructor())
+ writeNoneReturn(s, func, overloadData.hasNonVoidReturnType());
+ s << outdent << "}\n";
+}
+
+QString CppGenerator::cppToPythonFunctionName(const QString &sourceTypeName, QString targetTypeName)
+{
+ if (targetTypeName.isEmpty())
+ targetTypeName = sourceTypeName;
+ return sourceTypeName + u"_CppToPython_"_s + targetTypeName;
+}
+
+QString CppGenerator::pythonToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName)
+{
+ return sourceTypeName + u"_PythonToCpp_"_s + targetTypeName;
+}
+QString CppGenerator::pythonToCppFunctionName(const AbstractMetaType &sourceType, const AbstractMetaType &targetType)
+{
+ return pythonToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
+}
+QString CppGenerator::pythonToCppFunctionName(const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType)
+{
+ return pythonToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
+}
+
+QString CppGenerator::convertibleToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName)
+{
+ return u"is_"_s + sourceTypeName + u"_PythonToCpp_"_s
+ + targetTypeName + u"_Convertible"_s;
+}
+QString CppGenerator::convertibleToCppFunctionName(const AbstractMetaType &sourceType, const AbstractMetaType &targetType)
+{
+ return convertibleToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
+}
+QString CppGenerator::convertibleToCppFunctionName(const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType)
+{
+ return convertibleToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
+}
+
+void CppGenerator::writeCppToPythonFunction(TextStream &s, const QString &code, const QString &sourceTypeName,
+ QString targetTypeName) const
+{
+
+ QString prettyCode = code;
+ const QString funcName = cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ processCodeSnip(prettyCode, funcName);
+
+ s << "static PyObject *" << funcName
+ << "(const void *cppIn)\n{\n" << indent << prettyCode
+ << ensureEndl << outdent << "}\n";
+}
+
+static QString writeCppInRef(const QString &typeName, bool constRef)
+{
+ QString result;
+ QTextStream str(&result);
+ if (constRef)
+ str << "const ";
+ str << "auto &cppInRef = *reinterpret_cast<";
+ if (constRef)
+ str << "const ";
+ str << typeName << " *>("
+ << (constRef ? "cppIn" : "const_cast<void *>(cppIn)") << ");";
+ return result;
+}
+
+static void replaceCppToPythonVariables(QString &code, const QString &typeName,
+ bool constRef = false)
+{
+ CodeSnipAbstract::prependCode(&code, writeCppInRef(typeName, constRef));
+ code.replace(u"%INTYPE"_s, typeName);
+ code.replace(u"%OUTTYPE"_s, u"PyObject *"_s);
+ code.replace(u"%in"_s, u"cppInRef"_s);
+ code.replace(u"%out"_s, u"pyOut"_s);
+}
+
+void CppGenerator::writeCppToPythonFunction(TextStream &s,
+ const CustomConversionPtr &customConversion) const
+{
+ QString code = customConversion->nativeToTargetConversion();
+ auto ownerType = customConversion->ownerType();
+ const bool constRef = !ownerType->isPrimitive(); // PyCapsule needs a non-const ref
+ replaceCppToPythonVariables(code, getFullTypeName(ownerType), constRef);
+ writeCppToPythonFunction(s, code, fixedCppTypeName(customConversion->ownerType()));
+}
+
+QString CppGenerator::containerNativeToTargetTypeName(const ContainerTypeEntryCPtr &type)
+{
+ QString result = type->targetLangApiName();
+ if (result != cPyObjectT) {
+ result = containerCpythonBaseName(type);
+ if (result == cPySequenceT)
+ result = cPyListT;
+ }
+ return result;
+}
+
+void CppGenerator::writeCppToPythonFunction(TextStream &s, const AbstractMetaType &containerType) const
+{
+ Q_ASSERT(containerType.typeEntry()->isContainer());
+ auto cte = std::static_pointer_cast<const ContainerTypeEntry>(containerType.typeEntry());
+ if (!cte->hasCustomConversion()) {
+ QString m;
+ QTextStream(&m) << "Can't write the C++ to Python conversion function for container type '"
+ << containerType.typeEntry()->qualifiedCppName()
+ << "' - no conversion rule was defined for it in the type system.";
+ throw Exception(m);
+ }
+ const auto customConversion = cte->customConversion();
+ QString code = customConversion->nativeToTargetConversion();
+ for (qsizetype i = 0; i < containerType.instantiations().size(); ++i) {
+ const AbstractMetaType &type = containerType.instantiations().at(i);
+ QString typeName = getFullTypeName(type);
+ if (type.isConstant())
+ typeName = u"const "_s + typeName;
+ code.replace(u"%INTYPE_"_s + QString::number(i), typeName);
+ }
+ replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType), true);
+ processCodeSnip(code, containerType.typeEntry()->qualifiedCppName());
+ writeCppToPythonFunction(s, code, fixedCppTypeName(containerType),
+ containerNativeToTargetTypeName(cte));
+}
+
+void CppGenerator::writePythonToCppFunction(TextStream &s, const QString &code, const QString &sourceTypeName,
+ const QString &targetTypeName) const
+{
+ QString prettyCode = code;
+ const QString funcName = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ processCodeSnip(prettyCode, funcName);
+ s << "static void " << funcName
+ << "(PyObject *pyIn, void *cppOut)\n{\n" << indent << prettyCode
+ << ensureEndl << outdent << "}\n";
+}
+
+void CppGenerator::writeIsPythonConvertibleToCppFunction(TextStream &s,
+ const QString &sourceTypeName,
+ const QString &targetTypeName,
+ const QString &condition,
+ QString pythonToCppFuncName,
+ bool acceptNoneAsCppNull)
+{
+ if (pythonToCppFuncName.isEmpty())
+ pythonToCppFuncName = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+
+ s << "static PythonToCppFunc " << convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ s << "(PyObject *pyIn)\n{\n" << indent;
+ if (acceptNoneAsCppNull) {
+ s << "if (pyIn == Py_None)\n" << indent
+ << "return Shiboken::Conversions::nonePythonToCppNullPtr;\n" << outdent;
+ } else {
+ if (!condition.contains(u"pyIn"))
+ s << sbkUnusedVariableCast("pyIn");
+ }
+ s << "if (" << condition << ")\n" << indent
+ << "return " << pythonToCppFuncName << ";\n" << outdent
+ << "return {};\n" << outdent << "}\n";
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(TextStream &s,
+ const AbstractMetaType &sourceType,
+ const AbstractMetaType &targetType,
+ QString typeCheck,
+ QString conversion,
+ const QString &preConversion) const
+{
+ QString sourcePyType = cpythonTypeNameExt(sourceType);
+
+ // Python to C++ conversion function.
+ StringStream c(TextStream::Language::Cpp);
+ if (conversion.isEmpty())
+ conversion = u'*' + cpythonWrapperCPtr(sourceType, u"pyIn"_s);
+ if (!preConversion.isEmpty())
+ c << preConversion << '\n';
+ const QString fullTypeName = targetType.isSmartPointer()
+ ? targetType.cppSignature()
+ : getFullTypeName(targetType.typeEntry());
+ c << "*reinterpret_cast<" << fullTypeName << " *>(cppOut) = "
+ << fullTypeName << '('
+ << (sourceType.isUniquePointer() ? stdMove(conversion) : conversion)
+ << ");";
+ QString sourceTypeName = fixedCppTypeName(sourceType);
+ QString targetTypeName = fixedCppTypeName(targetType);
+ writePythonToCppFunction(s, c.toString(), sourceTypeName, targetTypeName);
+
+ // Python to C++ convertible check function.
+ if (typeCheck.isEmpty())
+ typeCheck = u"PyObject_TypeCheck(pyIn, "_s + sourcePyType + u')';
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
+ s << '\n';
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(TextStream &s,
+ const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType) const
+{
+ // Python to C++ conversion function.
+ QString code = toNative.conversion();
+ QString inType;
+ if (toNative.sourceType())
+ inType = cpythonTypeNameExt(toNative.sourceType());
+ else
+ inType = u'(' + toNative.sourceTypeName() + u"_TypeF())"_s;
+ code.replace(u"%INTYPE"_s, inType);
+ code.replace(u"%OUTTYPE"_s, targetType->qualifiedCppName());
+ code.replace(u"%in"_s, u"pyIn"_s);
+ code.replace(u"%out"_s,
+ u"*reinterpret_cast<"_s + getFullTypeName(targetType) + u" *>(cppOut)"_s);
+
+ QString sourceTypeName = fixedCppTypeName(toNative);
+ QString targetTypeName = fixedCppTypeName(targetType);
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // Python to C++ convertible check function.
+ QString typeCheck = toNative.sourceTypeCheck();
+ if (typeCheck.isEmpty()) {
+ QString pyTypeName = toNative.sourceTypeName();
+ if (pyTypeName == u"Py_None" || pyTypeName == u"PyNone")
+ typeCheck = u"%in == Py_None"_s;
+ else if (pyTypeName == u"SbkObject")
+ typeCheck = u"Shiboken::Object::checkType(%in)"_s;
+ }
+ if (typeCheck.isEmpty()) {
+ if (!toNative.sourceType() || toNative.sourceType()->isPrimitive()) {
+ QString m;
+ QTextStream(&m) << "User added implicit conversion for C++ type '" << targetType->qualifiedCppName()
+ << "' must provide either an input type check function or a non primitive type entry.";
+ throw Exception(m);
+ }
+ typeCheck = u"PyObject_TypeCheck(%in, "_s
+ + cpythonTypeNameExt(toNative.sourceType()) + u')';
+ }
+ typeCheck.replace(u"%in"_s, u"pyIn"_s);
+ processCodeSnip(typeCheck, targetType->qualifiedCppName());
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, const AbstractMetaType &containerType) const
+{
+ Q_ASSERT(containerType.typeEntry()->isContainer());
+ const auto cte = std::static_pointer_cast<const ContainerTypeEntry>(containerType.typeEntry());
+ const auto customConversion = cte->customConversion();
+ for (const auto &conv : customConversion->targetToNativeConversions())
+ writePythonToCppConversionFunction(s, containerType, conv);
+}
+
+void CppGenerator::writePythonToCppConversionFunction(TextStream &s,
+ const AbstractMetaType &containerType,
+ const TargetToNativeConversion &conv) const
+{
+ // Python to C++ conversion function.
+ QString cppTypeName = getFullTypeNameWithoutModifiers(containerType);
+ QString code = conv.conversion();
+ const QString line = u"auto &cppOutRef = *reinterpret_cast<"_s
+ + cppTypeName + u" *>(cppOut);"_s;
+ CodeSnipAbstract::prependCode(&code, line);
+ for (qsizetype i = 0; i < containerType.instantiations().size(); ++i) {
+ const AbstractMetaType &type = containerType.instantiations().at(i);
+ QString typeName = getFullTypeName(type);
+ // Containers of opaque containers are not handled here.
+ const auto generatorArg = GeneratorArgument::fromMetaType(type);
+ if (generatorArg.indirections > 0 && !type.generateOpaqueContainer()) {
+ for (int pos = 0; ; ) {
+ const QRegularExpressionMatch match = convertToCppRegEx().match(code, pos);
+ if (!match.hasMatch())
+ break;
+ pos = match.capturedEnd();
+ const QString varName = match.captured(1);
+ QString rightCode = code.mid(pos);
+ rightCode.replace(varName, u'*' + varName);
+ code.replace(pos, code.size() - pos, rightCode);
+ }
+ typeName.append(u" *"_s);
+ }
+ code.replace(u"%OUTTYPE_"_s + QString::number(i), typeName);
+ }
+ code.replace(u"%OUTTYPE"_s, cppTypeName);
+ code.replace(u"%in"_s, u"pyIn"_s);
+ code.replace(u"%out"_s, u"cppOutRef"_s);
+ QString typeName = fixedCppTypeName(containerType);
+ const QString &sourceTypeName = conv.sourceTypeName();
+ writePythonToCppFunction(s, code, sourceTypeName, typeName);
+
+ // Python to C++ convertible check function.
+ QString typeCheck = cpythonCheckFunction(containerType);
+ if (typeCheck.isEmpty())
+ typeCheck = u"false"_s;
+ else
+ typeCheck = typeCheck + u"pyIn)"_s;
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, typeName, typeCheck);
+ s << '\n';
+}
+
+static void writeSetConverterFunction(TextStream &s,
+ const char *function,
+ const QString &converterVar,
+ const QString &pythonToCppFunc,
+ const QString &isConvertibleFunc)
+{
+ s << "Shiboken::Conversions::" << function << '(' << converterVar << ',' << '\n'
+ << indent << pythonToCppFunc << ',' << '\n' << isConvertibleFunc
+ << outdent << ");\n";
+}
+
+void CppGenerator::writeAddPythonToCppConversion(TextStream &s, const QString &converterVar,
+ const QString &pythonToCppFunc,
+ const QString &isConvertibleFunc)
+{
+ writeSetConverterFunction(s, "addPythonToCppValueConversion",
+ converterVar, pythonToCppFunc, isConvertibleFunc);
+}
+
+void CppGenerator::writeSetPythonToCppPointerConversion(TextStream &s,
+ const QString &converterVar,
+ const QString &pythonToCppFunc,
+ const QString &isConvertibleFunc)
+{
+ writeSetConverterFunction(s, "setPythonToCppPointerFunctions",
+ converterVar, pythonToCppFunc, isConvertibleFunc);
+}
+
+// PYSIDE-1986: Some QObject derived classes, (QVBoxLayout) do not have default
+// arguments, which breaks setting properties by named arguments. Force the
+// handling code to be generated nevertheless for applicable widget classes,
+// so that the mechanism of falling through to the error handling to set
+// the properties works nevertheless.
+static bool forceQObjectNamedArguments(const AbstractMetaFunctionCPtr &func)
+{
+ if (func->functionType() != AbstractMetaFunction::ConstructorFunction)
+ return false;
+ const auto owner = func->ownerClass();
+ Q_ASSERT(owner);
+ if (!isQObject(owner))
+ return false;
+ const QString &name = owner->name();
+ return name == u"QVBoxLayout" || name == u"QHBoxLayout"
+ || name == u"QSplitterHandle" || name == u"QSizeGrip";
+}
+
+void CppGenerator::writeNamedArgumentResolution(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ bool usePyArgs,
+ const OverloadData &overloadData,
+ ErrorReturn errorReturn)
+{
+ const AbstractMetaArgumentList &args = OverloadData::getArgumentsWithDefaultValues(func);
+ const bool hasDefaultArguments = !args.isEmpty();
+ const bool force = !hasDefaultArguments && usePySideExtensions()
+ && forceQObjectNamedArguments(func);
+ if (!hasDefaultArguments && !force) {
+ if (overloadData.hasArgumentWithDefaultValue()) {
+ // PySide-535: Allow for empty dict instead of nullptr in PyPy
+ s << "if (kwds != nullptr && PyDict_Size(kwds) > 0) {\n" << indent
+ << "errInfo.reset(kwds);\n"
+ << "Py_INCREF(errInfo.object());\n"
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent << "}\n";
+ }
+ return;
+ }
+
+ // PySide-535: Allow for empty dict instead of nullptr in PyPy
+ s << "if (kwds && PyDict_Size(kwds) > 0) {\n" << indent;
+ if (!force)
+ s << "PyObject *value{};\n";
+ s << "Shiboken::AutoDecRef kwds_dup(PyDict_Copy(kwds));\n";
+ for (const AbstractMetaArgument &arg : args) {
+ const int pyArgIndex = arg.argumentIndex()
+ - OverloadData::numberOfRemovedArguments(func, arg.argumentIndex());
+ QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex)
+ : PYTHON_ARG;
+ QString pyKeyName = u"key_"_s + arg.name();
+ s << "static PyObject *const " << pyKeyName
+ << " = Shiboken::String::createStaticString(\"" << arg.name() << "\");\n"
+ << "if (PyDict_Contains(kwds, " << pyKeyName << ") != 0) {\n" << indent
+ << "value = PyDict_GetItem(kwds, " << pyKeyName << ");\n"
+ << "if (value != nullptr && " << pyArgName << " != nullptr ) {\n"
+ << indent << "errInfo.reset(" << pyKeyName << ");\n"
+ << "Py_INCREF(errInfo.object());\n"
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent << "}\nif (value != nullptr) {\n" << indent
+ << pyArgName << " = value;\nif (!";
+ const auto &type = arg.modifiedType();
+ writeTypeCheck(s, type, pyArgName, isNumber(type.typeEntry()), {});
+ s << ")\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent << outdent
+ << "}\nPyDict_DelItem(kwds_dup, " << pyKeyName << ");\n"
+ << outdent << "}\n";
+ }
+ // PYSIDE-1305: Handle keyword args correctly.
+ // Normal functions handle their parameters immediately.
+ // For constructors that are QObject, we need to delay that
+ // until extra keyword signals and properties are handled.
+ s << "if (PyDict_Size(kwds_dup) > 0) {\n" << indent
+ << "errInfo.reset(kwds_dup.release());\n";
+ if (!(func->isConstructor() && isQObject(func->ownerClass())))
+ s << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n";
+ else
+ s << "// fall through to handle extra keyword signals and properties\n";
+ s << outdent << "}\n"
+ << outdent << "}\n";
+}
+
+QString CppGenerator::argumentNameFromIndex(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func, int argIndex)
+{
+ switch (argIndex) {
+ case -1:
+ return PYTHON_SELF_VAR;
+ case 0:
+ return PYTHON_RETURN_VAR;
+ case 1: { // Single argument?
+ OverloadData data(getFunctionGroups(func->implementingClass()).value(func->name()), api);
+ if (!data.pythonFunctionWrapperUsesListOfArguments())
+ return PYTHON_ARG;
+ break;
+ }
+ }
+ return pythonArgsAt(argIndex - 1);
+}
+
+AbstractMetaClassCPtr
+CppGenerator::argumentClassFromIndex(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func, int argIndex)
+{
+ if (argIndex == -1)
+ return func->implementingClass();
+
+ AbstractMetaType type;
+ if (argIndex == 0) {
+ type = func->type();
+ } else {
+ const int arg = argIndex - 1;
+ const int realIndex = arg - OverloadData::numberOfRemovedArguments(func, arg);
+ type = func->arguments().at(realIndex).type();
+ }
+
+ if (type.typeEntry()->isContainer()) {
+ // only support containers with 1 type
+ if (type.instantiations().size() == 1)
+ type = type.instantiations().constFirst();
+ }
+
+ auto te = type.typeEntry();
+ if (type.isVoid() || !te->isComplex())
+ throw Exception(msgInvalidArgumentModification(func, argIndex));
+ const auto result = AbstractMetaClass::findClass(api.classes(), te);
+ if (!result)
+ throw Exception(msgClassNotFound(te));
+ return result;
+}
+
+const char tryBlock[] = R"(
+PyObject *errorType{};
+PyObject *errorString{};
+try {
+)";
+
+const char defaultExceptionHandling[] = R"(} catch (const std::exception &e) {
+ errorType = PyExc_RuntimeError;
+ errorString = Shiboken::String::fromCString(e.what());
+} catch (...) {
+ errorType = PyExc_RuntimeError;
+ errorString = Shiboken::Messages::unknownException();
+}
+)";
+
+const char propagateException[] = R"(
+if (errorType != nullptr)
+ PyErr_SetObject(errorType, errorString);
+)";
+
+static QString explicitConversion(const QString &v, const AbstractMetaType &t)
+{
+ return t.plainType().cppSignature() + u'(' + v + u')';
+}
+
+void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const GeneratorContext &context, bool usesPyArgs,
+ int maxArgs,
+ const QList<qsizetype> &argumentIndirections,
+ ErrorReturn errorReturn) const
+{
+ s << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << '\n';
+ if (func->isConstructor()) {
+ const CodeSnipList &snips = func->injectedCodeSnips();
+ for (const CodeSnip &cs : snips) {
+ if (cs.position == TypeSystem::CodeSnipPositionEnd) {
+ auto klass = func->ownerClass();
+ s << "overloadId = "
+ << klass->functions().indexOf(func)
+ << ";\n";
+ break;
+ }
+ }
+ }
+
+ if (func->isAbstract()) {
+ s << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(self))) {\n"
+ << indent << "Shiboken::Errors::setPureVirtualMethodError(\""
+ << func->ownerClass()->name() << '.' << func->name() << "\");\n"
+ << errorReturn << outdent << "}\n";
+ }
+
+ // Used to provide contextual information to custom code writer function.
+ const AbstractMetaArgument *lastArg = nullptr;
+
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+
+ // Find the last argument available in the method call to provide
+ // the injected code writer with information to avoid invalid replacements
+ // on the %# variable.
+ if (maxArgs > 0 && maxArgs < func->arguments().size() - OverloadData::numberOfRemovedArguments(func)) {
+ int removedArgs = 0;
+ for (int i = 0; i < maxArgs + removedArgs; i++) {
+ if (func->arguments().at(i).isModifiedRemoved())
+ removedArgs++;
+ }
+ } else if (maxArgs != 0 && !func->arguments().isEmpty()) {
+ lastArg = &func->arguments().constLast();
+ }
+
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func,
+ usesPyArgs, lastArg);
+ }
+
+ writeConversionRule(s, func, TypeSystem::NativeCode, usesPyArgs);
+
+ bool generateExceptionHandling = false;
+
+ if (!func->isUserAdded()) {
+ QStringList userArgs;
+ if (func->functionType() != AbstractMetaFunction::CopyConstructorFunction) {
+ int removedArgs = 0;
+ for (int i = 0; i < maxArgs + removedArgs; i++) {
+ const AbstractMetaArgument &arg = func->arguments().at(i);
+ const bool hasConversionRule =
+ func->hasConversionRule(TypeSystem::NativeCode, arg.argumentIndex() + 1);
+ if (arg.isModifiedRemoved()) {
+ // If some argument with default value is removed from a
+ // method signature, the said value must be explicitly
+ // added to the method call.
+ removedArgs++;
+
+ // If have conversion rules I will use this for removed args
+ if (hasConversionRule)
+ userArgs << arg.name() + CONV_RULE_OUT_VAR_SUFFIX;
+ else if (!arg.defaultValueExpression().isEmpty())
+ userArgs.append(CPP_ARG_REMOVED(i));
+ } else {
+ if (hasConversionRule) {
+ userArgs.append(arg.name() + CONV_RULE_OUT_VAR_SUFFIX);
+ } else {
+ const int idx = arg.argumentIndex() - removedArgs;
+ const auto deRef = argumentIndirections.at(i);
+ QString argName = AbstractMetaType::dereferencePrefix(deRef)
+ + CPP_ARG_N(idx);
+ userArgs.append(argName);
+ }
+ }
+ // "Pass unique ptr by value" pattern: Apply std::move()
+ auto type = arg.type();
+ if (type.useStdMove())
+ userArgs.last() = stdMove(userArgs.constLast());
+ else if (type.viewOn() != nullptr)
+ userArgs.last() = explicitConversion(userArgs.constLast(), type);
+ }
+
+ // If any argument's default value was modified the method must be called
+ // with this new value whenever the user doesn't pass an explicit value to it.
+ // Also, any unmodified default value coming after the last user specified
+ // argument and before the modified argument must be explicitly stated.
+ QStringList otherArgs;
+ bool otherArgsModified = false;
+ bool argsClear = true;
+ for (auto i = func->arguments().size() - 1; i >= maxArgs + removedArgs; i--) {
+ const AbstractMetaArgument &arg = func->arguments().at(i);
+ const bool defValModified = arg.hasModifiedDefaultValueExpression();
+ const bool hasConversionRule =
+ func->hasConversionRule(TypeSystem::NativeCode, arg.argumentIndex() + 1);
+ if (argsClear && !defValModified && !hasConversionRule)
+ continue;
+ argsClear = false;
+ otherArgsModified |= defValModified || hasConversionRule || arg.isModifiedRemoved();
+ if (hasConversionRule)
+ otherArgs.prepend(arg.name() + CONV_RULE_OUT_VAR_SUFFIX);
+ else
+ otherArgs.prepend(CPP_ARG_REMOVED(i));
+ }
+ if (otherArgsModified)
+ userArgs << otherArgs;
+ }
+
+ bool isCtor = false;
+ StringStream mc(TextStream::Language::Cpp);
+
+ StringStream uva(TextStream::Language::Cpp);
+ if (func->isOperatorOverload() && !func->isCallOperator()) {
+ QString firstArg(u'(');
+ if (!func->isPointerOperator()) // no de-reference operator
+ firstArg += u'*';
+ firstArg += CPP_SELF_VAR;
+ firstArg += u')';
+ QString secondArg = CPP_ARG0;
+ if (!func->isUnaryOperator())
+ AbstractMetaType::applyDereference(&secondArg, argumentIndirections.at(0));
+
+ if (func->isUnaryOperator())
+ std::swap(firstArg, secondArg);
+
+ QString op = func->originalName();
+ op.remove(0, int(std::strlen("operator")));
+
+ if (func->isBinaryOperator()) {
+ if (func->isReverseOperator())
+ std::swap(firstArg, secondArg);
+
+ // Emulate operator+=/-= (__iadd__, __isub__) by using ++/--
+ if (((op == u"++") || (op == u"--")) && !func->isReverseOperator()) {
+ s << "\nfor (int i = 0; i < " << secondArg
+ << "; ++i, " << op << firstArg << ");\n";
+ mc << firstArg;
+ } else {
+ mc << firstArg << ' ' << op << ' ' << secondArg;
+ }
+ } else {
+ mc << op << ' ' << secondArg;
+ }
+ } else if (!injectedCodeCallsCppFunction(context, func)) {
+ if (func->isConstructor()) {
+ isCtor = true;
+ const auto owner = func->ownerClass();
+ Q_ASSERT(owner == context.metaClass());
+ if (func->functionType() == AbstractMetaFunction::CopyConstructorFunction
+ && maxArgs == 1) {
+ mc << "new " << globalScopePrefix(context) << context.effectiveClassName()
+ << "(*" << CPP_ARG0 << ')';
+ } else {
+ const QString ctorCall = context.effectiveClassName() + u'('
+ + userArgs.join(u", "_s) + u')';
+ if (usePySideExtensions() && isQObject(owner)) {
+ s << "void *addr = PySide::nextQObjectMemoryAddr();\n";
+ uva << "if (addr != nullptr) {\n" << indent
+ << "cptr = new (addr) " << globalScopePrefix(context) << ctorCall
+ << ";\nPySide::setNextQObjectMemoryAddr(nullptr);\n" << outdent
+ << "} else {\n" << indent
+ << "cptr = new " << globalScopePrefix(context) << ctorCall << ";\n"
+ << outdent << "}\n";
+ } else {
+ mc << "new " << globalScopePrefix(context) << ctorCall;
+ }
+ }
+ } else {
+ QString methodCallClassName;
+ if (context.forSmartPointer())
+ methodCallClassName = context.preciseType().cppSignature();
+ else if (func->ownerClass())
+ methodCallClassName = func->ownerClass()->qualifiedCppName();
+
+ if (auto ownerClass = func->ownerClass()) {
+ const bool hasWrapper = shouldGenerateCppWrapper(ownerClass);
+ if (!avoidProtectedHack() || !func->isProtected() || !hasWrapper) {
+ if (func->isStatic()) {
+ mc << m_gsp << methodCallClassName << "::";
+ } else {
+ const QString cppSelfVar = CPP_SELF_VAR;
+ const QString selfVarCast = func->ownerClass() == func->implementingClass()
+ ? cppSelfVar
+ : u"reinterpret_cast<"_s + methodCallClassName
+ + u" *>("_s + cppSelfVar + u')';
+ if (func->isConstant()) {
+ if (avoidProtectedHack()) {
+ mc << "const_cast<const " << globalScopePrefix(context);
+ if (ownerClass->cppWrapper().testFlag(AbstractMetaClass::CppProtectedHackWrapper)) {
+ // PYSIDE-500: Need a special wrapper cast when inherited
+ const QString selfWrapCast = ownerClass == func->implementingClass()
+ ? cppSelfVar
+ : u"reinterpret_cast<"_s + wrapperName(ownerClass)
+ + u" *>("_s + cppSelfVar + u')';
+ mc << wrapperName(ownerClass);
+ mc << " *>(" << selfWrapCast << ")->";
+ }
+ else {
+ mc << methodCallClassName;
+ mc << " *>(" << selfVarCast << ")->";
+ }
+ } else {
+ mc << "const_cast<const " << m_gsp << methodCallClassName;
+ mc << " *>(" << selfVarCast << ")->";
+ }
+ } else {
+ mc << selfVarCast << "->";
+ }
+ }
+
+ if (!func->isAbstract() && func->isVirtual())
+ mc << "::%CLASS_NAME::";
+
+ mc << func->originalName();
+ } else {
+ if (!func->isStatic()) {
+ const bool directInheritance = context.metaClass() == ownerClass;
+ mc << (directInheritance ? "static_cast" : "reinterpret_cast")
+ << '<' << wrapperName(ownerClass) << " *>("
+ << CPP_SELF_VAR << ")->";
+ }
+
+ if (!func->isAbstract())
+ mc << (func->isProtected() ? wrapperName(func->ownerClass()) :
+ m_gsp + methodCallClassName) << "::";
+ mc << func->originalName() << "_protected";
+ }
+ } else {
+ mc << func->originalName();
+ }
+ mc << '(' << userArgs.join(u", "_s) << ')';
+ if (!func->isAbstract() && func->isVirtual()) {
+ if (!avoidProtectedHack() || !func->isProtected()) {
+ QString virtualCall = mc;
+ QString normalCall = virtualCall;
+ virtualCall.replace(u"%CLASS_NAME"_s,
+ methodCallClassName);
+ normalCall.remove(u"::%CLASS_NAME::"_s);
+ mc.clear();
+ mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(self))\n"
+ << " ? " << virtualCall << '\n'
+ << " : " << normalCall;
+ }
+ }
+ }
+ }
+
+ if (!injectedCodeCallsCppFunction(context, func)) {
+ const bool allowThread = func->allowThread();
+ generateExceptionHandling = func->generateExceptionHandling();
+ if (generateExceptionHandling) {
+ s << tryBlock << indent;
+ if (allowThread) {
+ s << "Shiboken::ThreadStateSaver threadSaver;\n"
+ << "threadSaver.save();\n";
+ }
+ } else if (allowThread) {
+ s << BEGIN_ALLOW_THREADS << '\n';
+ }
+ if (isCtor) {
+ if (uva.size() > 0)
+ s << uva.toString() << '\n';
+ else
+ s << "cptr = " << mc.toString() << ";\n";
+ } else if (!func->isVoid() && !func->isInplaceOperator()) {
+ bool writeReturnType = true;
+ if (avoidProtectedHack()) {
+ auto metaEnum = api().findAbstractMetaEnum(func->type().typeEntry());
+ if (metaEnum.has_value()) {
+ QString enumName;
+ if (metaEnum->isProtected()) {
+ enumName = context.wrapperName() + u"::"_s
+ + metaEnum.value().name();
+ } else {
+ enumName = func->type().cppSignature();
+ }
+ const QString methodCall = enumName + u'('
+ + mc.toString() + u')';
+ mc.clear();
+ mc << methodCall;
+ s << enumName;
+ writeReturnType = false;
+ }
+ }
+ QString methodCall = mc.toString();
+ if (writeReturnType) {
+ s << func->type().cppSignature();
+ if (func->type().isObjectTypeUsedAsValueType()) {
+ s << '*';
+ methodCall = u"new "_s
+ + func->type().typeEntry()->qualifiedCppName()
+ + u'(' + mc.toString() + u')';
+ }
+ }
+ s << " " << CPP_RETURN_VAR << " = " << methodCall << ";\n";
+ } else {
+ s << mc.toString() << ";\n";
+ }
+
+ if (allowThread) {
+ s << (generateExceptionHandling
+ ? u"threadSaver.restore();"_s : END_ALLOW_THREADS) << '\n';
+ }
+
+ // Convert result
+ const auto funcType = func->type();
+ if (func->hasConversionRule(TypeSystem::TargetLangCode, 0)) {
+ writeConversionRule(s, func, TypeSystem::TargetLangCode,
+ PYTHON_RETURN_VAR);
+ } else if (!isCtor && !func->isInplaceOperator() && !func->isVoid()
+ && !func->injectedCodeHasReturnValueAttribution(TypeSystem::TargetLangCode)) {
+ if (func->type().isObjectTypeUsedAsValueType()) {
+ s << PYTHON_RETURN_VAR << " = Shiboken::Object::newObject("
+ << cpythonTypeNameExt(func->type().typeEntry())
+ << ", " << CPP_RETURN_VAR << ", true, true)";
+ } else if (func->generateOpaqueContainerReturn()) {
+ const QString creationFunc = opaqueContainerCreationFunc(funcType);
+ writeOpaqueContainerCreationFuncDecl(s, creationFunc, funcType);
+ s << PYTHON_RETURN_VAR << " = " << creationFunc
+ << "(&" << CPP_RETURN_VAR << ");\n";
+ } else {
+ s << PYTHON_RETURN_VAR << " = ";
+ writeToPythonConversion(s, funcType, func->ownerClass(),
+ CPP_RETURN_VAR);
+ }
+ s << ";\n";
+ }
+
+ if (generateExceptionHandling) { // "catch" code
+ s << outdent << defaultExceptionHandling;
+ }
+ } // !injected code calls C++ function
+ } // !userAdded
+
+ if (func->hasInjectedCode() && !func->isConstructor())
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd,
+ TypeSystem::TargetLangCode, func, usesPyArgs, lastArg);
+
+ bool hasReturnPolicy = false;
+
+ // Ownership transference between C++ and Python.
+ QList<ArgumentModification> ownership_mods;
+ // Python object reference management.
+ QList<ArgumentModification> refcount_mods;
+ for (const auto &func_mod : func->modifications()) {
+ for (const ArgumentModification &arg_mod : func_mod.argument_mods()) {
+ if (arg_mod.targetOwnerShip() != TypeSystem::UnspecifiedOwnership)
+ ownership_mods.append(arg_mod);
+ else if (!arg_mod.referenceCounts().isEmpty())
+ refcount_mods.append(arg_mod);
+ }
+ }
+
+ // If there's already a setParent(return, me), don't use the return heuristic!
+ if (func->argumentOwner(func->ownerClass(), -1).index == 0)
+ hasReturnPolicy = true;
+
+ if (!ownership_mods.isEmpty()) {
+ s << '\n' << "// Ownership transferences.\n";
+ for (const ArgumentModification &arg_mod : std::as_const(ownership_mods)) {
+ const int argIndex = arg_mod.index();
+ const QString pyArgName = argumentNameFromIndex(api(), func, argIndex);
+
+ if (argIndex == 0 || arg_mod.owner().index == 0)
+ hasReturnPolicy = true;
+
+ // The default ownership does nothing. This is useful to avoid automatic heuristically
+ // based generation of code defining parenting.
+ const auto ownership = arg_mod.targetOwnerShip();
+ if (ownership == TypeSystem::DefaultOwnership)
+ continue;
+
+ s << "Shiboken::Object::";
+ if (ownership == TypeSystem::TargetLangOwnership) {
+ s << "getOwnership(" << pyArgName << ");";
+ } else if (auto ac = argumentClassFromIndex(api(), func, argIndex);
+ ac && ac->hasVirtualDestructor()) {
+ s << "releaseOwnership(" << pyArgName << ");";
+ } else {
+ s << "invalidate(" << pyArgName << ");";
+ }
+ s << '\n';
+ }
+
+ } else if (!refcount_mods.isEmpty()) {
+ for (const ArgumentModification &arg_mod : std::as_const(refcount_mods)) {
+ ReferenceCount refCount = arg_mod.referenceCounts().constFirst();
+ if (refCount.action != ReferenceCount::Set
+ && refCount.action != ReferenceCount::Remove
+ && refCount.action != ReferenceCount::Add) {
+ qCWarning(lcShiboken) << "\"set\", \"add\" and \"remove\" are the only values supported by Shiboken for action attribute of reference-count tag.";
+ continue;
+ }
+ const int argIndex = arg_mod.index();
+ const QString pyArgName = refCount.action == ReferenceCount::Remove
+ ? u"Py_None"_s : argumentNameFromIndex(api(), func, argIndex);
+
+ if (refCount.action == ReferenceCount::Add || refCount.action == ReferenceCount::Set)
+ s << "Shiboken::Object::keepReference(";
+ else
+ s << "Shiboken::Object::removeReference(";
+
+ s << "reinterpret_cast<SbkObject *>(self), \"";
+ QString varName = arg_mod.referenceCounts().constFirst().varName;
+ if (varName.isEmpty())
+ varName = func->minimalSignature() + QString::number(argIndex);
+
+ s << varName << "\", " << pyArgName
+ << (refCount.action == ReferenceCount::Add ? ", true" : "")
+ << ");\n";
+
+ if (argIndex == 0)
+ hasReturnPolicy = true;
+ }
+ }
+ writeParentChildManagement(s, func, usesPyArgs, !hasReturnPolicy);
+
+ if (generateExceptionHandling)
+ s << propagateException;
+}
+
+QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClassCPtr &metaClass)
+{
+ QStringList result;
+ const auto &baseClases = metaClass->typeSystemBaseClasses();
+ if (!baseClases.isEmpty()) {
+ for (const auto &baseClass : baseClases) {
+ QString offset;
+ QTextStream(&offset) << "reinterpret_cast<uintptr_t>(static_cast<const "
+ << baseClass->qualifiedCppName() << " *>(class_ptr)) - base";
+ result.append(offset);
+ offset.clear();
+ QTextStream(&offset) << "reinterpret_cast<uintptr_t>(static_cast<const "
+ << baseClass->qualifiedCppName() << " *>(static_cast<const "
+ << metaClass->qualifiedCppName()
+ << " *>(static_cast<const void *>(class_ptr)))) - base";
+ result.append(offset);
+ }
+
+ for (const auto &baseClass : baseClases)
+ result.append(getAncestorMultipleInheritance(baseClass));
+ }
+ return result;
+}
+
+void CppGenerator::writeMultipleInheritanceInitializerFunction(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ QString className = metaClass->qualifiedCppName();
+ const QStringList ancestors = getAncestorMultipleInheritance(metaClass);
+ s << "int *\n"
+ << multipleInheritanceInitializerFunctionName(metaClass) << "(const void *cptr)\n"
+ << "{\n" << indent;
+ s << "static int mi_offsets[] = {-2";
+ for (qsizetype i = 0; i < ancestors.size(); i++)
+ s << ", 0";
+ s << "};\n"
+ << "if (mi_offsets[0] == -2) {\n" << indent
+ << "const auto *class_ptr = reinterpret_cast<const " << className << " *>(cptr);\n"
+ << "const auto base = reinterpret_cast<uintptr_t>(class_ptr);\n"
+ << "int *p = mi_offsets;\n";
+
+ for (const QString &ancestor : ancestors)
+ s << "*p++ = int(" << ancestor << ");\n";
+ s << "std::sort(mi_offsets, p);\n"
+ << "auto *end = std::unique(mi_offsets, p);\n"
+ << "*end++ = -1;\n"
+ << "if (mi_offsets[0] == 0)\n"
+ << indent
+ << "std::memmove(&mi_offsets[0], &mi_offsets[1], (end - mi_offsets - 1) * sizeof(int));\n"
+ << outdent << outdent
+ << "}\nreturn mi_offsets;\n" << outdent << "}\n";
+}
+
+void CppGenerator::writeSpecialCastFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass)
+{
+ QString className = metaClass->qualifiedCppName();
+ s << "static void * " << cpythonSpecialCastFunctionName(metaClass)
+ << "(void *obj, PyTypeObject *desiredType)\n{\n" << indent
+ << "auto me = reinterpret_cast< " << m_gsp << className << " *>(obj);\n";
+ bool firstClass = true;
+ const auto &allAncestors = metaClass->allTypeSystemAncestors();
+ for (const auto &baseClass : allAncestors) {
+ if (!firstClass)
+ s << "else ";
+ s << "if (desiredType == " << cpythonTypeNameExt(baseClass->typeEntry())
+ << ")\n" << indent
+ << "return static_cast< " << getFullTypeName(baseClass) << " *>(me);\n"
+ << outdent;
+ firstClass = false;
+ }
+ s << "return me;\n" << outdent << "}\n\n";
+}
+
+void CppGenerator::writePrimitiveConverterInitialization(TextStream &s,
+ const CustomConversionPtr &customConversion)
+{
+ TypeEntryCPtr type = customConversion->ownerType();
+ QString converter = converterObject(type);
+ s << "// Register converter for type '" << type->qualifiedTargetLangName() << "'.\n"
+ << converter << " = Shiboken::Conversions::createConverter(";
+ if (!type->hasTargetLangApiType())
+ s << "nullptr";
+ else if (type->targetLangApiName() == cPyObjectT)
+ s << "&PyBaseObject_Type";
+ else
+ s << '&' << type->targetLangApiName() << "_Type";
+ QString typeName = fixedCppTypeName(type);
+ s << ", " << cppToPythonFunctionName(typeName, typeName) << ");\n"
+ << registerConverterName(type->qualifiedCppName(), converter);
+ writeCustomConverterRegister(s, customConversion, converter);
+}
+
+static void registerConverterInScopes(TextStream &s, QStringView signature,
+ QAnyStringView varName = converterVar)
+{
+ while (true) {
+ s << registerConverterName(signature, varName);
+ const auto qualifierPos = signature.indexOf("::"_L1);
+ if (qualifierPos == -1)
+ break;
+ signature = signature.sliced(qualifierPos + 2);
+ }
+}
+
+void CppGenerator::writeEnumConverterInitialization(TextStream &s, const AbstractMetaEnum &metaEnum)
+{
+ if (metaEnum.isPrivate() || metaEnum.isAnonymous())
+ return;
+ EnumTypeEntryCPtr enumType = metaEnum.typeEntry();
+ Q_ASSERT(enumType);
+
+ static const char enumPythonVar[] = "EType";
+
+ s << "// Register converter for enum '" << enumType->qualifiedCppName()
+ << "'.\n{\n" << indent;
+
+ const QString typeName = fixedCppTypeName(enumType);
+ s << "SbkConverter *converter = Shiboken::Conversions::createConverter("
+ << enumPythonVar << ',' << '\n' << indent
+ << cppToPythonFunctionName(typeName, typeName) << ");\n" << outdent;
+
+ const QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ const QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ writeAddPythonToCppConversion(s, u"converter"_s, toCpp, isConv);
+ s << "Shiboken::Enum::setTypeConverter(" << enumPythonVar
+ << ", converter);\n";
+
+ registerConverterInScopes(s, enumType->qualifiedCppName());
+ if (auto flags = enumType->flags())
+ s << "// Register converter for flag '" << flags->qualifiedCppName() << "'.\n"
+ << registerConverterName(flags->name()) // QMetaType
+ << registerConverterName(flags->originalName()); // Signals with flags
+
+ s << outdent << "}\n";
+}
+
+QString CppGenerator::writeContainerConverterInitialization(TextStream &s,
+ const AbstractMetaType &type,
+ const ApiExtractorResult &api)
+{
+ const auto cppSignature =
+ QString::fromUtf8(QMetaObject::normalizedSignature(type.cppSignature().toUtf8()));
+ s << "// Register converter for type '" << cppSignature << "'.\n";
+ const QString converter = converterObject(type);
+ s << converter << " = Shiboken::Conversions::createConverter(";
+
+ Q_ASSERT(type.typeEntry()->isContainer());
+ const auto typeEntry = std::static_pointer_cast<const ContainerTypeEntry>(type.typeEntry());
+
+ const QString targetTypeName = containerNativeToTargetTypeName(typeEntry);
+ if (targetTypeName == cPyObjectT) {
+ s << "&PyBaseObject_Type";
+ } else {
+ s << '&' << targetTypeName << "_Type";
+ }
+
+ const QString typeName = fixedCppTypeName(type);
+ s << ", " << cppToPythonFunctionName(typeName, targetTypeName) << ");\n";
+
+ s << registerConverterName(cppSignature, converter);
+ if (usePySideExtensions() && cppSignature.startsWith("const "_L1)
+ && cppSignature.endsWith(u'&')) {
+ auto underlyingType = QStringView{cppSignature}.sliced(6, cppSignature.size() - 7);
+ s << registerConverterName(underlyingType, converter);
+ }
+
+ for (const auto &conv : typeEntry->customConversion()->targetToNativeConversions()) {
+ const QString &sourceTypeName = conv.sourceTypeName();
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, typeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, typeName);
+ writeAddPythonToCppConversion(s, converter, toCpp, isConv);
+ }
+
+ auto typedefItPair = api.typedefTargetToName().equal_range(type.cppSignature());
+ if (typedefItPair.first != typedefItPair.second) {
+ auto *typeDb = TypeDatabase::instance();
+ s << "// Register converters for type aliases of " << cppSignature << "'.\n";
+ for (auto it = typedefItPair.first; it != typedefItPair.second; ++it) {
+ if (!typeDb->findType(it.value()))
+ s << registerConverterName(it.value(), converter);
+ }
+ }
+
+ return converter;
+}
+
+QString CppGenerator::typeInitStruct(const TypeEntryCPtr &te)
+{
+ return cppApiVariableName(te->targetLangPackage()) + u'['
+ + getTypeIndexVariableName(te) + u']';
+}
+
+void CppGenerator::writeExtendedConverterInitialization(TextStream &s,
+ const TypeEntryCPtr &externalType,
+ const AbstractMetaClassCList &conversions)
+{
+ s << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName()
+ << ".\n";
+ for (const auto &sourceClass : conversions) {
+ QString sourceTypeName = fixedCppTypeName(sourceClass->typeEntry());
+ QString targetTypeName = fixedCppTypeName(externalType);
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ if (!externalType->isPrimitive())
+ s << cpythonTypeNameExt(externalType) << ";\n";
+ writeAddPythonToCppConversion(s, typeInitStruct(externalType), toCpp, isConv);
+ }
+}
+
+QString CppGenerator::multipleInheritanceInitializerFunctionName(const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonBaseName(metaClass->typeEntry()) + u"_mi_init"_s;
+}
+
+bool CppGenerator::supportsMappingProtocol(const AbstractMetaClassCPtr &metaClass)
+{
+ for (const auto &m : mappingProtocols()) {
+ if (metaClass->hasFunction(m.name))
+ return true;
+ }
+
+ return false;
+}
+
+bool CppGenerator::supportsNumberProtocol(const AbstractMetaClassCPtr &metaClass)
+{
+ return metaClass->hasArithmeticOperatorOverload()
+ || metaClass->hasIncDecrementOperatorOverload()
+ || metaClass->hasLogicalOperatorOverload()
+ || metaClass->hasBitwiseOperatorOverload()
+ || hasBoolCast(metaClass);
+}
+
+bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClassCPtr &metaClass)
+{
+ for (const auto &seq : sequenceProtocols()) {
+ if (metaClass->hasFunction(seq.name))
+ return true;
+ }
+
+ ComplexTypeEntryCPtr baseType = metaClass->typeEntry()->baseContainerType();
+ return baseType && baseType->isContainer();
+}
+
+bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClassCPtr &metaClass)
+{
+ for (const AbstractMetaField &f : metaClass->fields()) {
+ if (!f.isStatic())
+ return true;
+ }
+ // Generate all user-added properties unless Pyside extensions are used,
+ // in which only the explicitly specified ones are generated (rest is handled
+ // in libpyside).
+ return usePySideExtensions()
+ ? std::any_of(metaClass->propertySpecs().cbegin(), metaClass->propertySpecs().cend(),
+ [] (const QPropertySpec &s) { return s.generateGetSetDef(); })
+ : !metaClass->propertySpecs().isEmpty();
+ return false;
+}
+
+struct pyTypeSlotEntry
+{
+ explicit pyTypeSlotEntry(QAnyStringView name, QAnyStringView function) :
+ m_name(name), m_function(function) {}
+
+ QAnyStringView m_name;
+ QAnyStringView m_function;
+};
+
+TextStream &operator<<(TextStream &str, const pyTypeSlotEntry &e)
+{
+ if (!e.m_function.isEmpty()) {
+ str << '{' << e.m_name << ',' << Pad(' ', qMax(0, 18 - e.m_name.size()))
+ << "reinterpret_cast<void *>(" << e.m_function << ")},\n";
+ }
+ return str;
+}
+
+void CppGenerator::writeClassDefinition(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext)
+{
+ QString tp_init;
+ QString tp_new;
+ QString tp_dealloc;
+ QString tp_hash;
+ QString tp_call;
+ const QString className = chopType(cpythonTypeName(metaClass));
+ AbstractMetaFunctionCList ctors;
+ const auto &allCtors = metaClass->queryFunctions(FunctionQueryOption::AnyConstructor);
+ for (const auto &f : allCtors) {
+ if (!f->isPrivate() && !f->isModifiedRemoved()
+ && f->functionType() != AbstractMetaFunction::MoveConstructorFunction) {
+ ctors.append(f);
+ }
+ }
+
+ bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
+
+ const bool isQApp = usePySideExtensions()
+ && inheritsFrom(metaClass, u"QCoreApplication"_s);
+
+ QString tp_flags = u"Py_TPFLAGS_DEFAULT"_s;
+ if (!metaClass->attributes().testFlag(AbstractMetaClass::FinalCppClass))
+ tp_flags += u"|Py_TPFLAGS_BASETYPE"_s;
+ if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) {
+ tp_dealloc = metaClass->hasPrivateDestructor() ?
+ u"SbkDeallocWrapperWithPrivateDtor"_s :
+ u"Sbk_object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */"_s;
+ tp_init.clear();
+ } else {
+ tp_dealloc = isQApp
+ ? u"&SbkDeallocQAppWrapper"_s : u"&SbkDeallocWrapper"_s;
+ if (!onlyPrivCtor && !ctors.isEmpty())
+ tp_init = cpythonFunctionName(ctors.constFirst());
+ }
+
+ const AttroCheck attroCheck = checkAttroFunctionNeeds(metaClass);
+ const QString tp_getattro = (attroCheck & AttroCheckFlag::GetattroMask) != 0
+ ? cpythonGetattroFunctionName(metaClass) : QString();
+ const QString tp_setattro = (attroCheck & AttroCheckFlag::SetattroMask) != 0
+ ? cpythonSetattroFunctionName(metaClass) : QString();
+
+ if (metaClass->hasPrivateDestructor() || onlyPrivCtor) {
+ // tp_flags = u"Py_TPFLAGS_DEFAULT"_s;
+ // This is not generally possible, because PySide does not care about
+ // privacy the same way. This worked before the heap types were used,
+ // because inheritance is not really checked for static types.
+ // Instead, we check this at runtime, see SbkObjectType_tp_new.
+ if (metaClass->fullName().startsWith(u"PySide6.Qt")) {
+ // PYSIDE-595: No idea how to do non-inheritance correctly.
+ // Since that is only relevant in shiboken, I used a shortcut for
+ // PySide.
+ tp_new = u"SbkObject_tp_new"_s;
+ }
+ else {
+ tp_new = u"SbkDummyNew /* PYSIDE-595: Prevent replacement "
+ "of \"0\" with base->tp_new. */"_s;
+ }
+ }
+ else if (isQApp) {
+ tp_new = u"SbkQApp_tp_new"_s; // PYSIDE-571: need singleton app
+ }
+ else {
+ tp_new = u"SbkObject_tp_new"_s;
+ }
+ tp_flags.append(u"|Py_TPFLAGS_HAVE_GC"_s);
+
+ QString tp_richcompare;
+ if (generateRichComparison(classContext))
+ tp_richcompare = cpythonBaseName(metaClass) + u"_richcompare"_s;
+
+ const bool isSmartPointer = classContext.forSmartPointer();
+ QString tp_getset;
+ if (shouldGenerateGetSetList(metaClass) && !isSmartPointer)
+ tp_getset = cpythonGettersSettersDefinitionName(metaClass);
+
+ // search for special functions
+ clearTpFuncs();
+ for (const auto &func : metaClass->functions()) {
+ // Special non-operator functions identified by name
+ auto it = m_tpFuncs.find(func->name());
+ if (it != m_tpFuncs.end())
+ it.value() = cpythonFunctionName(func);
+ else if ( it = m_nbFuncs.find(func->name()); it != m_nbFuncs.end() )
+ it.value() = cpythonFunctionName(func);
+ }
+ if (m_tpFuncs.value(REPR_FUNCTION).isEmpty()
+ && (isSmartPointer || metaClass->hasToStringCapability())) {
+ const QString name = isSmartPointer
+ ? writeSmartPointerReprFunction(s, classContext)
+ : writeReprFunction(s, classContext, metaClass->toStringCapabilityIndirections());
+ m_tpFuncs[REPR_FUNCTION] = name;
+ }
+
+ // class or some ancestor has multiple inheritance
+ const auto miClass = getMultipleInheritingClass(metaClass);
+ if (miClass) {
+ if (metaClass == miClass)
+ writeMultipleInheritanceInitializerFunction(s, metaClass);
+ writeSpecialCastFunction(s, metaClass);
+ s << '\n';
+ }
+
+ s << "// Class Definition -----------------------------------------------\n"
+ "extern \"C\" {\n";
+
+ if (hasHashFunction(metaClass))
+ tp_hash = u'&' + cpythonBaseName(metaClass) + u"_HashFunc"_s;
+
+ const auto callOp = metaClass->findFunction("operator()");
+ if (callOp && !callOp->isModifiedRemoved())
+ tp_call = u'&' + cpythonFunctionName(callOp);
+
+ const QString typePtr = u"_"_s + className
+ + u"_Type"_s;
+ s << "static PyTypeObject *" << typePtr << " = nullptr;\n"
+ << "static PyTypeObject *" << className << "_TypeF(void)\n"
+ << "{\n" << indent << "return " << typePtr << ";\n" << outdent
+ << "}\n\nstatic PyType_Slot " << className << "_slots[] = {\n" << indent
+ << "{Py_tp_base, nullptr}, // inserted by introduceWrapperType\n"
+ << pyTypeSlotEntry("Py_tp_dealloc", tp_dealloc)
+ << pyTypeSlotEntry("Py_tp_repr", m_tpFuncs.value(REPR_FUNCTION))
+ << pyTypeSlotEntry("Py_tp_hash", tp_hash)
+ << pyTypeSlotEntry("Py_tp_call", tp_call)
+ << pyTypeSlotEntry("Py_tp_str", m_tpFuncs.value(u"__str__"_s))
+ << pyTypeSlotEntry("Py_tp_getattro", tp_getattro)
+ << pyTypeSlotEntry("Py_tp_setattro", tp_setattro)
+ << pyTypeSlotEntry("Py_tp_traverse", className + u"_traverse"_s)
+ << pyTypeSlotEntry("Py_tp_clear", className + u"_clear"_s)
+ << pyTypeSlotEntry("Py_tp_richcompare", tp_richcompare)
+ << pyTypeSlotEntry("Py_tp_iter", m_tpFuncs.value(u"__iter__"_s))
+ << pyTypeSlotEntry("Py_tp_iternext", m_tpFuncs.value(u"__next__"_s))
+ << pyTypeSlotEntry("Py_tp_methods", className + u"_methods"_s)
+ << pyTypeSlotEntry("Py_tp_getset", tp_getset)
+ << pyTypeSlotEntry("Py_tp_init", tp_init)
+ << pyTypeSlotEntry("Py_tp_new", tp_new);
+ if (supportsSequenceProtocol(metaClass)) {
+ s << "// type supports sequence protocol\n";
+ writeTypeAsSequenceDefinition(s, metaClass);
+ }
+ if (supportsMappingProtocol(metaClass)) {
+ s << "// type supports mapping protocol\n";
+ writeTypeAsMappingDefinition(s, metaClass);
+ }
+ if (supportsNumberProtocol(metaClass)) {
+ s << "// type supports number protocol\n";
+ writeTypeAsNumberDefinition(s, metaClass);
+ }
+ s << "{0, " << NULL_PTR << "}\n" << outdent << "};\n";
+
+ int packageLevel = packageName().count(u'.') + 1;
+ s << "static PyType_Spec " << className << "_spec = {\n" << indent
+ << '"' << packageLevel << ':' << getClassTargetFullName(metaClass) << "\",\n"
+ << "sizeof(SbkObject),\n0,\n" << tp_flags << ",\n"
+ << className << "_slots\n" << outdent
+ << "};\n\n} //extern \"C\"\n";
+}
+
+void CppGenerator::writeMappingMethods(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &context) const
+{
+ for (const auto & m : mappingProtocols()) {
+ const auto func = metaClass->findFunction(m.name);
+ if (!func)
+ continue;
+ QString funcName = cpythonFunctionName(func);
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ s << m.returnType << ' ' << funcName << '(' << m.arguments << ")\n{\n" << indent;
+
+ writeCppSelfDefinition(s, func, context, ErrorReturn::Default);
+
+ const AbstractMetaArgument *lastArg = func->arguments().isEmpty()
+ ? nullptr : &func->arguments().constLast();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, func, false, lastArg);
+ s << outdent << "}\n\n";
+ }
+}
+
+void CppGenerator::writeSequenceMethods(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &context) const
+{
+ bool injectedCode = false;
+
+ for (const auto &seq : sequenceProtocols()) {
+ const auto func = metaClass->findFunction(seq.name);
+ if (!func)
+ continue;
+ injectedCode = true;
+ QString funcName = cpythonFunctionName(func);
+
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ s << seq.returnType << ' ' << funcName << '(' << seq.arguments << ")\n{\n" << indent;
+
+ writeCppSelfDefinition(s, func, context, ErrorReturn::Default);
+
+ const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : &func->arguments().constLast();
+ writeCodeSnips(s, snips,TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, func, false /* uses PyArgs */, lastArg);
+ s<< outdent << "}\n\n";
+ }
+
+ if (!injectedCode)
+ writeDefaultSequenceMethods(s, context);
+}
+
+// Sequence protocol structure member names
+static const QHash<QString, QString> &sqFuncs()
+{
+ static const QHash<QString, QString> result = {
+ {u"__concat__"_s, u"Py_sq_concat"_s},
+ {u"__contains__"_s, u"Py_sq_contains"_s},
+ {u"__getitem__"_s, u"Py_sq_item"_s},
+ {u"__getslice__"_s, u"Py_sq_slice"_s},
+ {u"__len__"_s, u"Py_sq_length"_s},
+ {u"__setitem__"_s, u"Py_sq_ass_item"_s},
+ {u"__setslice__"_s, u"Py_sq_ass_slice"_s}
+ };
+ return result;
+}
+
+void CppGenerator::writeTypeAsSequenceDefinition(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ bool hasFunctions = false;
+ QMap<QString, QString> funcs;
+ for (const auto &seq : sequenceProtocols()) {
+ const auto func = metaClass->findFunction(seq.name);
+ if (func) {
+ funcs.insert(seq.name, u'&' + cpythonFunctionName(func));
+ hasFunctions = true;
+ }
+ }
+
+ QString baseName = cpythonBaseName(metaClass);
+
+ //use default implementation
+ if (!hasFunctions) {
+ funcs[u"__len__"_s] = baseName + u"__len__"_s;
+ funcs[u"__getitem__"_s] = baseName + u"__getitem__"_s;
+ funcs[u"__setitem__"_s] = baseName + u"__setitem__"_s;
+ }
+
+ for (auto it = sqFuncs().cbegin(), end = sqFuncs().cend(); it != end; ++it) {
+ const QString &sqName = it.key();
+ auto fit = funcs.constFind(sqName);
+ if (fit != funcs.constEnd())
+ s << pyTypeSlotEntry(it.value(), fit.value());
+ }
+}
+
+void CppGenerator::writeTypeAsMappingDefinition(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ // Sequence protocol structure members names
+ static const QHash<QString, QString> mpFuncs{
+ {u"__mlen__"_s, u"Py_mp_length"_s},
+ {u"__mgetitem__"_s, u"Py_mp_subscript"_s},
+ {u"__msetitem__"_s, u"Py_mp_ass_subscript"_s},
+ };
+ QMap<QString, QString> funcs;
+ for (const auto &m : mappingProtocols()) {
+ const auto func = metaClass->findFunction(m.name);
+ if (func) {
+ const QString entry = u"reinterpret_cast<void *>(&"_s
+ + cpythonFunctionName(func) + u')';
+ funcs.insert(m.name, entry);
+ }
+ }
+
+ for (auto it = mpFuncs.cbegin(), end = mpFuncs.cend(); it != end; ++it) {
+ const auto fit = funcs.constFind(it.key());
+ if (fit != funcs.constEnd())
+ s << pyTypeSlotEntry(it.value(), fit.value());
+ }
+}
+
+// Number protocol structure members names
+static const QHash<QString, QString> &nbFuncs()
+{
+ static const QHash<QString, QString> result = {
+ {u"__abs__"_s, u"Py_nb_absolute"_s},
+ {u"__add__"_s, u"Py_nb_add"_s},
+ {u"__sub__"_s, u"Py_nb_subtract"_s},
+ {u"__mul__"_s, u"Py_nb_multiply"_s},
+ {u"__div__"_s, u"Py_nb_true_divide"_s},
+ {u"__mod__"_s, u"Py_nb_remainder"_s},
+ {u"__neg__"_s, u"Py_nb_negative"_s},
+ {u"__pos__"_s, u"Py_nb_positive"_s},
+ {u"__pow__"_s, u"Py_nb_power"_s},
+ {u"__invert__"_s, u"Py_nb_invert"_s},
+ {u"__lshift__"_s, u"Py_nb_lshift"_s},
+ {u"__rshift__"_s, u"Py_nb_rshift"_s},
+ {u"__and__"_s, u"Py_nb_and"_s},
+ {u"__xor__"_s, u"Py_nb_xor"_s},
+ {u"__or__"_s, u"Py_nb_or"_s},
+ {u"__iadd__"_s, u"Py_nb_inplace_add"_s},
+ {u"__isub__"_s, u"Py_nb_inplace_subtract"_s},
+ {u"__imul__"_s, u"Py_nb_inplace_multiply"_s},
+ {u"__imod__"_s, u"Py_nb_inplace_remainder"_s},
+ {u"__ilshift__"_s, u"Py_nb_inplace_lshift"_s},
+ {u"__irshift__"_s, u"Py_nb_inplace_rshift"_s},
+ {u"__iand__"_s, u"Py_nb_inplace_and"_s},
+ {u"__ixor__"_s, u"Py_nb_inplace_xor"_s},
+ {u"__ior__"_s, u"Py_nb_inplace_or"_s},
+ {u"__bool__"_s, u"Py_nb_bool"_s},
+ {u"__int__"_s, u"Py_nb_int"_s},
+ {u"__float__"_s, u"Py_nb_float"_s}
+ };
+ return result;
+}
+
+void CppGenerator::writeTypeAsNumberDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass) const
+{
+ QMap<QString, QString> nb;
+
+ const QList<AbstractMetaFunctionCList> opOverloads = numberProtocolOperators(metaClass);
+ for (const auto &opOverload : opOverloads) {
+ const auto rfunc = opOverload.at(0);
+ QString opName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ nb[opName] = cpythonFunctionName(rfunc);
+ }
+
+ for (auto it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) {
+ if (!it.value().isEmpty())
+ nb.insert(it.key(), it.value());
+ }
+
+ QString baseName = cpythonBaseName(metaClass);
+
+ if (hasBoolCast(metaClass))
+ nb.insert(u"__bool__"_s, baseName + u"___nb_bool"_s);
+
+ for (auto it = nbFuncs().cbegin(), end = nbFuncs().cend(); it != end; ++it) {
+ const QString &nbName = it.key();
+ const auto nbIt = nb.constFind(nbName);
+ if (nbIt != nb.constEnd())
+ s << pyTypeSlotEntry(it.value(), nbIt.value());
+ }
+}
+
+void CppGenerator::writeTpTraverseFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass)
+{
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static int " << baseName
+ << "_traverse(PyObject *self, visitproc visit, void *arg)\n{\n" << indent
+ << "auto traverseProc = "
+ << pyTypeGetSlot("traverseproc", sbkObjectTypeF, "Py_tp_traverse") << ";\n"
+ << "return traverseProc(self, visit, arg);\n"
+ << outdent << "}\n";
+}
+
+void CppGenerator::writeTpClearFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass)
+{
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static int " << baseName << "_clear(PyObject *self)\n{\n" << indent
+ << "auto clearProc = "
+ << pyTypeGetSlot("inquiry", sbkObjectTypeF, "Py_tp_clear") << ";\n"
+ << "return clearProc(self);\n"
+ << outdent << "}\n";
+}
+
+QString CppGenerator::writeCopyFunction(TextStream &s,
+ TextStream &definitionStream,
+ TextStream &signatureStream,
+ const GeneratorContext &context)
+{
+ const auto metaClass = context.metaClass();
+ const QString className = chopType(cpythonTypeName(metaClass));
+ const QString funcName = className + u"__copy__"_s;
+
+ signatureStream << fullPythonClassName(metaClass) << ".__copy__()\n";
+ definitionStream << PyMethodDefEntry{u"__copy__"_s, funcName, {"METH_NOARGS"_ba}, {}}
+ << ",\n";
+
+ s << "static PyObject *" << funcName << "(PyObject *self)\n"
+ << "{\n" << indent;
+ writeCppSelfDefinition(s, context, ErrorReturn::Default, CppSelfDefinitionFlag::CppSelfAsReference);
+ QString conversionCode;
+ if (!context.forSmartPointer())
+ conversionCode = cpythonToPythonConversionFunction(metaClass);
+ else
+ conversionCode = cpythonToPythonConversionFunction(context.preciseType());
+
+ s << "PyObject *" << PYTHON_RETURN_VAR << " = " << conversionCode
+ << CPP_SELF_VAR << ");\n";
+ writeFunctionReturnErrorCheckSection(s, ErrorReturn::Default);
+ s << "return " << PYTHON_RETURN_VAR << ";\n" << outdent
+ << "}\n\n";
+
+ return funcName;
+}
+
+static inline void writeGetterFunctionStart(TextStream &s, const QString &funcName)
+{
+ s << "static PyObject *" << funcName << "(PyObject *self, void * /* closure */)\n"
+ << "{\n" << indent;
+}
+
+QString CppGenerator::cppFieldAccess(const AbstractMetaField &metaField,
+ const GeneratorContext &context)
+{
+ QString result;
+ QTextStream str(&result);
+ if (avoidProtectedHack() && metaField.isProtected())
+ str << "static_cast<" << context.wrapperName() << " *>(" << CPP_SELF_VAR << ')';
+ else
+ str << CPP_SELF_VAR;
+ str << "->" << metaField.originalName();
+ return result;
+}
+
+void CppGenerator::writeGetterFunction(TextStream &s,
+ const AbstractMetaField &metaField,
+ const GeneratorContext &context)
+{
+ writeGetterFunctionStart(s, cpythonGetterFunctionName(metaField));
+
+ writeCppSelfDefinition(s, context);
+
+ const AbstractMetaType &fieldType = metaField.type();
+ // Force use of pointer to return internal variable memory
+ bool newWrapperSameObject = !fieldType.isConstant() && fieldType.isWrapperType()
+ && !fieldType.isPointer();
+
+ QString cppField = cppFieldAccess(metaField, context);
+
+ if (metaField.generateOpaqueContainer()
+ && fieldType.generateOpaqueContainer()) {
+ const QString creationFunc = opaqueContainerCreationFunc(fieldType);
+ writeOpaqueContainerCreationFuncDecl(s, creationFunc, fieldType);
+ s << "PyObject *pyOut = " << creationFunc
+ << "(&" << cppField << ");\nPy_IncRef(pyOut);\n"
+ << "return pyOut;\n" << outdent << "}\n";
+ return;
+ }
+
+ if (newWrapperSameObject) {
+ cppField.prepend(u"&(");
+ cppField.append(u')');
+ }
+
+ if (fieldType.isCppIntegralPrimitive() || fieldType.isEnum()) {
+ s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ";\n";
+ cppField = u"cppOut_local"_s;
+ }
+
+ s << "PyObject *pyOut = {};\n";
+ if (newWrapperSameObject) {
+ // Special case colocated field with same address (first field in a struct)
+ s << "if (reinterpret_cast<void *>("
+ << cppField << ") == reinterpret_cast<void *>("
+ << CPP_SELF_VAR << ")) {\n" << indent
+ << "pyOut = reinterpret_cast<PyObject *>(Shiboken::Object::findColocatedChild("
+ << "reinterpret_cast<SbkObject *>(self), "
+ << cpythonTypeNameExt(fieldType) << "));\n"
+ << "if (pyOut != nullptr) {\n" << indent
+ << "Py_IncRef(pyOut);\n"
+ << "return pyOut;\n"
+ << outdent << "}\n";
+ // Check if field wrapper has already been created.
+ s << outdent << "} else if (Shiboken::BindingManager::instance().hasWrapper("
+ << cppField << ")) {" << "\n" << indent
+ << "pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper("
+ << cppField << "));" << "\n"
+ << "Py_IncRef(pyOut);" << "\n"
+ << "return pyOut;" << "\n"
+ << outdent << "}\n";
+ // Create and register new wrapper. We force a pointer conversion also
+ // for wrapped value types so that they refer to the struct member,
+ // avoiding any trouble copying them. Add a parent relationship to
+ // properly notify if the struct is deleted (see protected_test.py,
+ // testProtectedValueTypeProperty()). Note that this has currently
+ // unsolved issues when using temporary Python lists of structs
+ // which can cause elements to be reported deleted in expressions like
+ // "foo.list_of_structs[2].field".
+ s << "pyOut = "
+ << "Shiboken::Object::newObject(" << cpythonTypeNameExt(fieldType)
+ << ", " << cppField << ", false, true);\n"
+ << "Shiboken::Object::setParent(self, pyOut)";
+ } else {
+ s << "pyOut = ";
+ writeToPythonConversion(s, fieldType, metaField.enclosingClass(), cppField);
+ }
+ s << ";\nreturn pyOut;\n" << outdent << "}\n";
+}
+
+// Write a getter for QPropertySpec
+void CppGenerator::writeGetterFunction(TextStream &s,
+ const QPropertySpec &property,
+ const GeneratorContext &context)
+{
+ writeGetterFunctionStart(s, cpythonGetterFunctionName(property, context.metaClass()));
+ writeCppSelfDefinition(s, context);
+ const QString value = "value"_L1;
+ s << "auto " << value << " = " << CPP_SELF_VAR << "->" << property.read() << "();\n"
+ << "auto *pyResult = ";
+ writeToPythonConversion(s, property.type(), context.metaClass(), value);
+ s << ";\nif (" << shibokenErrorsOccurred << " || pyResult == nullptr) {\n"
+ << indent << "Py_XDECREF(pyResult);\nreturn {};\n" << outdent
+ << "}\nreturn pyResult;\n" << outdent << "}\n\n";
+}
+
+// Write setter function preamble (type checks on "pyIn")
+void CppGenerator::writeSetterFunctionPreamble(TextStream &s,
+ const QString &name,
+ const QString &funcName,
+ const AbstractMetaType &type,
+ const GeneratorContext &context)
+{
+ s << "static int " << funcName << "(PyObject *self, PyObject *pyIn, void * /* closure */)\n"
+ << "{\n" << indent;
+
+ writeCppSelfDefinition(s, context, ErrorReturn::Zero);
+
+ s << "if (pyIn == " << NULL_PTR << ") {\n" << indent
+ << "Shiboken::Errors::setInvalidTypeDeletion(\"" << name << "\");\n"
+ << "return -1;\n"
+ << outdent << "}\n";
+
+ s << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR << ";\n"
+ << "if (!";
+ writeTypeCheck(s, type, u"pyIn"_s, isNumber(type.typeEntry()));
+ s << ") {\n" << indent
+ << "Shiboken::Errors::setSetterTypeError(\"" << name << "\", \""
+ << type.name() << "\");\n"
+ << "return -1;\n"
+ << outdent << "}\n\n";
+}
+
+void CppGenerator::writeSetterFunction(TextStream &s,
+ const AbstractMetaField &metaField,
+ const GeneratorContext &context)
+{
+ const AbstractMetaType &fieldType = metaField.type();
+ writeSetterFunctionPreamble(s, metaField.name(), cpythonSetterFunctionName(metaField),
+ fieldType, context);
+
+
+ const QString cppField = cppFieldAccess(metaField, context);
+
+ if (fieldType.isCppIntegralPrimitive() || fieldType.typeEntry()->isEnum()
+ || fieldType.typeEntry()->isFlags()) {
+ s << "auto cppOut_local = " << cppField << ";\n"
+ << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);\n"
+ << cppField << " = cppOut_local";
+ } else {
+ if (fieldType.isPointerToConst())
+ s << "const ";
+ s << "auto " << QByteArray(fieldType.indirections(), '*')
+ << "&cppOut_ptr = " << cppField << ";\n"
+ << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_ptr)";
+ }
+ s << ";\n\n";
+
+ if (fieldType.isPointerToWrapperType()) {
+ s << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(self), \""
+ << metaField.name() << "\", pyIn);\n";
+ }
+
+ s << "return 0;\n" << outdent << "}\n";
+}
+
+// Write a setter for QPropertySpec
+void CppGenerator::writeSetterFunction(TextStream &s,
+ const QPropertySpec &property,
+ const GeneratorContext &context)
+{
+ writeSetterFunctionPreamble(s,
+ property.name(),
+ cpythonSetterFunctionName(property, context.metaClass()),
+ property.type(), context);
+
+ s << "auto cppOut = " << CPP_SELF_VAR << "->" << property.read() << "();\n"
+ << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut);\n"
+ << "if (" << shibokenErrorsOccurred << ")\n" << indent
+ << "return -1;\n" << outdent
+ << CPP_SELF_VAR << "->" << property.write() << "(cppOut);\n"
+ << "return 0;\n" << outdent << "}\n\n";
+}
+
+void CppGenerator::writeRichCompareFunctionHeader(TextStream &s,
+ const QString &baseName,
+ const GeneratorContext &context)
+{
+ s << "static PyObject * ";
+ s << baseName << "_richcompare(PyObject *self, PyObject *" << PYTHON_ARG
+ << ", int op)\n{\n" << indent;
+ writeCppSelfDefinition(s, context, ErrorReturn::Default, CppSelfDefinitionFlag::CppSelfAsReference);
+ s << sbkUnusedVariableCast(CPP_SELF_VAR)
+ << "PyObject *" << PYTHON_RETURN_VAR << "{};\n"
+ << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR << ";\n"
+ << sbkUnusedVariableCast(PYTHON_TO_CPP_VAR) << '\n';
+}
+
+void CppGenerator::writeRichCompareFunction(TextStream &s,
+ const GeneratorContext &context) const
+{
+ const auto metaClass = context.metaClass();
+ QString baseName = cpythonBaseName(metaClass);
+ writeRichCompareFunctionHeader(s, baseName, context);
+
+ s << "switch (op) {\n" << indent;
+ const QList<AbstractMetaFunctionCList> &groupedFuncs =
+ filterGroupedOperatorFunctions(metaClass, OperatorQueryOption::ComparisonOp);
+ for (const AbstractMetaFunctionCList &overloads : groupedFuncs) {
+ const auto rfunc = overloads[0];
+
+ const auto op = rfunc->comparisonOperatorType().value();
+ s << "case " << AbstractMetaFunction::pythonRichCompareOpCode(op)
+ << ":\n" << indent;
+
+ int alternativeNumericTypes = 0;
+ for (const auto &func : overloads) {
+ if (!func->isStatic() &&
+ ShibokenGenerator::isNumber(func->arguments().at(0).type().typeEntry()))
+ alternativeNumericTypes++;
+ }
+
+ bool first = true;
+ OverloadData overloadData(overloads, api());
+ const OverloadDataList &nextOverloads = overloadData.children();
+ for (const auto &od : nextOverloads) {
+ const auto func = od->referenceFunction();
+ if (func->isStatic())
+ continue;
+ auto argType = getArgumentType(func, 0);
+ if (!first) {
+ s << " else ";
+ } else {
+ first = false;
+ }
+ s << "if (";
+ writeTypeCheck(s, argType, PYTHON_ARG,
+ alternativeNumericTypes == 1 || isPyInt(argType));
+ s << ") {\n" << indent
+ << "// " << func->signature() << '\n';
+ writeArgumentConversion(s, argType, CPP_ARG0,
+ PYTHON_ARG, ErrorReturn::Default,
+ metaClass,
+ QString(), func->isUserAdded());
+ // If the function is user added, use the inject code
+ bool generateOperatorCode = true;
+ if (func->isUserAdded()) {
+ CodeSnipList snips = func->injectedCodeSnips();
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, func,
+ false /* uses PyArgs */, &func->arguments().constLast());
+ generateOperatorCode = false;
+ }
+ }
+ if (generateOperatorCode) {
+ if (!func->isVoid())
+ s << func->type().cppSignature() << " " << CPP_RETURN_VAR << " = ";
+ // expression
+ if (func->isPointerOperator())
+ s << '&';
+ s << CPP_SELF_VAR << ' '
+ << AbstractMetaFunction::cppComparisonOperator(op) << " (";
+ auto generatorArg = GeneratorArgument::fromMetaType(argType);
+ if (generatorArg.indirections != 0)
+ s << QByteArray(generatorArg.indirections, '*');
+ s << CPP_ARG0 << ");\n"
+ << PYTHON_RETURN_VAR << " = ";
+ if (!func->isVoid()) {
+ writeToPythonConversion(s, func->type(), metaClass,
+ CPP_RETURN_VAR);
+ } else {
+ s << "Py_None;\n" << "Py_INCREF(Py_None)";
+ }
+ s << ";\n";
+ }
+ s << outdent << '}';
+ }
+
+ s << " else {\n";
+ if (op == AbstractMetaFunction::OperatorEqual ||
+ op == AbstractMetaFunction::OperatorNotEqual) {
+ s << indent << PYTHON_RETURN_VAR << " = "
+ << (op == AbstractMetaFunction::OperatorEqual ? "Py_False" : "Py_True") << ";\n"
+ << "Py_INCREF(" << PYTHON_RETURN_VAR << ");\n" << outdent;
+ } else {
+ s << indent << "return Shiboken::returnFromRichCompare("
+ << PYTHON_RETURN_VAR << ");\n" << outdent;
+ }
+ s << "}\n\n";
+
+ s << "break;\n" << outdent;
+ }
+ s << "default:\n" << indent
+ << richCompareComment
+ << "return FallbackRichCompare(self, " << PYTHON_ARG << ", op);\n"
+ << outdent << outdent << "}\n\n"
+ << "return Shiboken::returnFromRichCompare(" << PYTHON_RETURN_VAR << ");\n" << outdent
+ << "}\n\n";
+}
+
+// Return a flag combination for PyMethodDef
+QByteArrayList CppGenerator::methodDefinitionParameters(const OverloadData &overloadData) const
+{
+ const bool usePyArgs = overloadData.pythonFunctionWrapperUsesListOfArguments();
+ int min = overloadData.minArgs();
+ int max = overloadData.maxArgs();
+
+ QByteArrayList result;
+ if ((min == max) && (max < 2) && !usePyArgs) {
+ result.append(max == 0 ? QByteArrayLiteral("METH_NOARGS")
+ : QByteArrayLiteral("METH_O"));
+ } else {
+ result.append(QByteArrayLiteral("METH_VARARGS"));
+ if (overloadData.hasArgumentWithDefaultValue())
+ result.append(QByteArrayLiteral("METH_KEYWORDS"));
+ }
+ // METH_STATIC causes a crash when used for global functions (also from
+ // invisible namespaces).
+ const auto ownerClass = overloadData.referenceFunction()->ownerClass();
+ if (ownerClass
+ && !invisibleTopNamespaces().contains(std::const_pointer_cast<AbstractMetaClass>(ownerClass))) {
+ if (overloadData.hasStaticFunction())
+ result.append(QByteArrayLiteral("METH_STATIC"));
+ if (overloadData.hasClassMethod())
+ result.append(QByteArrayLiteral("METH_CLASS"));
+ }
+ return result;
+}
+
+QList<PyMethodDefEntry>
+ CppGenerator::methodDefinitionEntries(const OverloadData &overloadData) const
+{
+
+ const QStringList names = overloadData.referenceFunction()->definitionNames();
+ const QString funcName = cpythonFunctionName(overloadData.referenceFunction());
+ const QByteArrayList parameters = methodDefinitionParameters(overloadData);
+
+ QList<PyMethodDefEntry> result;
+ result.reserve(names.size());
+ for (const auto &name : names)
+ result.append({name, funcName, parameters, {}});
+ 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
+{
+ QString result;
+ QTextStream s(&result);
+
+ auto metaType = arg.type();
+ if (auto viewOn = metaType.viewOn())
+ metaType = *viewOn;
+ s << arg.name() << ':';
+
+ 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()) {
+ // 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();
+ if (size > 1)
+ s << "typing.Union[";
+ for (qsizetype i = 0; i < size; ++i) {
+ if (i > 0)
+ s << ", ";
+ s << signatures.at(i);
+ }
+ if (size > 1)
+ s << ']';
+
+ return result;
+}
+
+void CppGenerator::writeSignatureInfo(TextStream &s, const OverloadData &overloadData) const
+{
+ const auto rfunc = overloadData.referenceFunction();
+ QString funcName = fullPythonFunctionName(rfunc, false);
+
+ int idx = overloadData.overloads().length() - 1;
+ bool multiple = idx > 0;
+
+ for (const auto &f : overloadData.overloads()) {
+ QStringList args;
+ // PYSIDE-1328: `self`-ness cannot be computed in Python because there are mixed cases.
+ // Toplevel functions like `PySide6.QtCore.QEnum` are always self-less.
+ if (!(f->isStatic()) && f->ownerClass())
+ args << PYTHON_SELF_VAR;
+ const auto &arguments = f->arguments();
+ for (qsizetype i = 0, size = arguments.size(); i < size; ++i) {
+ const auto n = i + 1;
+ const auto &arg = arguments.at(i);
+ if (!f->argumentRemoved(n)) {
+ QString t = f->pyiTypeReplaced(n);
+ if (t.isEmpty()) {
+ t = signatureParameter(arg);
+ } else {
+ t.prepend(u':');
+ t.prepend(arg.name());
+ }
+ QString defaultValue = arg.defaultValueExpression();
+ if (!defaultValue.isEmpty())
+ t += u'=' + defaultValue.replace(u"::"_s, u"."_s);
+ args.append(t);
+ }
+ }
+
+ // mark the multiple signatures as such, to make it easier to generate different code
+ if (multiple)
+ s << idx-- << ':';
+ s << funcName << '(' << args.join(u',') << ')';
+
+ QString returnType = f->pyiTypeReplaced(0); // pyi or modified type
+ if (returnType.isEmpty() && !f->isVoid())
+ returnType = pythonSignature(f->type());
+ if (!returnType.isEmpty())
+ s << "->" << returnType;
+
+ s << '\n';
+ }
+}
+
+void CppGenerator::writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums)
+{
+ if (enums.isEmpty())
+ return;
+ bool preambleWritten = false;
+ bool etypeUsed = false;
+
+ for (const AbstractMetaEnum &cppEnum : std::as_const(enums)) {
+ if (cppEnum.isPrivate())
+ continue;
+ if (!preambleWritten) {
+ s << "// Initialization of enums.\n"
+ << "Shiboken::AutoDecRef tpDict{};\n"
+ << "PyTypeObject *EType{};\n\n";
+ preambleWritten = true;
+ }
+ ConfigurableScope configScope(s, cppEnum.typeEntry());
+ etypeUsed |= writeEnumInitialization(s, cppEnum);
+ }
+ if (preambleWritten && !etypeUsed)
+ s << sbkUnusedVariableCast("EType");
+}
+
+static qsizetype maxLineLength(const QStringList &list)
+{
+ qsizetype result = 0;
+ for (const auto &s : list) {
+ if (auto len = s.size(); len > result)
+ result = len;
+ }
+ return result;
+}
+
+bool CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum &cppEnum)
+{
+ const auto enclosingClass = cppEnum.targetLangEnclosingClass();
+ const bool hasUpperEnclosingClass = enclosingClass
+ && enclosingClass->targetLangEnclosingClass();
+ EnumTypeEntryCPtr enumTypeEntry = cppEnum.typeEntry();
+ QString enclosingObjectVariable;
+ if (enclosingClass)
+ enclosingObjectVariable = cpythonTypeName(enclosingClass);
+ else if (hasUpperEnclosingClass)
+ enclosingObjectVariable = u"enclosingClass"_s;
+ else
+ enclosingObjectVariable = u"module"_s;
+
+ s << "// Initialization of ";
+ s << (cppEnum.isAnonymous() ? "anonymous enum identified by enum value" : "enum");
+ s << " '" << cppEnum.name() << "'.\n";
+
+ const QString userType = cppEnum.typeEntry()->cppType();
+ const bool isSigned = cppEnum.isSigned() && !userType.contains(u"unsigned"_s);
+ const bool isAccessible = !avoidProtectedHack() || !cppEnum.isProtected();
+ const auto enumValues = cppEnum.nonRejectedValues();
+
+ const QString prefix = cppEnum.name();
+
+ const QString intType = userType.isEmpty() ? cppEnum.underlyingType() : userType;
+
+ // Create a list of values
+ const QString initializerValues = prefix + u"_InitializerValues"_s;
+ const QString initializerName = prefix + u"_Initializer"_s;
+
+ // Build maybe array of enum names.
+ if (cppEnum.enumKind() != AnonymousEnum) {
+ s << "const char *" << initializerName << "[] = {\n" << indent;
+ for (const auto &enumValue : enumValues) {
+ QString name = mangleName(enumValue.name());
+ s << '\"' << name << "\",\n";
+ }
+ s << "nullptr};\n" << outdent;
+ }
+
+ int targetHexLen = 0;
+ QString usedIntType = userType;
+ if (usedIntType.isEmpty()) {
+ const int usedBits = cppEnum.usedBits();
+ targetHexLen = usedBits / 4;
+ usedIntType = AbstractMetaEnum::intTypeForSize(usedBits, cppEnum.isSigned());
+ }
+
+ if (usedIntType != intType)
+ s << "// \"" << usedIntType << "\" used instead of \"" << intType << "\"\n";
+
+ // Calculating formatting columns
+ QString enumValuePrefix;
+ if (isAccessible) {
+ if (cppEnum.enclosingClass())
+ enumValuePrefix += cppEnum.enclosingClass()->qualifiedCppName() + u"::"_s;
+ if (!cppEnum.isAnonymous())
+ enumValuePrefix += cppEnum.name() + u"::"_s;
+ }
+
+ // Build array of enum values
+ if (enumValues.isEmpty()) {
+ s << "const " << usedIntType << " *" << initializerValues << "{};\n";
+ } else {
+ QStringList values;
+ values.reserve(enumValues.size());
+ s << "constexpr " << usedIntType << ' ' << initializerValues << "[] = {\n" << indent;
+ for (qsizetype idx = 0, last = enumValues.size() - 1; idx <= last; ++idx) {
+ const auto &enumValue = enumValues.at(idx);
+ QString line = usedIntType + u'(' + (isAccessible
+ ? enumValuePrefix + enumValue.name()
+ : enumValue.value().toString()) + u')';
+ if (idx != last)
+ line += u',';
+ values.append(line);
+ }
+
+ const auto len = maxLineLength(values) + 1;
+ for (qsizetype idx = 0, size = enumValues.size(); idx < size; ++idx) {
+ const auto &enumValue = enumValues.at(idx).value();
+ const char *numberSpace = enumValue.isNegative() ? " " : " ";
+ s << values.at(idx) << Pad(' ', len - values.at(idx).size())
+ << "//" << numberSpace << enumValue.toHex(targetHexLen)
+ << numberSpace << enumValue.toString() << '\n';
+ }
+ s << "};\n" << outdent;
+ }
+
+ // Build initialization of anonymous enums
+ if (cppEnum.enumKind() == AnonymousEnum) {
+ int idx = 0;
+ for (const auto &enumValue : enumValues) {
+ const QString mangledName = mangleName(enumValue.name());
+ const QString pyValue = initializerValues + u'[' + QString::number(idx++) + u']';
+ if (enclosingClass || hasUpperEnclosingClass) {
+ s << "tpDict.reset(PepType_GetDict(reinterpret_cast<PyTypeObject *>("
+ << enclosingObjectVariable << ")));\n"
+ << "PyDict_SetItemString(tpDict.object(), \"" << mangledName << "\",\n"
+ << indent << (isSigned ? "PyLong_FromLongLong" : "PyLong_FromUnsignedLongLong")
+ << "(" << pyValue << "));\n" << outdent;
+ } else {
+ s << "PyModule_AddObject(module, \"" << mangledName << "\",\n" << indent
+ << (isSigned ? "PyLong_FromLongLong" : "PyLong_FromUnsignedLongLong") << "("
+ << pyValue << "));\n" << outdent;
+ }
+ }
+ }
+
+ bool etypeUsed = false;
+
+ QString enumVarTypeObj = cpythonTypeNameExtSet(enumTypeEntry);
+ if (!cppEnum.isAnonymous()) {
+ int packageLevel = packageName().count(u'.') + 1;
+ s << "EType = Shiboken::Enum::"
+ << "createPythonEnum"
+ << '(' << enclosingObjectVariable << ",\n" << indent
+ << '"' << packageLevel << ':' << getClassTargetFullName(cppEnum) << "\",\n"
+ << initializerName << ", " << initializerValues << ");\n" << outdent
+ << enumVarTypeObj << " = EType;\n";
+ etypeUsed = true;
+ }
+
+ if (cppEnum.typeEntry()->flags()) {
+ s << "// PYSIDE-1735: Mapping the flags class to the same enum class.\n"
+ << cpythonTypeNameExtSet(cppEnum.typeEntry()->flags()) << " =\n"
+ << indent << "EType;\n" << outdent;
+ }
+ writeEnumConverterInitialization(s, cppEnum);
+
+ s << "// End of '" << cppEnum.name() << "' enum";
+ if (cppEnum.typeEntry()->flags())
+ s << "/flags";
+ s << ".\n\n";
+
+ return etypeUsed;
+}
+
+void CppGenerator::writeSignalInitialization(TextStream &s, const AbstractMetaClassCPtr &metaClass)
+{
+ // Try to check something and print some warnings
+ const auto &signalFuncs = metaClass->cppSignalFunctions();
+ for (const auto &cppSignal : signalFuncs) {
+ if (cppSignal->declaringClass() != metaClass)
+ continue;
+ const AbstractMetaArgumentList &arguments = cppSignal->arguments();
+ for (const AbstractMetaArgument &arg : arguments) {
+ AbstractMetaType metaType = arg.type();
+ const QByteArray origType =
+ QMetaObject::normalizedType(qPrintable(metaType.originalTypeDescription()));
+ const QByteArray cppSig =
+ QMetaObject::normalizedType(qPrintable(metaType.cppSignature()));
+ if ((origType != cppSig) && (!metaType.isFlags())) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Typedef used on signal " << metaClass->qualifiedCppName() << "::"
+ << cppSignal->signature();
+ }
+ }
+ }
+
+ s << "PySide::Signal::registerSignals(pyType, &" << m_gsp
+ << metaClass->qualifiedCppName() << "::staticMetaObject);\n";
+}
+
+QString CppGenerator::getSimpleClassInitFunctionName(const AbstractMetaClassCPtr &metaClass)
+{
+ QString initFunctionName;
+ // Disambiguate namespaces per module to allow for extending them.
+ if (metaClass->isNamespace())
+ initFunctionName += moduleName();
+ initFunctionName += metaClass->qualifiedCppName();
+ initFunctionName.replace(u"::"_s, u"_"_s);
+ return initFunctionName;
+}
+
+QString
+ CppGenerator::getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClassCPtr &metaClass)
+{
+ return u"init_"_s + getSimpleClassInitFunctionName(metaClass)
+ + u"StaticFields"_s;
+}
+
+QString CppGenerator::getInitFunctionName(const GeneratorContext &context)
+{
+ return getSimpleClassInitFunctionName(context.metaClass());
+}
+
+void CppGenerator::writeSignatureStrings(TextStream &s,
+ const QString &signatures,
+ const QString &arrayName,
+ const char *comment)
+{
+ s << "// The signatures string for the " << comment << ".\n"
+ << "// Multiple signatures have their index \"n:\" in front.\n"
+ << "static const char *" << arrayName << "_SignatureStrings[] = {\n" << indent;
+ const auto lines = QStringView{signatures}.split(u'\n', Qt::SkipEmptyParts);
+ for (auto line : lines) {
+ // must anything be escaped?
+ if (line.contains(u'"') || line.contains(u'\\'))
+ s << "R\"CPP(" << line << ")CPP\",\n";
+ else
+ s << '"' << line << "\",\n";
+ }
+ s << NULL_PTR << "}; // Sentinel\n" << outdent << '\n';
+}
+
+// Return the class name for which to invoke the destructor
+QString CppGenerator::destructorClassName(const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext)
+{
+ if (metaClass->isNamespace() || metaClass->hasPrivateDestructor())
+ return {};
+ if (classContext.forSmartPointer())
+ return classContext.effectiveClassName();
+ const bool isValue = metaClass->typeEntry()->isValue();
+ const bool hasProtectedDestructor = metaClass->hasProtectedDestructor();
+ if (((avoidProtectedHack() && hasProtectedDestructor) || isValue)
+ && classContext.useWrapper()) {
+ return classContext.wrapperName();
+ }
+ if (avoidProtectedHack() && hasProtectedDestructor)
+ return {}; // Cannot call (happens with "disable-wrapper").
+ return metaClass->qualifiedCppName();
+}
+
+// Return the base type entries for introduceWrapperType()
+static ComplexTypeEntryCList pyBaseTypeEntries(const AbstractMetaClassCPtr &metaClass)
+{
+ ComplexTypeEntryCList result;
+ if (metaClass->isNamespace()) {
+ if (auto extended = metaClass->extendedNamespace())
+ result.append(extended->typeEntry());
+ return result;
+ }
+
+ const auto &baseClasses = metaClass->typeSystemBaseClasses();
+ for (auto base : baseClasses) {
+ for (; base != nullptr; base = base->baseClass()) { // Find a type that is not disabled.
+ const auto ct = base->typeEntry()->codeGeneration();
+ if (ct == TypeEntry::GenerateCode || ct == TypeEntry::GenerateForSubclass)
+ break;
+ }
+ result.append(base->typeEntry());
+ }
+ return result;
+}
+
+// Return the base type strings for introduceWrapperType()
+QStringList CppGenerator::pyBaseTypes(const AbstractMetaClassCPtr &metaClass)
+{
+ const auto &baseEntries = pyBaseTypeEntries(metaClass);
+ QStringList result;
+ for (const auto &baseEntry : baseEntries)
+ result.append("reinterpret_cast<PyObject *>("_L1 + cpythonTypeNameExt(baseEntry) + u')');
+ if (result.isEmpty()) // no base classes -> SbkObjectType.
+ result.append(sbkObjectTypeF);
+ return result;
+}
+
+void CppGenerator::writeInitInheritance(TextStream &s) const
+{
+ s << "static void " << initInheritanceFunction << "()\n{\n" << indent
+ << "auto &bm = Shiboken::BindingManager::instance();\n"
+ << sbkUnusedVariableCast("bm");
+ for (const auto &cls : api().classes()){
+ auto te = cls->typeEntry();
+ if (shouldGenerate(te)) {
+ const auto &baseEntries = pyBaseTypeEntries(cls);
+ if (!baseEntries.isEmpty()) {
+ const QString childTypeInitStruct = typeInitStruct(cls->typeEntry());
+ for (const auto &baseEntry : baseEntries) {
+ s << "bm.addClassInheritance(&" << typeInitStruct(baseEntry) << ",\n"
+ << Pad(' ', 23) << '&' << childTypeInitStruct << ");\n";
+ }
+ }
+ }
+ }
+ s << outdent << "}\n\n";
+}
+
+void CppGenerator::writeClassRegister(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext,
+ const QString &signatures) const
+{
+ ComplexTypeEntryCPtr classTypeEntry = metaClass->typeEntry();
+
+ AbstractMetaClassCPtr enc = metaClass->targetLangEnclosingClass();
+ QString enclosingObjectVariable = enc ? u"enclosingClass"_s : u"module"_s;
+
+ QString pyTypeName = cpythonTypeName(metaClass);
+ QString initFunctionName = getInitFunctionName(classContext);
+
+ // PYSIDE-510: Create a signatures string for the introspection feature.
+ writeSignatureStrings(s, signatures, initFunctionName, "functions");
+ s << "PyTypeObject *init_" << initFunctionName
+ << "(PyObject *" << enclosingObjectVariable << ")\n{\n" << indent;
+
+ const QString globalTypeVarExpr = !classContext.forSmartPointer()
+ ? cpythonTypeNameExtSet(classTypeEntry)
+ : cpythonTypeNameExtSet(classContext.preciseType());
+ s << "if (" << globalTypeVarExpr << " != nullptr)\n" << indent
+ << "return " << globalTypeVarExpr << ";\n\n" << outdent;
+
+ // Multiple inheritance
+ QString pyTypeBasesVariable = chopType(pyTypeName) + u"_Type_bases"_s;
+ const QStringList pyBases = pyBaseTypes(metaClass);
+ s << "Shiboken::AutoDecRef " << pyTypeBasesVariable << "(PyTuple_Pack("
+ << pyBases.size() << ",\n" << indent;
+ for (qsizetype i = 0, size = pyBases.size(); i < size; ++i) {
+ if (i)
+ s << ",\n";
+ s << pyBases.at(i);
+ }
+ s << "));\n\n" << outdent;
+
+ // Create type and insert it in the module or enclosing class.
+ const QString typePtr = u"_"_s + chopType(pyTypeName)
+ + u"_Type"_s;
+
+ s << typePtr << " = Shiboken::ObjectType::introduceWrapperType(\n" << indent;
+ // 1:enclosingObject
+ s << enclosingObjectVariable << ",\n";
+
+ // 2:typeName
+ s << "\"" << metaClass->name() << "\",\n";
+
+ // 3:originalName
+ s << "\"";
+ if (!classContext.forSmartPointer()) {
+ s << metaClass->qualifiedCppName();
+ if (classTypeEntry->isObject())
+ s << '*';
+ } else {
+ s << classContext.preciseType().cppSignature();
+ }
+
+ s << "\",\n";
+ // 4:typeSpec
+ s << '&' << chopType(pyTypeName) << "_spec,\n";
+
+ // 5:cppObjDtor
+ QString dtorClassName = destructorClassName(metaClass, classContext);
+ if (dtorClassName.isEmpty())
+ s << "nullptr,\n";
+ else
+ s << "&Shiboken::callCppDestructor< " << globalScopePrefix(classContext)
+ << dtorClassName << " >,\n";
+
+ // 7:baseTypes
+ s << pyTypeBasesVariable << ".object()," << '\n';
+
+ // 8:wrapperflags
+ QByteArrayList wrapperFlags;
+ if (enc)
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::InnerClass"));
+ if (metaClass->deleteInMainThread())
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::DeleteInMainThread"));
+ if (classTypeEntry->isValue())
+ wrapperFlags.append("Shiboken::ObjectType::WrapperFlags::Value"_ba);
+ if (wrapperFlags.isEmpty())
+ s << '0';
+ else
+ s << wrapperFlags.join(" | ");
+
+ s << outdent << ");\nauto *pyType = " << pyTypeName << "; // references "
+ << typePtr << "\n"
+ << "InitSignatureStrings(pyType, " << initFunctionName << "_SignatureStrings);\n";
+
+ if (usePySideExtensions() && !classContext.forSmartPointer())
+ s << "SbkObjectType_SetPropertyStrings(pyType, "
+ << chopType(pyTypeName) << "_PropertyStrings);\n";
+ s << globalTypeVarExpr << " = pyType;\n\n";
+
+ // Register conversions for the type.
+ 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(),
+ TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode,
+ classContext);
+ s << '\n';
+ }
+
+ // Fill multiple inheritance data, if needed.
+ const auto miClass = getMultipleInheritingClass(metaClass);
+ if (miClass) {
+ s << "MultipleInheritanceInitFunction func = ";
+ if (miClass == metaClass) {
+ s << multipleInheritanceInitializerFunctionName(miClass) << ";\n";
+ } else {
+ s << "Shiboken::ObjectType::getMultipleInheritanceFunction("
+ << cpythonTypeNameExt(miClass->typeEntry()) << ");\n";
+ }
+ s << "Shiboken::ObjectType::setMultipleInheritanceFunction("
+ << cpythonTypeName(metaClass) << ", func);\n"
+ << "Shiboken::ObjectType::setCastFunction(" << cpythonTypeName(metaClass)
+ << ", &" << cpythonSpecialCastFunctionName(metaClass) << ");\n";
+ }
+
+ // Set typediscovery struct or fill the struct of another one
+ if (needsTypeDiscoveryFunction(metaClass)) {
+ s << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(\n" << indent
+ << cpythonTypeName(metaClass)
+ << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);" << outdent << "\n\n";
+ }
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ metaClass->getEnumsFromInvisibleNamespacesToBeGenerated(&classEnums);
+
+ if (!classContext.forSmartPointer() && !classEnums.isEmpty())
+ s << "// Pass the ..._EnumFlagInfo to the class.\n"
+ << "SbkObjectType_SetEnumFlagInfo(pyType, " << chopType(pyTypeName)
+ << "_EnumFlagInfo);\n\n";
+ writeEnumsInitialization(s, classEnums);
+
+ if (metaClass->hasSignals())
+ writeSignalInitialization(s, metaClass);
+
+ // class inject-code target/end
+ if (!classTypeEntry->codeSnips().isEmpty()) {
+ s << '\n';
+ writeClassCodeSnips(s, classTypeEntry->codeSnips(),
+ TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode,
+ classContext);
+ }
+
+ if (usePySideExtensions()) {
+ if (avoidProtectedHack() && classContext.useWrapper())
+ s << classContext.wrapperName() << "::pysideInitQtMetaTypes();\n";
+ else
+ writeInitQtMetaTypeFunctionBody(s, classContext);
+ }
+
+ if (usePySideExtensions() && isQObject(metaClass)) {
+ s << "Shiboken::ObjectType::setSubTypeInitHook(pyType, &PySide::initQObjectSubType);\n"
+ << "PySide::initDynamicMetaObject(pyType, &" << m_gsp
+ << metaClass->qualifiedCppName() << "::staticMetaObject, sizeof("
+ << (shouldGenerateCppWrapper(metaClass)
+ ? wrapperName(metaClass) : getFullTypeName(metaClass))
+ << "));\n";
+ }
+
+ s << "\nreturn pyType;\n" << outdent << "}\n";
+}
+
+void CppGenerator::writeStaticFieldInitialization(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ // cpythonTypeName == "Sbk_QRhiShaderResourceBinding_Data_TypeF"
+ QString name = cpythonTypeName(metaClass);
+ const auto parts = QStringView{name}.split(u'_', Qt::SkipEmptyParts);
+ if (parts.size() < 4) {
+ s << "\nPyTypeObject *" << getSimpleClassStaticFieldsInitFunctionName(metaClass)
+ << "(PyObject *module)\n{\n" << indent
+ << "auto *obType = PyObject_GetAttrString(module, \"" << metaClass->name() << "\");\n"
+ << "auto *type = reinterpret_cast<PyTypeObject *>(obType);\n"
+ << "Shiboken::AutoDecRef dict(PepType_GetDict(type));\n";
+ } else {
+ s << "\nPyTypeObject *" << getSimpleClassStaticFieldsInitFunctionName(metaClass)
+ << "(PyObject *module)\n{\n" << indent
+ << "auto *obContainerType = PyObject_GetAttrString(module, \""
+ << parts.at(1) << "\");\n"
+ << "auto *obType = PyObject_GetAttrString(obContainerType, \""
+ << parts.at(2) << "\");\n"
+ << "auto *type = reinterpret_cast<PyTypeObject *>(obType);\n"
+ << "Shiboken::AutoDecRef dict(PepType_GetDict(type));\n";
+ }
+ for (const AbstractMetaField &field : metaClass->fields()) {
+ if (field.isStatic()) {
+ s << "PyDict_SetItemString(dict, \"" << field.name()
+ << "\",\n ";
+ writeToPythonConversion(s, field.type(), metaClass, field.qualifiedCppName());
+ s << ");\n";
+ }
+ }
+ s << "return type;\n" << outdent << "}\n";
+}
+
+enum class QtRegisterMetaType
+{
+ None, Pointer, Value
+};
+
+static bool hasQtMetaTypeRegistrationSpec(const AbstractMetaClassCPtr &c)
+{
+ return c->typeEntry()->qtMetaTypeRegistration() !=
+ TypeSystem::QtMetaTypeRegistration::Unspecified;
+}
+
+// Returns if and how to register the Qt meta type. By default, "pointer" for
+// non-QObject object types and "value" for non-abstract, default-constructible
+// value types.
+QtRegisterMetaType qtMetaTypeRegistration(const AbstractMetaClassCPtr &c)
+{
+ if (c->isNamespace())
+ return QtRegisterMetaType::None;
+
+ // Specified in type system?
+ const bool isObject = c->isObjectType();
+ switch (c->typeEntry()->qtMetaTypeRegistration()) {
+ case TypeSystem::QtMetaTypeRegistration::Disabled:
+ return QtRegisterMetaType::None;
+ case TypeSystem::QtMetaTypeRegistration::Enabled:
+ case TypeSystem::QtMetaTypeRegistration::BaseEnabled:
+ return isObject ? QtRegisterMetaType::Pointer : QtRegisterMetaType::Value;
+ case TypeSystem::QtMetaTypeRegistration::Unspecified:
+ break;
+ }
+
+ // Is there a "base" specification in some base class, meaning only the
+ // base class is to be registered?
+ if (auto base = recurseClassHierarchy(c, hasQtMetaTypeRegistrationSpec)) {
+ const auto baseSpec = base->typeEntry()->qtMetaTypeRegistration();
+ if (baseSpec == TypeSystem::QtMetaTypeRegistration::BaseEnabled)
+ return QtRegisterMetaType::None;
+ }
+
+ // Default.
+ if (isObject)
+ return isQObject(c) ? QtRegisterMetaType::None : QtRegisterMetaType::Pointer;
+
+ return !c->isAbstract() && c->isDefaultConstructible()
+ ? QtRegisterMetaType::Value : QtRegisterMetaType::None;
+}
+
+void CppGenerator::writeInitQtMetaTypeFunctionBody(TextStream &s, const GeneratorContext &context)
+{
+ const auto metaClass = context.metaClass();
+ // Gets all class name variants used on different possible scopes
+ QStringList nameVariants;
+ if (!context.forSmartPointer())
+ nameVariants << metaClass->name();
+ else
+ nameVariants << context.preciseType().cppSignature();
+
+ AbstractMetaClassCPtr enclosingClass = metaClass->enclosingClass();
+ while (enclosingClass) {
+ if (enclosingClass->typeEntry()->generateCode())
+ nameVariants << (enclosingClass->name() + u"::"_s + nameVariants.constLast());
+ enclosingClass = enclosingClass->enclosingClass();
+ }
+
+ QString className;
+ if (!context.forSmartPointer())
+ className = metaClass->qualifiedCppName();
+ else
+ className = context.preciseType().cppSignature();
+
+ // Register meta types for signal/slot connections to work
+ // Qt metatypes are registered only on their first use, so we do this now.
+ switch (qtMetaTypeRegistration(metaClass)) {
+ case QtRegisterMetaType::None:
+ break;
+ case QtRegisterMetaType::Pointer:
+ s << "qRegisterMetaType< " << m_gsp << className << " *>();\n";
+ break;
+ case QtRegisterMetaType::Value:
+ for (const QString &name : std::as_const(nameVariants))
+ s << "qRegisterMetaType< " << m_gsp << className << " >(\"" << name << "\");\n";
+ break;
+ }
+
+ for (const AbstractMetaEnum &metaEnum : metaClass->enums()) {
+ if (!metaEnum.isPrivate() && !metaEnum.isAnonymous()) {
+ for (const QString &name : std::as_const(nameVariants)) {
+ s << "qRegisterMetaType< " << m_gsp
+ << metaEnum.typeEntry()->qualifiedCppName() << " >(\""
+ << name << "::" << metaEnum.name() << "\");\n";
+ }
+ }
+ }
+}
+
+void CppGenerator::replacePolymorphicIdPlaceHolders(const AbstractMetaClassCPtr &metaClass,
+ QString *id)
+{
+ if (id->contains("%1"_L1)) {
+ QString replacement = " reinterpret_cast< "_L1 + m_gsp + metaClass->qualifiedCppName()
+ + " *>(cptr)"_L1;
+ id->replace("%1"_L1, replacement);
+ }
+ if (id->contains("%B"_L1)) {
+ auto baseClass = metaClass;
+ while (!baseClass->typeEntry()->isPolymorphicBase() && baseClass->baseClass())
+ baseClass = baseClass->baseClass();
+ QString replacement = " reinterpret_cast< "_L1 + m_gsp + baseClass->qualifiedCppName()
+ + " *>(cptr)"_L1;
+ id->replace("%B"_L1, replacement);
+ }
+}
+
+void CppGenerator::writeTypeDiscoveryFunction(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue();
+
+ s << "static void *" << cpythonBaseName(metaClass)
+ << "_typeDiscovery(void *cptr, PyTypeObject *instanceType)\n{\n" << indent
+ << sbkUnusedVariableCast("cptr")
+ << sbkUnusedVariableCast("instanceType");
+
+ if (!polymorphicExpr.isEmpty()) {
+ replacePolymorphicIdPlaceHolders(metaClass, &polymorphicExpr);
+ s << "if (" << polymorphicExpr << ")\n" << indent
+ << "return cptr;\n" << outdent;
+ } else if (metaClass->isPolymorphic()) {
+ const auto &ancestors = metaClass->allTypeSystemAncestors();
+ for (const auto &ancestor : ancestors) {
+ if (ancestor->baseClass() && !ancestor->typeEntry()->isPolymorphicBase())
+ continue;
+ if (ancestor->isPolymorphic()) {
+ s << "if (instanceType == Shiboken::SbkType< " << m_gsp
+ << ancestor->qualifiedCppName() << " >())\n" << indent
+ << "return dynamic_cast< " << getFullTypeName(metaClass)
+ << " *>(reinterpret_cast< "<< getFullTypeName(ancestor)
+ << " *>(cptr));\n" << outdent;
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << metaClass->qualifiedCppName() << " inherits from a non polymorphic type ("
+ << ancestor->qualifiedCppName() << "), type discovery based on RTTI is "
+ "impossible, write a polymorphic-id-expression for this type.";
+ }
+
+ }
+ }
+ s << "return {};\n" << outdent << "}\n\n";
+}
+
+void CppGenerator::writeSetattroDefinition(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ s << "static int " << ShibokenGenerator::cpythonSetattroFunctionName(metaClass)
+ << "(PyObject *self, PyObject *name, PyObject *value)\n{\n" << indent;
+ if (wrapperDiagnostics()) {
+ s << R"(std::cerr << __FUNCTION__ << ' ' << Shiboken::debugPyObject(name)
+ << ' ' << Shiboken::debugPyObject(value) << '\n';)" << '\n';
+ }
+}
+
+void CppGenerator::writeSetattroDefaultReturn(TextStream &s)
+{
+ s << "return PyObject_GenericSetAttr(self, name, value);\n"
+ << outdent << "}\n\n";
+}
+
+void CppGenerator::writeSetattroFunction(TextStream &s, AttroCheck attroCheck,
+ const GeneratorContext &context) const
+{
+ Q_ASSERT(!context.forSmartPointer());
+ const auto metaClass = context.metaClass();
+ writeSetattroDefinition(s, metaClass);
+
+ // PYSIDE-1019: Switch tp_dict before doing tp_setattro.
+ if (usePySideExtensions())
+ s << "PySide::Feature::Select(self);\n";
+
+ // PYSIDE-803: Detect duck-punching; clear cache if a method is set.
+ if (attroCheck.testFlag(AttroCheckFlag::SetattroMethodOverride)
+ && context.useWrapper()) {
+ s << "if (value != nullptr && PyCallable_Check(value) != 0) {\n" << indent
+ << "auto plain_inst = " << cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR) << ";\n"
+ << "auto *inst = dynamic_cast<" << context.wrapperName() << " *>(plain_inst);\n"
+ << "if (inst != nullptr)\n" << indent
+ << "inst->resetPyMethodCache();\n" << outdent << outdent
+ << "}\n";
+ }
+ if (attroCheck.testFlag(AttroCheckFlag::SetattroQObject)) {
+ s << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject *>(PySide::Property::getObject(self, name)));\n"
+ << "if (!pp.isNull())\n" << indent
+ << "return PySide::Property::setValue(reinterpret_cast<PySideProperty *>(pp.object()), self, value);\n"
+ << outdent;
+ }
+
+ if (attroCheck.testFlag(AttroCheckFlag::SetattroUser)) {
+ auto func = AbstractMetaClass::queryFirstFunction(metaClass->functions(),
+ FunctionQueryOption::SetAttroFunction);
+ Q_ASSERT(func);
+ s << "{\n" << indent
+ << "auto " << CPP_SELF_VAR << " = "
+ << cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR) << ";\n";
+ writeClassCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, context);
+ s << outdent << "}\n";
+ }
+
+ writeSetattroDefaultReturn(s);
+}
+
+void CppGenerator::writeGetattroDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass)
+{
+ s << "static PyObject *" << cpythonGetattroFunctionName(metaClass)
+ << "(PyObject *self, PyObject *name)\n{\n" << indent;
+}
+
+QString CppGenerator::qObjectGetAttroFunction() const
+{
+ static QString result;
+ if (result.isEmpty()) {
+ auto qobjectClass = AbstractMetaClass::findClass(api().classes(), qObjectT);
+ Q_ASSERT(qobjectClass);
+ result = u"PySide::getHiddenDataFromQObject("_s
+ + cpythonWrapperCPtr(qobjectClass, PYTHON_SELF_VAR)
+ + u", self, name)"_s;
+ }
+ return result;
+}
+
+void CppGenerator::writeGetattroFunction(TextStream &s, AttroCheck attroCheck,
+ const GeneratorContext &context) const
+{
+ Q_ASSERT(!context.forSmartPointer());
+ const auto metaClass = context.metaClass();
+ writeGetattroDefinition(s, metaClass);
+
+ // PYSIDE-1019: Switch tp_dict before doing tp_getattro.
+ if (usePySideExtensions())
+ s << "PySide::Feature::Select(self);\n";
+
+ const QString getattrFunc = usePySideExtensions() && isQObject(metaClass)
+ ? qObjectGetAttroFunction() : u"PyObject_GenericGetAttr(self, name)"_s;
+
+ if (attroCheck.testFlag(AttroCheckFlag::GetattroOverloads)) {
+ s << "// Search the method in the instance dict\n"
+ << "auto *ob_dict = SbkObject_GetDict_NoRef(self);\n";
+ s << "if (auto *meth = PyDict_GetItem(ob_dict, name)) {\n" << indent
+ << "Py_INCREF(meth);\nreturn meth;\n" << outdent << "}\n"
+ << "// Search the method in the type dict\n"
+ << "if (Shiboken::Object::isUserType(self)) {\n" << indent;
+ // PYSIDE-772: Perform optimized name mangling.
+ s << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(self, name));\n"
+ << "Shiboken::AutoDecRef tpDict(PepType_GetDict(Py_TYPE(self)));\n"
+ << "if (auto *meth = PyDict_GetItem(tpDict.object(), tmp)) {\n" << indent;
+ // PYSIDE-1523: PyFunction_Check is not accepting compiled functions.
+ s << "if (std::strcmp(Py_TYPE(meth)->tp_name, \"compiled_function\") == 0) {\n" << indent
+ << "auto descrGetFunc = "
+ << pyTypeGetSlot("descrgetfunc", "Py_TYPE(meth)", "Py_tp_descr_get") << ";\n"
+ << "return descrGetFunc(meth, self, nullptr);\n" << outdent
+ << "}\nreturn PyFunction_Check(meth) ? PyMethod_New(meth, self)\n"
+ << " : " << getattrFunc << ";\n" << outdent
+ << "}\n" << outdent << "}\n";
+
+ const auto &funcs = getMethodsWithBothStaticAndNonStaticMethods(metaClass);
+ for (const auto &func : funcs) {
+ QString defName = cpythonMethodDefinitionName(func);
+ s << "static PyMethodDef non_static_" << defName << " = {\n" << indent
+ << defName << ".ml_name,\n"
+ << defName << ".ml_meth,\n"
+ << defName << ".ml_flags & (~METH_STATIC),\n"
+ << defName << ".ml_doc,\n" << outdent
+ << "};\n"
+ << "if (Shiboken::String::compare(name, \""
+ << func->definitionNames().constFirst() << "\") == 0)\n" << indent
+ << "return PyCFunction_NewEx(&non_static_" << defName << ", self, 0);\n"
+ << outdent;
+ }
+ }
+
+ if (attroCheck.testFlag(AttroCheckFlag::GetattroUser)) {
+ auto func = AbstractMetaClass::queryFirstFunction(metaClass->functions(),
+ FunctionQueryOption::GetAttroFunction);
+ Q_ASSERT(func);
+ s << "{\n" << indent
+ << "auto " << CPP_SELF_VAR << " = "
+ << cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR) << ";\n";
+ writeClassCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, context);
+ s << outdent << "}\n";
+ }
+
+ s << "return " << getattrFunc << ";\n" << outdent << "}\n\n";
+}
+
+void CppGenerator::writeNbBoolExpression(TextStream &s, const BoolCastFunction &f,
+ bool invert)
+{
+ if (f.function->isOperatorBool()) {
+ if (invert)
+ s << '!';
+ s << '*' << CPP_SELF_VAR;
+ return;
+ }
+ if (invert != f.invert)
+ s << '!';
+ s << CPP_SELF_VAR << "->" << f.function->name() << "()";
+}
+
+void CppGenerator::writeNbBoolFunction(const GeneratorContext &context,
+ const BoolCastFunction &f,
+ TextStream &s)
+{
+ s << "static int " << cpythonBaseName(context.metaClass()) << "___nb_bool(PyObject *self)\n"
+ << "{\n" << indent;
+ writeCppSelfDefinition(s, context, ErrorReturn::MinusOne);
+
+ const bool allowThread = f.function->allowThread();
+ if (allowThread)
+ s << "int result;\n" << BEGIN_ALLOW_THREADS << "\nresult = ";
+ else
+ s << "return ";
+
+ writeNbBoolExpression(s, f);
+ s << " ? 1 : 0;\n";
+
+ if (allowThread)
+ s << END_ALLOW_THREADS << "\nreturn result;\n";
+ s << outdent << "}\n\n";
+}
+
+// Write declaration and invocation of the init function for the module init
+// function.
+static void writeInitFuncDecl(TextStream &declStr,
+ const QString &functionName)
+{
+ 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')'
+ : "module"_L1;
+ callStr << functionName << '(' << enclosing << ");\n";
+ } 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, \"" << parts[0] << "\", "
+ << functionName << ", \"" << namePathPrefix << '.' << pythonName << "\");\n";
+ } else {
+ callStr << "Shiboken::Module::AddTypeCreationFunction("
+ << "module, \"" << pythonName << "\", "
+ << functionName << ");\n";
+ }
+}
+
+static void writeSubModuleHandling(TextStream &s, const QString &moduleName,
+ const QString &subModuleOf)
+{
+ s << "{\n" << indent
+ << "Shiboken::AutoDecRef parentModule(Shiboken::Module::import(\""
+ << subModuleOf << "\"));\n"
+ << "if (parentModule.isNull())\n" << indent
+ << "return nullptr;\n" << outdent
+ << "if (PyModule_AddObject(parentModule.object(), \"" << moduleName
+ << "\", module) < 0)\n"
+ << indent << "return nullptr;\n" << outdent << outdent << "}\n";
+}
+
+bool CppGenerator::finishGeneration()
+{
+ //Generate CPython wrapper file
+ StringStream s_classInitDecl(TextStream::Language::Cpp);
+ StringStream s_classPythonDefines(TextStream::Language::Cpp);
+
+ std::set<Include> includes;
+ StringStream s_globalFunctionImpl(TextStream::Language::Cpp);
+ StringStream s_globalFunctionDef(TextStream::Language::Cpp);
+ StringStream signatureStream(TextStream::Language::Cpp);
+
+ const auto functionGroups = getGlobalFunctionGroups();
+ for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ const AbstractMetaFunctionCList &overloads = it.value();
+ for (const auto &func : overloads) {
+ if (auto te = func->typeEntry())
+ includes.insert(te->include());
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ // Dummy context to satisfy the API.
+ GeneratorContext classContext;
+ OverloadData overloadData(overloads, api());
+
+ writeMethodWrapper(s_globalFunctionImpl, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ s_globalFunctionDef << methodDefinitionEntries(overloadData);
+ }
+
+ AbstractMetaClassCList classesWithStaticFields;
+ for (const auto &cls : api().classes()){
+ auto te = cls->typeEntry();
+ if (shouldGenerate(te)) {
+ const bool hasConfigCondition = te->hasConfigCondition();
+ if (hasConfigCondition) {
+ s_classInitDecl << te->configCondition() << '\n';
+ s_classPythonDefines << te->configCondition() << '\n';
+ }
+ 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";
+ classesWithStaticFields.append(cls);
+ }
+ if (hasConfigCondition) {
+ s_classInitDecl << "#endif\n";
+ s_classPythonDefines << "#endif\n";
+ }
+ }
+ }
+
+ // Initialize smart pointer types.
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ GeneratorContext context = contextForSmartPointer(smp.specialized, smp.type);
+ const auto enclosingClass = context.metaClass()->enclosingClass();
+ auto enclosingTypeEntry = targetLangEnclosingEntry(smp.specialized->typeEntry());
+
+ 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());
+ }
+
+ for (auto &instantiatedContainer : api().instantiatedContainers()) {
+ includes.insert(instantiatedContainer.typeEntry()->include());
+ for (const auto &inst : instantiatedContainer.instantiations())
+ includes.insert(inst.typeEntry()->include());
+ }
+
+ const ExtendedConverterData extendedConverters = getExtendedConverters();
+ for (auto it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
+ TypeEntryCPtr te = it.key();
+ includes.insert(te->include());
+ for (const auto &metaClass : it.value())
+ includes.insert(metaClass->typeEntry()->include());
+ }
+
+ const QList<CustomConversionPtr> &typeConversions = getPrimitiveCustomConversions();
+ for (const auto &c : typeConversions) {
+ if (auto te = c->ownerType())
+ includes.insert(te->include());
+ }
+
+ QString moduleFileName(outputDirectory() + u'/' + subDirectoryForPackage(packageName()));
+ moduleFileName += u'/' + moduleName().toLower() + u"_module_wrapper.cpp"_s;
+
+ FileOut file(moduleFileName);
+
+ TextStream &s = file.stream;
+ s.setLanguage(TextStream::Language::Cpp);
+
+ // write license comment
+ s << licenseComment() << R"(
+#include <sbkpython.h>
+#include <shiboken.h>
+#include <algorithm>
+#include <signature.h>
+)";
+
+ if (!api().instantiatedContainers().isEmpty())
+ s << "#include <sbkcontainer.h>\n#include <sbkstaticstrings.h>\n";
+
+ if (usePySideExtensions()) {
+ s << includeQDebug;
+ s << R"(#include <pysidecleanup.h>
+#include <pysideqenum.h>
+#include <feature_select.h>
+#include <pysidestaticstrings.h>
+)";
+ }
+
+ s << "#include \"" << getModuleHeaderFileName() << '"' << "\n\n";
+ for (const Include &include : includes)
+ s << include;
+ s << '\n';
+
+ // Global enums
+ AbstractMetaEnumList globalEnums = api().globalEnums();
+ for (const auto &nsp : invisibleTopNamespaces()) {
+ const auto oldSize = globalEnums.size();
+ nsp->getEnumsToBeGenerated(&globalEnums);
+ if (globalEnums.size() > oldSize)
+ s << nsp->typeEntry()->include();
+ }
+
+ TypeDatabase *typeDb = TypeDatabase::instance();
+ TypeSystemTypeEntryCPtr moduleEntry = typeDb->defaultTypeSystemType();
+ Q_ASSERT(moduleEntry);
+
+ s << '\n';
+ // Extra includes
+ QList<Include> extraIncludes = moduleEntry->extraIncludes();
+ for (const AbstractMetaEnum &cppEnum : std::as_const(globalEnums))
+ extraIncludes.append(cppEnum.typeEntry()->extraIncludes());
+ if (!extraIncludes.isEmpty()) {
+ s << "// Extra includes\n";
+ std::sort(extraIncludes.begin(), extraIncludes.end());
+ for (const Include &inc : std::as_const(extraIncludes))
+ s << inc;
+ s << '\n';
+ }
+
+ // FIXME PYSIDE-7: Remove backwards compatible structure
+ s << "// Current module's type array.\n"
+ << "Shiboken::Module::TypeInitStruct *" << cppApiVariableName() << " = nullptr;\n"
+ << "// Backwards compatible structure with identical indexing.\n"
+ << "PyTypeObject **" << cppApiVariableNameOld() << " = nullptr;\n"
+ << "// Current module's PyObject pointer.\n"
+ << "PyObject *" << pythonModuleObjectName() << " = nullptr;\n"
+ << "// Current module's converter array.\n"
+ << "SbkConverter **" << convertersVariableName() << " = nullptr;\n\n";
+
+ const CodeSnipList snips = moduleEntry->codeSnips();
+
+ // module inject-code native/beginning
+ writeModuleCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode);
+
+ // cleanup staticMetaObject attribute
+ if (usePySideExtensions()) {
+ QString iType = cppApiVariableName() + "[i].type"_L1;
+ QString iName = cppApiVariableName() + "[i].fullName"_L1;
+
+ s << "void cleanTypesAttributes() {\n" << indent
+ << "static PyObject *attrName = Shiboken::PyName::qtStaticMetaObject();\n"
+ << "const int imax = SBK_" << moduleName() << "_IDX_COUNT;\n"
+ << "for (int i = 0; i < imax && " << iName << " != nullptr; ++i) {\n" << indent
+ << "auto *pyType = reinterpret_cast<PyObject *>(" << iType << ");\n"
+ << "if (pyType != nullptr && PyObject_HasAttr(pyType, attrName))\n" << indent
+ << "PyObject_SetAttr(pyType, attrName, Py_None);\n" << outdent
+ << outdent << "}\n" << outdent << "}\n\n";
+ }
+
+ s << "// Global functions "
+ << "------------------------------------------------------------\n"
+ << s_globalFunctionImpl.toString() << '\n'
+ << "static PyMethodDef " << moduleName() << "_methods[] = {\n" << indent
+ << s_globalFunctionDef.toString()
+ << METHOD_DEF_SENTINEL << outdent << "};\n\n"
+ << "// Classes initialization functions "
+ << "------------------------------------------------------------\n"
+ << s_classInitDecl.toString() << '\n';
+
+ if (!globalEnums.isEmpty()) {
+ StringStream convImpl(TextStream::Language::Cpp);
+
+ s << "// Enum definitions "
+ << "------------------------------------------------------------\n";
+ for (const AbstractMetaEnum &cppEnum : std::as_const(globalEnums))
+ writeEnumConverterFunctions(s, cppEnum);
+
+ if (convImpl.size() > 0) {
+ s << "// Enum converters "
+ << "------------------------------------------------------------\n"
+ << "namespace Shiboken\n{\n"
+ << convImpl.toString() << '\n'
+ << "} // namespace Shiboken\n\n";
+ }
+
+ s << '\n';
+ }
+
+ const QStringList &requiredModules = typeDb->requiredTargetImports();
+ if (!requiredModules.isEmpty())
+ s << "// Required modules' type and converter arrays.\n";
+ for (const QString &requiredModule : requiredModules) {
+ s << "Shiboken::Module::TypeInitStruct *" << cppApiVariableName(requiredModule) << ";\n"
+ << "SbkConverter **" << convertersVariableName(requiredModule) << ";\n";
+ }
+
+ s << "\n// Module initialization "
+ << "------------------------------------------------------------\n";
+ if (!extendedConverters.isEmpty()) {
+ s << '\n' << "// Extended Converters.\n\n";
+ for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
+ TypeEntryCPtr externalType = it.key();
+ s << "// Extended implicit conversions for "
+ << externalType->qualifiedTargetLangName() << '.' << '\n';
+ for (const auto &sourceClass : it.value()) {
+ AbstractMetaType sourceType = AbstractMetaType::fromAbstractMetaClass(sourceClass);
+ AbstractMetaType targetType = AbstractMetaType::fromTypeEntry(externalType);
+ writePythonToCppConversionFunctions(s, sourceType, targetType);
+ }
+ }
+ }
+
+ if (!typeConversions.isEmpty()) {
+ s << "\n// Primitive Type converters.\n\n";
+ for (const auto &conversion : typeConversions) {
+ s << "// C++ to Python conversion for primitive type '" << conversion->ownerType()->qualifiedCppName() << "'.\n";
+ writeCppToPythonFunction(s, conversion);
+ writeCustomConverterFunctions(s, conversion);
+ }
+ s << '\n';
+ }
+
+ QHash<AbstractMetaType, OpaqueContainerData> opaqueContainers;
+ const auto &containers = api().instantiatedContainers();
+ QSet<AbstractMetaType> valueConverters;
+ if (!containers.isEmpty()) {
+ s << "// Container Type converters.\n\n";
+ for (const AbstractMetaType &container : containers) {
+ s << "// C++ to Python conversion for container type '"
+ << container.cppSignature() << "'.\n";
+ writeContainerConverterFunctions(s, container);
+ if (container.generateOpaqueContainer()) {
+ auto data = writeOpaqueContainerConverterFunctions(s, container,
+ &valueConverters);
+ opaqueContainers.insert(container, data);
+ }
+ }
+ s << '\n';
+ }
+
+ s << "static struct PyModuleDef moduledef = {\n"
+ << " /* m_base */ PyModuleDef_HEAD_INIT,\n"
+ << " /* m_name */ \"" << moduleName() << "\",\n"
+ << " /* m_doc */ nullptr,\n"
+ << " /* m_size */ -1,\n"
+ << " /* m_methods */ " << moduleName() << "_methods,\n"
+ << " /* m_reload */ nullptr,\n"
+ << " /* m_traverse */ nullptr,\n"
+ << " /* m_clear */ nullptr,\n"
+ << " /* m_free */ nullptr\n};\n\n";
+
+ // PYSIDE-510: Create a signatures string for the introspection feature.
+ writeSignatureStrings(s, signatureStream.toString(), moduleName(), "global functions");
+
+ writeInitInheritance(s);
+
+ // Write module init function
+ const QString globalModuleVar = pythonModuleObjectName();
+ s << "extern \"C\" LIBSHIBOKEN_EXPORT PyObject *PyInit_"
+ << moduleName() << "()\n{\n" << indent;
+ // Guard against repeated invocation
+ s << "if (" << globalModuleVar << " != nullptr)\n"
+ << indent << "return " << globalModuleVar << ";\n" << outdent;
+
+ // module inject-code target/beginning
+ writeModuleCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning,
+ TypeSystem::TargetLangCode);
+
+ for (const QString &requiredModule : requiredModules) {
+ s << "{\n" << indent
+ << "Shiboken::AutoDecRef requiredModule(Shiboken::Module::import(\"" << requiredModule << "\"));\n"
+ << "if (requiredModule.isNull())\n" << indent
+ << "return nullptr;\n" << outdent
+ << cppApiVariableName(requiredModule)
+ << " = Shiboken::Module::getTypes(requiredModule);\n"
+ << convertersVariableName(requiredModule)
+ << " = Shiboken::Module::getTypeConverters(requiredModule);\n" << outdent
+ << "}\n\n";
+ }
+
+ int maxTypeIndex = getMaxTypeIndex() + api().instantiatedSmartPointers().size();
+ if (maxTypeIndex) {
+ s << "// Create an array of wrapper types/names for the current module.\n"
+ << "static Shiboken::Module::TypeInitStruct cppApi[] = {\n" << indent;
+
+ // Windows did not like an array of QString.
+ QStringList typeNames;
+ for (int idx = 0; idx < maxTypeIndex; ++idx)
+ typeNames.append("+++ unknown entry #"_L1 + QString::number(idx)
+ + " in "_L1 + moduleName());
+
+ collectFullTypeNamesArray(typeNames);
+
+ for (auto typeName : typeNames)
+ s << "{nullptr, \"" << typeName << "\"},\n";
+
+ s << "{nullptr, nullptr}\n" << outdent << "};\n"
+ << "// The new global structure consisting of (type, name) pairs.\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"
+ << "static SbkConverter *sbkConverters[SBK_" << moduleName()
+ << "_CONVERTERS_IDX_COUNT" << "];\n"
+ << convertersVariableName() << " = sbkConverters;\n\n"
+ << "PyObject *module = Shiboken::Module::create(\"" << moduleName()
+ << "\", &moduledef);\n\n"
+ << "// Make module available from global scope\n"
+ << globalModuleVar << " = module;\n\n";
+
+ const QString subModuleOf = typeDb->defaultTypeSystemType()->subModuleOf();
+ if (!subModuleOf.isEmpty())
+ writeSubModuleHandling(s, moduleName(), subModuleOf);
+
+ s << "// Initialize classes in the type system\n"
+ << s_classPythonDefines.toString();
+
+ if (!typeConversions.isEmpty()) {
+ s << '\n';
+ for (const auto &conversion : typeConversions) {
+ writePrimitiveConverterInitialization(s, conversion);
+ s << '\n';
+ }
+ }
+
+ if (!containers.isEmpty()) {
+ s << '\n';
+ for (const AbstractMetaType &container : containers) {
+ const QString converterObj = writeContainerConverterInitialization(s, container, api());
+ const auto it = opaqueContainers.constFind(container);
+ if (it != opaqueContainers.constEnd()) {
+ writeSetPythonToCppPointerConversion(s, converterObj,
+ it.value().pythonToConverterFunctionName,
+ it.value().converterCheckFunctionName);
+ }
+ s << '\n';
+ }
+ }
+
+ if (!opaqueContainers.isEmpty()) {
+ s << "\n// Opaque container type registration\n"
+ << "PyObject *ob_type{};\n";
+ for (const auto &d : opaqueContainers)
+ s << d.registrationCode;
+ s << '\n';
+ }
+
+ if (!extendedConverters.isEmpty()) {
+ s << '\n';
+ for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
+ writeExtendedConverterInitialization(s, it.key(), it.value());
+ s << '\n';
+ }
+ }
+
+ writeEnumsInitialization(s, globalEnums);
+
+ s << "// Register primitive types converters.\n";
+ const PrimitiveTypeEntryCList &primitiveTypeList = primitiveTypes();
+ for (const auto &pte : primitiveTypeList) {
+ if (!pte->generateCode() || !isCppPrimitive(pte))
+ continue;
+ if (!pte->referencesType())
+ continue;
+ TypeEntryCPtr referencedType = basicReferencedTypeEntry(pte);
+ registerConverterInScopes(s, pte->qualifiedCppName(), converterObject(referencedType));
+ }
+
+ s << '\n';
+ if (maxTypeIndex)
+ s << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");\n";
+ s << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");\n";
+
+ // Static fields are registered last since they may use converter functions
+ // of the previously registered types (PYSIDE-1529).
+ if (!classesWithStaticFields.isEmpty()) {
+ s << "\n// Static field initialization\n";
+ for (const auto &cls : std::as_const(classesWithStaticFields)) {
+ ConfigurableScope configScope(s, cls->typeEntry());
+ s << getSimpleClassStaticFieldsInitFunctionName(cls) << "(module);\n";
+ }
+ }
+
+ s << '\n' << initInheritanceFunction << "();\n"
+ << "\nif (" << shibokenErrorsOccurred << ") {\n" << indent
+ << "PyErr_Print();\n"
+ << "Py_FatalError(\"can't initialize module " << moduleName() << "\");\n"
+ << outdent << "}\n";
+
+ // module inject-code target/end
+ writeModuleCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode);
+
+ // module inject-code native/end
+ writeModuleCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode);
+
+ if (usePySideExtensions()) {
+ for (const AbstractMetaEnum &metaEnum : std::as_const(globalEnums))
+ if (!metaEnum.isAnonymous()) {
+ ConfigurableScope configScope(s, metaEnum.typeEntry());
+ s << "qRegisterMetaType< " << getFullTypeName(metaEnum.typeEntry())
+ << " >(\"" << metaEnum.name() << "\");\n";
+ }
+
+ // cleanup staticMetaObject attribute
+ s << "PySide::registerCleanupFunction(cleanTypesAttributes);\n\n";
+ }
+
+ // finish the rest of get_signature() initialization.
+ s << "FinishSignatureInitialization(module, " << moduleName()
+ << "_SignatureStrings);\n"
+ << "\nreturn module;\n" << outdent << "}\n";
+
+ file.done();
+ return true;
+}
+
+static ArgumentOwner getArgumentOwner(const AbstractMetaFunctionCPtr &func, int argIndex)
+{
+ ArgumentOwner argOwner = func->argumentOwner(func->ownerClass(), argIndex);
+ if (argOwner.index == ArgumentOwner::InvalidIndex)
+ argOwner = func->argumentOwner(func->declaringClass(), argIndex);
+ return argOwner;
+}
+
+// Whether to enable parent ownership heuristic for a function and its argument.
+// Both must belong to the same class hierarchy and have the same
+// type entry enabling parent management.
+static bool useParentHeuristics(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaType &argType)
+{
+ if (!ComplexTypeEntry::isParentManagementEnabled()) // FIXME PYSIDE 7: Remove this
+ return true;
+ const auto owner = func->ownerClass();
+ if (!owner)
+ return false;
+ auto ownerEntry = parentManagementEntry(owner);
+ if (!ownerEntry)
+ return false;
+ auto argTypeEntry = argType.typeEntry();
+ if (!argTypeEntry->isComplex())
+ return false;
+ const auto argClass = AbstractMetaClass::findClass(api.classes(), argTypeEntry);
+ return argClass && parentManagementEntry(argClass) == ownerEntry;
+}
+
+bool CppGenerator::writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ int argIndex,
+ bool usePyArgs, bool useHeuristicPolicy) const
+{
+ const int numArgs = func->arguments().size();
+ bool ctorHeuristicEnabled = func->isConstructor() && useCtorHeuristic() && useHeuristicPolicy;
+ bool heuristicTriggered = false;
+
+ ArgumentOwner argOwner = getArgumentOwner(func, argIndex);
+ ArgumentOwner::Action action = argOwner.action;
+ int parentIndex = argOwner.index;
+ int childIndex = argIndex;
+ if (ctorHeuristicEnabled && argIndex > 0 && argIndex <= numArgs) {
+ const AbstractMetaArgument &arg = func->arguments().at(argIndex-1);
+ if (arg.name() == u"parent" && arg.type().isObjectType()
+ && useParentHeuristics(api(), func, arg.type())) {
+ action = ArgumentOwner::Add;
+ parentIndex = argIndex;
+ childIndex = -1;
+ heuristicTriggered = true;
+ }
+ }
+
+ QString parentVariable;
+ QString childVariable;
+ if (action != ArgumentOwner::Invalid) {
+ if (!usePyArgs && argIndex > 1)
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Argument index for parent tag out of bounds: " << func->signature();
+
+ if (action == ArgumentOwner::Remove) {
+ parentVariable = u"Py_None"_s;
+ } else {
+ if (parentIndex == 0) {
+ parentVariable = PYTHON_RETURN_VAR;
+ } else if (parentIndex == -1) {
+ parentVariable = PYTHON_SELF_VAR;
+ } else {
+ parentVariable = usePyArgs
+ ? pythonArgsAt(parentIndex - 1) : PYTHON_ARG;
+ }
+ }
+
+ if (childIndex == 0) {
+ childVariable = PYTHON_RETURN_VAR;
+ } else if (childIndex == -1) {
+ childVariable = PYTHON_SELF_VAR;
+ } else {
+ childVariable = usePyArgs
+ ? pythonArgsAt(childIndex - 1) : PYTHON_ARG;
+ }
+
+ s << "// Ownership transferences";
+ if (heuristicTriggered)
+ s << " (constructor heuristics)";
+ s << ".\nShiboken::Object::setParent(" << parentVariable << ", "
+ << childVariable << ");\n";
+ return true;
+ }
+
+ return false;
+}
+
+void CppGenerator::writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ bool usesPyArgs,
+ bool useHeuristicForReturn) const
+{
+ const int numArgs = func->arguments().size();
+
+ // -1 = return value
+ // 0 = self
+ // 1..n = func. args.
+ for (int i = -1; i <= numArgs; ++i)
+ writeParentChildManagement(s, func, i, usesPyArgs, useHeuristicForReturn);
+
+ if (useHeuristicForReturn)
+ writeReturnValueHeuristics(s, func);
+}
+
+void CppGenerator::writeReturnValueHeuristics(TextStream &s, const AbstractMetaFunctionCPtr &func) const
+{
+ const AbstractMetaType &type = func->type();
+ if (!useReturnValueHeuristic()
+ || !func->ownerClass()
+ || type.isVoid()
+ || func->isStatic()
+ || func->isConstructor()
+ || func->isTypeModified()
+ || !useParentHeuristics(api(), func, type)
+ // Something like parent(), parentWidget(): No child relationship here.
+ || (func->maybeAccessor() && func->name().startsWith(u"parent"))) {
+ return;
+ }
+
+ ArgumentOwner argOwner = getArgumentOwner(func, ArgumentOwner::ReturnIndex);
+ if (argOwner.action == ArgumentOwner::Invalid || argOwner.index != ArgumentOwner::ThisIndex) {
+ if (type.isPointerToWrapperType()) {
+ s << "// Ownership transferences (return value heuristics).\n"
+ << "Shiboken::Object::setParent(self, " << PYTHON_RETURN_VAR << ");\n";
+ }
+ }
+}
+
+void CppGenerator::writeHashFunction(TextStream &s, const GeneratorContext &context)
+{
+ const auto metaClass = context.metaClass();
+ const char hashType[] = "Py_hash_t";
+ s << "static " << hashType << ' ' << cpythonBaseName(metaClass)
+ << "_HashFunc(PyObject *self)\n{\n" << indent;
+ writeCppSelfDefinition(s, context);
+
+ bool deref = true;
+ QString name = metaClass->typeEntry()->hashFunction();
+ if (name.isEmpty())
+ name = metaClass->hashFunction();
+ else
+ deref = !metaClass->isObjectType();
+ Q_ASSERT(!name.isEmpty());
+
+ s << "return " << hashType << '(' << name << '(';
+ if (deref)
+ s << '*';
+ s << CPP_SELF_VAR << "));\n"
+ << outdent << "}\n\n";
+}
+
+void CppGenerator::writeDefaultSequenceMethods(TextStream &s,
+ const GeneratorContext &context) const
+{
+ const auto metaClass = context.metaClass();
+ ErrorReturn errorReturn = ErrorReturn::Zero;
+
+ // __len__
+ const QString namePrefix = cpythonBaseName(metaClass->typeEntry());
+ s << "Py_ssize_t " << namePrefix
+ << "__len__(PyObject *self)\n{\n" << indent;
+ writeCppSelfDefinition(s, context, errorReturn);
+ s << "return " << CPP_SELF_VAR << "->size();\n"
+ << outdent << "}\n";
+
+ // __getitem__
+ s << "PyObject *" << namePrefix
+ << "__getitem__(PyObject *self, Py_ssize_t _i)\n{\n" << indent;
+ writeCppSelfDefinition(s, context, errorReturn);
+ writeIndexError(s, u"index out of bounds"_s, errorReturn);
+
+ s << metaClass->qualifiedCppName() << "::const_iterator _item = "
+ << CPP_SELF_VAR << "->begin();\n"
+ << "std::advance(_item, _i);\n";
+
+ const AbstractMetaTypeList &instantiations = metaClass->templateBaseClassInstantiations();
+ if (instantiations.isEmpty()) {
+ QString m;
+ QTextStream(&m) << "shiboken: " << __FUNCTION__
+ << ": Internal error, no instantiations of \"" << metaClass->qualifiedCppName()
+ << "\" were found.";
+ throw Exception(m);
+ }
+ const AbstractMetaType &itemType = instantiations.constFirst();
+
+ s << "return ";
+ writeToPythonConversion(s, itemType, metaClass, u"*_item"_s);
+ s << ";\n" << outdent << "}\n";
+
+ // __setitem__
+ s << "int " << namePrefix
+ << "__setitem__(PyObject *self, Py_ssize_t _i, PyObject *pyArg)\n{\n"
+ << indent;
+ errorReturn = ErrorReturn::MinusOne;
+ writeCppSelfDefinition(s, context, errorReturn);
+ writeIndexError(s, u"list assignment index out of range"_s, errorReturn);
+
+ s << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR << ";\n"
+ << "if (!";
+ writeTypeCheck(s, itemType, u"pyArg"_s, isNumber(itemType.typeEntry()));
+ s << ") {\n" << indent
+ << "Shiboken::Errors::setSequenceTypeError(\"" << itemType.name() << "\");\n"
+ << "return -1;\n" << outdent << "}\n";
+ writeArgumentConversion(s, itemType, u"cppValue"_s,
+ u"pyArg"_s, errorReturn, metaClass);
+
+ s << metaClass->qualifiedCppName() << "::iterator _item = "
+ << CPP_SELF_VAR << "->begin();\n"
+ << "std::advance(_item, _i);\n"
+ << "*_item = cppValue;\n";
+
+ s << "return {};\n" << outdent << "}\n";
+}
+void CppGenerator::writeIndexError(TextStream &s, const QString &errorMsg,
+ ErrorReturn errorReturn)
+{
+ s << "if (_i < 0 || _i >= (Py_ssize_t) " << CPP_SELF_VAR << "->size()) {\n"
+ << indent << "PyErr_SetString(PyExc_IndexError, \"" << errorMsg << "\");\n"
+ << errorReturn << outdent << "}\n";
+}
+
+QString CppGenerator::writeReprFunctionHeader(TextStream &s, const GeneratorContext &context)
+{
+ QString funcName = cpythonBaseName(context.metaClass()) + REPR_FUNCTION;
+ s << "extern \"C\"\n{\n"
+ << "static PyObject *" << funcName << "(PyObject *self)\n{\n" << indent;
+ return funcName;
+}
+
+QString CppGenerator::writeReprFunction(TextStream &s,
+ const GeneratorContext &context,
+ uint indirections)
+{
+ const auto metaClass = context.metaClass();
+ QString funcName = writeReprFunctionHeader(s, context);
+ writeCppSelfDefinition(s, context);
+ s << R"(QBuffer buffer;
+buffer.open(QBuffer::ReadWrite);
+QDebug dbg(&buffer);
+dbg << )";
+ if (metaClass->typeEntry()->isValue() || indirections == 0)
+ s << '*';
+ s << CPP_SELF_VAR << R"(;
+buffer.close();
+QByteArray str = buffer.data();
+const auto idx = str.indexOf('(');
+auto *typeName = Py_TYPE(self)->tp_name;
+if (idx >= 0)
+)" << indent << "str.replace(0, idx, typeName);\n" << outdent
+ << "str = str.trimmed();\n"
+ << "Shiboken::AutoDecRef tpDict(PepType_GetDict(Py_TYPE(self)));\n"
+ << "PyObject *mod = PyDict_GetItem(tpDict.object(), Shiboken::PyMagicName::module());\n";
+ // PYSIDE-595: The introduction of heap types has the side effect that the module name
+ // is always prepended to the type name. Therefore the strchr check:
+ s << "if (mod != nullptr && std::strchr(typeName, '.') == nullptr)\n" << indent
+ << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\","
+ " Shiboken::String::toCString(mod), str.constData(), self);\n"
+ << outdent
+ << "return Shiboken::String::fromFormat(\"<%s at %p>\", str.constData(), self);\n";
+ writeReprFunctionFooter(s);
+ return funcName;
+}
+
+void CppGenerator::writeReprFunctionFooter(TextStream &s)
+{
+ s << outdent << "}\n} // extern C\n\n";
+}
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h
new file mode 100644
index 000000000..5920c9a3a
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.h
@@ -0,0 +1,565 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CPPGENERATOR_H
+#define CPPGENERATOR_H
+
+#include "shibokengenerator.h"
+#include "include.h"
+#include "modifications_typedefs.h"
+
+#include <QtCore/QFlags>
+#include <QtCore/QSet>
+#include <QtCore/QHash>
+
+#include <memory>
+#include <utility>
+
+class OverloadDataNode;
+class OverloadDataRootNode;
+struct PyMethodDefEntry;
+
+/**
+ * The CppGenerator generate the implementations of C++ bindings classes.
+ */
+class CppGenerator : public ShibokenGenerator
+{
+public:
+ enum class ErrorReturn {
+ Default, // "{}"
+ Zero,
+ MinusOne,
+ Void
+ };
+
+ enum CppSelfDefinitionFlag {
+ HasStaticOverload = 0x1,
+ HasClassMethodOverload = 0x2,
+ CppSelfAsReference = 0x4
+ };
+ Q_DECLARE_FLAGS(CppSelfDefinitionFlags, CppSelfDefinitionFlag)
+
+ CppGenerator();
+
+ const char *name() const override { return "Source generator"; }
+
+protected:
+ QString fileNameForContext(const GeneratorContext &context) const override;
+ void generateClass(TextStream &s, const GeneratorContext &classContext) override;
+ bool finishGeneration() override;
+
+private:
+ struct VirtualMethodReturn
+ {
+ QString statement;
+ bool needsReference = false;
+ };
+
+
+ void generateSmartPointerClass(TextStream &s, const GeneratorContext &classContext);
+ void generateIncludes(TextStream &s, const GeneratorContext &classContext,
+ const IncludeGroupList &includes = {},
+ const AbstractMetaClassCList &innerClasses = {}) const;
+ static void 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;
+ static void writeDestructorNative(TextStream &s, const GeneratorContext &classContext);
+
+ QString getVirtualFunctionReturnTypeName(const AbstractMetaFunctionCPtr &func) const;
+ static std::pair<QString, QChar> virtualMethodNativeArg(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &arg);
+ static void writeVirtualMethodNativeVectorCallArgs(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgumentList &arguments,
+ const QList<int> &invalidateArgs);
+ static void writeVirtualMethodNativeArgs(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgumentList &arguments,
+ const QList<int> &invalidateArgs);
+ void writeVirtualMethodNative(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ int cacheIndex) const;
+ void writeVirtualMethodPythonOverride(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const CodeSnipList &snips,
+ const VirtualMethodReturn &returnStatement) const;
+ void writeUserAddedPythonOverride(TextStream &s,
+ const AbstractMetaFunctionCPtr &func) const;
+ void writeVirtualMethodCppCall(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const QString &funcName, const QList<CodeSnip> &snips,
+ const AbstractMetaArgument *lastArg, const TypeEntryCPtr &retType,
+ const QString &returnStatement, bool hasGil) const;
+
+ static VirtualMethodReturn virtualMethodReturn(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func,
+ const FunctionModificationList &functionModifications);
+ void writeMetaObjectMethod(TextStream &s, const GeneratorContext &classContext) const;
+ static void writeMetaCast(TextStream &s, const GeneratorContext &classContext);
+
+ void writeEnumConverterFunctions(TextStream &s, const AbstractMetaEnum &metaEnum) const;
+ void writeConverterFunctions(TextStream &s, const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext) const;
+ void writeCustomConverterFunctions(TextStream &s,
+ const CustomConversionPtr &customConversion) const;
+ void writeConverterRegister(TextStream &s, const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext) const;
+ static void writeCustomConverterRegister(TextStream &s,
+ const CustomConversionPtr &customConversion,
+ const QString &converterVar);
+
+ void writeContainerConverterFunctions(TextStream &s,
+ const AbstractMetaType &containerType) const;
+
+ struct OpaqueContainerData
+ {
+ QString name;
+ QString checkFunctionName;
+ QString converterCheckFunctionName;
+ QString pythonToConverterFunctionName;
+ QString registrationCode;
+ };
+
+ OpaqueContainerData
+ writeOpaqueContainerConverterFunctions(TextStream &s,
+ const AbstractMetaType &containerType,
+ QSet<AbstractMetaType> *valueTypes) const;
+ void writeOpaqueContainerValueConverter(TextStream &s,
+ const AbstractMetaType &valueType) const;
+
+ void writeSmartPointerConverterFunctions(TextStream &s,
+ const AbstractMetaType &smartPointerType) const;
+
+ static bool needsArgumentErrorHandling(const OverloadData &overloadData);
+ static void writeMethodWrapperPreamble(TextStream &s,
+ const OverloadData &overloadData,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn = ErrorReturn::Default);
+ void writeConstructorWrapper(TextStream &s,
+ const OverloadData &overloadData,
+ const GeneratorContext &classContext) const;
+ void writeMethodWrapper(TextStream &s, const OverloadData &overloadData,
+ const GeneratorContext &classContext) const;
+ void writeMethodWrapper(TextStream &s, TextStream &definitionStream,
+ TextStream &signatureStream,
+ const AbstractMetaFunctionCList &overloads,
+ const GeneratorContext &classContext) const;
+ static void writeArgumentsInitializer(TextStream &s, const OverloadData &overloadData,
+ ErrorReturn errorReturn = ErrorReturn::Default);
+ static void writeCppSelfConversion(TextStream &s,
+ const GeneratorContext &context,
+ const QString &className,
+ bool useWrapperClass);
+ static void writeSmartPointerCppSelfConversion(TextStream &s,
+ const GeneratorContext &context);
+
+ static void writeCppSelfVarDef(TextStream &s, CppSelfDefinitionFlags flags = {});
+ static void writeSmartPointerCppSelfDefinition(TextStream &s,
+ const GeneratorContext &,
+ ErrorReturn errorReturn = ErrorReturn::Default,
+ CppSelfDefinitionFlags flags = {});
+ static void writeCppSelfDefinition(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn = ErrorReturn::Default,
+ CppSelfDefinitionFlags flags = {});
+ static void writeCppSelfDefinition(TextStream &s,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn = ErrorReturn::Default,
+ CppSelfDefinitionFlags flags = {});
+
+ static void writeErrorSection(TextStream &s,
+ const OverloadData &overloadData,
+ ErrorReturn errorReturn);
+
+ static QString returnErrorWrongArguments(const OverloadData &overloadData,
+ ErrorReturn errorReturn);
+
+ static void writeFunctionReturnErrorCheckSection(TextStream &s,
+ ErrorReturn errorReturn,
+ bool hasReturnValue = true);
+
+ /// Writes the check section for the validity of wrapped C++ objects.
+ static void writeInvalidPyObjectCheck(TextStream &s, const QString &pyObj,
+ ErrorReturn errorReturn);
+
+ static void writeTypeCheck(TextStream &s, const AbstractMetaType &argType,
+ const QString &argumentName,
+ bool isNumber = false, bool rejectNull = false);
+ static void writeTypeCheck(TextStream &s, const QString &customType,
+ const QString &argumentName);
+ static void writeTypeCheck(TextStream& s, const std::shared_ptr<OverloadDataNode> &overloadData,
+ const QString &argumentName);
+
+ static void replacePolymorphicIdPlaceHolders(const AbstractMetaClassCPtr &metaClass,
+ QString *id);
+ static void writeTypeDiscoveryFunction(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass);
+
+ static void writeSetattroDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+ static void writeSetattroDefaultReturn(TextStream &s);
+ static void writeSmartPointerSetattroFunction(TextStream &s,
+ const GeneratorContext &context);
+ void writeSetattroFunction(TextStream &s,
+ AttroCheck attroCheck,
+ const GeneratorContext &context) const;
+ static void writeGetattroDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+ static void writeSmartPointerGetattroFunction(TextStream &s,
+ const GeneratorContext &context,
+ const BoolCastFunctionOptional &boolCast);
+ void writeGetattroFunction(TextStream &s, AttroCheck attroCheck,
+ const GeneratorContext &context) const;
+ QString qObjectGetAttroFunction() const;
+
+ static void writeNbBoolFunction(const GeneratorContext &context,
+ const BoolCastFunction &f,
+ TextStream &s);
+ static void writeNbBoolExpression(TextStream &s, const BoolCastFunction &f, bool invert = false);
+
+ /**
+ * Writes Python to C++ conversions for arguments on Python wrappers.
+ * If implicit conversions, and thus new object allocation, are needed,
+ * code to deallocate a possible new instance is also generated.
+ * \param s text stream to write
+ * \param argType a pointer to the argument type to be converted
+ * \param argName C++ argument name
+ * \param pyArgName Python argument name
+ * \param context the current meta class
+ * \param defaultValue an optional default value to be used instead of the conversion result
+ * \param castArgumentAsUnused if true the converted argument is cast as unused to avoid compiler warnings
+ */
+ qsizetype writeArgumentConversion(TextStream &s, const AbstractMetaType &argType,
+ const QString &argName, const QString &pyArgName,
+ ErrorReturn errorReturn,
+ const AbstractMetaClassCPtr &context = {},
+ const QString &defaultValue = QString(),
+ bool castArgumentAsUnused = false) const;
+
+ /**
+ * Returns the AbstractMetaType for a function argument.
+ * If the argument type was modified in the type system, this method will
+ * try to build a new type based on the type name defined in the type system.
+ * \param func The function which owns the argument.
+ * \param index Argument index in the function signature.
+ * \return The type of the argument indicated by \p index.
+ */
+ static AbstractMetaType
+ getArgumentType(const AbstractMetaFunctionCPtr &func, int index);
+
+ /// Writes the Python to C++ Conversion for function arguments and return
+ /// values of virtual methods for wrappers.
+ /// \return The number of indirections in case of return types
+ qsizetype writePythonToCppTypeConversion(TextStream &s,
+ const AbstractMetaType &type,
+ const QString &pyIn,
+ const QString &cppOut,
+ const AbstractMetaClassCPtr &context = {},
+ const QString &defaultValue = {}) const;
+
+ /// Writes the conversion rule for arguments of regular and virtual methods.
+ void writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ TypeSystem::Language language, bool usesPyArgs) const;
+ /// Writes the conversion rule for the return value of a method.
+ void writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ TypeSystem::Language language, const QString &outputVar) const;
+
+ /**
+ * Set the Python method wrapper return value variable to Py_None if
+ * there are return types different from void in any of the other overloads
+ * for the function passed as parameter.
+ * \param s text stream to write
+ * \param func a pointer to the function that will possibly return Py_None
+ * \param thereIsReturnValue indicates if the return type of any of the other overloads
+ * for this function is different from 'void'
+ */
+ static void writeNoneReturn(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ bool thereIsReturnValue);
+
+ /**
+ * Writes the Python function wrapper overload decisor that selects which C++
+ * method/function to call with the received Python arguments.
+ * \param s text stream to write
+ * \param overloadData the overload data describing all the possible overloads for the function/method
+ */
+ void writeOverloadedFunctionDecisor(TextStream &s, const OverloadData &overloadData,
+ ErrorReturn errorReturn) const;
+ /// Recursive auxiliar method to the other writeOverloadedFunctionDecisor.
+ void writeOverloadedFunctionDecisorEngine(TextStream &s,
+ const OverloadData &overloadData,
+ const OverloadDataRootNode *node) const;
+
+ /// Writes calls to all the possible method/function overloads.
+ void writeFunctionCalls(TextStream &s,
+ const OverloadData &overloadData,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn) const;
+
+ /// Writes the call to a single function usually from a collection of overloads.
+ void writeSingleFunctionCall(TextStream &s,
+ const OverloadData &overloadData,
+ const AbstractMetaFunctionCPtr &func,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn) const;
+
+ /// Returns the name of a C++ to Python conversion function.
+ static QString cppToPythonFunctionName(const QString &sourceTypeName, QString targetTypeName = QString());
+
+ /// Returns the name of a Python to C++ conversion function.
+ static QString pythonToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName);
+ static QString pythonToCppFunctionName(const AbstractMetaType &sourceType, const AbstractMetaType &targetType);
+ static QString pythonToCppFunctionName(const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType);
+
+ /// Returns the name of a Python to C++ convertible check function.
+ static QString convertibleToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName);
+ static QString convertibleToCppFunctionName(const AbstractMetaType &sourceType, const AbstractMetaType &targetType);
+ static QString convertibleToCppFunctionName(const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType);
+
+ /// Writes a C++ to Python conversion function.
+ void writeCppToPythonFunction(TextStream &s, const QString &code, const QString &sourceTypeName,
+ QString targetTypeName = QString()) const;
+ void writeCppToPythonFunction(TextStream &s, const CustomConversionPtr &customConversion) const;
+ void writeCppToPythonFunction(TextStream &s, const AbstractMetaType &containerType) const;
+ /// Main target type name of a container (for naming the functions).
+ static QString containerNativeToTargetTypeName(const ContainerTypeEntryCPtr &type);
+
+ /// Writes a Python to C++ conversion function.
+ void writePythonToCppFunction(TextStream &s, const QString &code, const QString &sourceTypeName,
+ const QString &targetTypeName) const;
+
+ /// Writes a Python to C++ convertible check function.
+ static void writeIsPythonConvertibleToCppFunction(TextStream &s,
+ const QString &sourceTypeName,
+ const QString &targetTypeName,
+ const QString &condition,
+ QString pythonToCppFuncName = QString(),
+ bool acceptNoneAsCppNull = false);
+
+ /// Writes a pair of Python to C++ conversion and check functions.
+ void writePythonToCppConversionFunctions(TextStream &s,
+ const AbstractMetaType &sourceType,
+ const AbstractMetaType &targetType,
+ QString typeCheck = QString(),
+ QString conversion = QString(),
+ const QString &preConversion = QString()) const;
+ /// Writes a pair of Python to C++ conversion and check functions for implicit conversions.
+ void writePythonToCppConversionFunctions(TextStream &s,
+ const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType) const;
+
+ /// Writes a pair of Python to C++ conversion and check functions for instantiated container types.
+ void writePythonToCppConversionFunctions(TextStream &s,
+ const AbstractMetaType &containerType) const;
+
+ void writePythonToCppConversionFunction(TextStream &s,
+ const AbstractMetaType &containerType,
+ const TargetToNativeConversion &conv) const;
+
+ static void writeAddPythonToCppConversion(TextStream &s, const QString &converterVar,
+ const QString &pythonToCppFunc,
+ const QString &isConvertibleFunc);
+
+ static void writeSetPythonToCppPointerConversion(TextStream &s, const QString &converterVar,
+ const QString &pythonToCppFunc,
+ const QString &isConvertibleFunc);
+
+ static void writeNamedArgumentResolution(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ bool usePyArgs,
+ const OverloadData &overloadData,
+ ErrorReturn errorReturn);
+
+ /// Returns a string containing the name of an argument for the given function and argument index.
+ static QString argumentNameFromIndex(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func, int argIndex);
+ /// Returns the class for an ownership modification of the argument.
+ /// Throws if the argument is not a class or cannot be found.
+ static AbstractMetaClassCPtr
+ argumentClassFromIndex(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func, int argIndex);
+
+ void writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const GeneratorContext &context, bool usesPyArgs,
+ int maxArgs, const QList<qsizetype> &argumentIndirections,
+ ErrorReturn errorReturn) const;
+
+ static QString getInitFunctionName(const GeneratorContext &context) ;
+ static QString getSimpleClassInitFunctionName(const AbstractMetaClassCPtr &metaClass);
+ static QString
+ getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClassCPtr &metaClass);
+
+ static void writeSignatureStrings(TextStream &s, const QString &signatures,
+ const QString &arrayName,
+ const char *comment);
+ void writeInitInheritance(TextStream &s) const;
+ void writeClassRegister(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext,
+ const QString &signatures) const;
+ static QStringList pyBaseTypes(const AbstractMetaClassCPtr &metaClass);
+ static QString destructorClassName(const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext);
+ static void writeStaticFieldInitialization(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass);
+ void writeClassDefinition(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext);
+ QByteArrayList methodDefinitionParameters(const OverloadData &overloadData) const;
+ QList<PyMethodDefEntry> methodDefinitionEntries(const OverloadData &overloadData) const;
+
+ 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,
+ const GeneratorContext &context) const;
+ static void writeTypeAsSequenceDefinition(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass);
+
+ /// Writes the PyMappingMethods structure for types that supports the python mapping protocol.
+ static void writeTypeAsMappingDefinition(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass);
+ void writeMappingMethods(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &context) const;
+
+ void writeTypeAsNumberDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass) const;
+
+ static void writeTpTraverseFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+ static void writeTpClearFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+
+ static QString writeCopyFunction(TextStream &s, TextStream &definitionStream,
+ TextStream &signatureStream, const GeneratorContext &context);
+
+ static QString cppFieldAccess(const AbstractMetaField &metaField,
+ const GeneratorContext &context);
+ static void writeGetterFunction(TextStream &s,
+ const AbstractMetaField &metaField,
+ const GeneratorContext &context);
+ static void writeGetterFunction(TextStream &s,
+ const QPropertySpec &property,
+ const GeneratorContext &context);
+ static void writeSetterFunctionPreamble(TextStream &s,
+ const QString &name,
+ const QString &funcName,
+ const AbstractMetaType &type,
+ const GeneratorContext &context);
+ static void writeSetterFunction(TextStream &s,
+ const AbstractMetaField &metaField,
+ const GeneratorContext &context);
+ static void writeSetterFunction(TextStream &s,
+ const QPropertySpec &property,
+ const GeneratorContext &context);
+
+ static void writeRichCompareFunctionHeader(TextStream &s,
+ const QString &baseName,
+ const GeneratorContext &context);
+ void writeRichCompareFunction(TextStream &s, const GeneratorContext &context) const;
+ void writeSmartPointerRichCompareFunction(TextStream &s, const GeneratorContext &context) const;
+
+ static void writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums);
+ static bool writeEnumInitialization(TextStream &s, const AbstractMetaEnum &metaEnum);
+
+ static void writeSignalInitialization(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+
+ /// Writes the function that registers the multiple inheritance information
+ /// for the classes that need it.
+ static void writeMultipleInheritanceInitializerFunction(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass);
+ /// Writes the implementation of special cast functions, used when we need
+ /// to cast a class with multiple inheritance.
+ static void writeSpecialCastFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+
+ static void writePrimitiveConverterInitialization(TextStream &s,
+ const CustomConversionPtr &customConversion);
+ static void writeEnumConverterInitialization(TextStream &s, const AbstractMetaEnum &metaEnum);
+ static QString writeContainerConverterInitialization(TextStream &s,
+ const AbstractMetaType &type,
+ const ApiExtractorResult &api);
+ void writeSmartPointerConverterInitialization(TextStream &s, const AbstractMetaType &ype) const;
+
+ static QString typeInitStruct(const TypeEntryCPtr &te);
+ static void writeExtendedConverterInitialization(TextStream &s,
+ const TypeEntryCPtr &externalType,
+ const AbstractMetaClassCList &conversions);
+
+ void writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ bool usesPyArgs,
+ bool userHeuristicForReturn) const;
+ bool writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ int argIndex,
+ bool usePyArgs,
+ bool userHeuristicPolicy) const;
+ void writeReturnValueHeuristics(TextStream &s, const AbstractMetaFunctionCPtr &func) const;
+ static void writeInitQtMetaTypeFunctionBody(TextStream &s, const GeneratorContext &context);
+
+ /**
+ * Returns the multiple inheritance initializer function for the given class.
+ * \param metaClass the class for whom the function name must be generated.
+ * \return name of the multiple inheritance information initializer function or
+ * an empty string if there is no multiple inheritance in its ancestry.
+ */
+ static QString multipleInheritanceInitializerFunctionName(const AbstractMetaClassCPtr &metaClass);
+
+ /// Returns a list of all classes to which the given class could be cast.
+ static QStringList getAncestorMultipleInheritance(const AbstractMetaClassCPtr &metaClass);
+
+ /// Returns true if the given class supports the python number protocol
+ static bool supportsNumberProtocol(const AbstractMetaClassCPtr &metaClass);
+
+ /// Returns true if the given class supports the python sequence protocol
+ static bool supportsSequenceProtocol(const AbstractMetaClassCPtr &metaClass) ;
+
+ /// Returns true if the given class supports the python mapping protocol
+ static bool supportsMappingProtocol(const AbstractMetaClassCPtr &metaClass) ;
+
+ /// Returns true if generator should produce getters and setters for the given class.
+ static bool shouldGenerateGetSetList(const AbstractMetaClassCPtr &metaClass);
+
+ static bool hasHashFunction(const AbstractMetaClassCPtr &c);
+ static void writeHashFunction(TextStream &s, const GeneratorContext &context);
+
+ /// Write default implementations for sequence protocol
+ void writeDefaultSequenceMethods(TextStream &s, const GeneratorContext &context) const;
+ /// Helper function for writeStdListWrapperMethods.
+ static void writeIndexError(TextStream &s, const QString &errorMsg,
+ ErrorReturn errorReturn);
+
+ static QString writeReprFunctionHeader(TextStream &s, const GeneratorContext &context);
+ static QString writeReprFunction(TextStream &s,
+ const GeneratorContext &context,
+ uint indirections);
+ static QString writeSmartPointerReprFunction(TextStream &s,
+ const GeneratorContext &context);
+ static QString writeSmartPointerDirFunction(TextStream &s,
+ TextStream &definitionStream,
+ TextStream &signatureStream,
+ const GeneratorContext &context);
+ static void writeReprFunctionFooter(TextStream &s);
+ static void writePyMethodDefs(TextStream &s, const QString &className,
+ const QString &methodsDefinitions);
+
+ void writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const;
+
+ static bool hasBoolCast(const AbstractMetaClassCPtr &metaClass)
+ { return boolCast(metaClass).has_value(); }
+
+ void clearTpFuncs();
+ static QString chopType(QString s);
+
+ QHash<QString, QString> m_tpFuncs;
+ QHash<QString, QString> m_nbFuncs;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(CppGenerator::CppSelfDefinitionFlags)
+
+TextStream &operator<<(TextStream &s, CppGenerator::ErrorReturn r);
+
+#endif // CPPGENERATOR_H
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
new file mode 100644
index 000000000..00e0cabea
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
@@ -0,0 +1,272 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "cppgenerator.h"
+#include "generatorstrings.h"
+#include <abstractmetalang.h>
+#include "apiextractorresult.h"
+#include "ctypenames.h"
+#include "containertypeentry.h"
+#include "textstream.h"
+#include "typedatabase.h"
+
+#include <QtCore/QDebug>
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+// Write a PyMethodDef entry, allowing for registering C++ functions
+// under different names for Python.
+static void writeMethod(TextStream &s, const QString &privateObjType,
+ const char *cppName, const char *pythonName,
+ const char *flags)
+{
+ if (pythonName == nullptr)
+ pythonName = cppName;
+ s << "{\"" << pythonName << "\", reinterpret_cast<PyCFunction>("
+ << privateObjType << "::" << cppName << "), "<< flags
+ << ", \"" << /* doc */ pythonName << "\"},\n";
+}
+
+static inline void writeMethod(TextStream &s, const QString &privateObjType,
+ const char *cppName, const char *pythonName = nullptr)
+{
+ writeMethod(s, privateObjType, cppName, pythonName, "METH_O");
+}
+
+static inline void writeNoArgsMethod(TextStream &s, const QString &privateObjType,
+ const char *cppName, const char *pythonName = nullptr)
+{
+ writeMethod(s, privateObjType, cppName, pythonName, "METH_NOARGS");
+}
+
+static void writeSlot(TextStream &s, const char *tpName, const char *value)
+{
+ s << '{' << tpName << ", reinterpret_cast<void *>(" << value << ")},\n";
+}
+
+static void writeSlot(TextStream &s, const QString &privateObjType,
+ const char *tpName, const char *methodName)
+{
+ s << '{' << tpName << ", reinterpret_cast<void *>(" << privateObjType
+ << "::" << methodName << ")},\n";
+}
+
+// Write creation function from C++ reference, used by field accessors
+// and getters which are within extern "C"
+
+enum ContainerCreationFlag
+{
+ None = 0,
+ Const = 0x1,
+ Allocate = 0x2
+};
+
+Q_DECLARE_FLAGS(ContainerCreationFlags, ContainerCreationFlag)
+Q_DECLARE_OPERATORS_FOR_FLAGS(ContainerCreationFlags)
+
+static void writeContainerCreationFunc(TextStream &s,
+ const QString &funcName,
+ const QString &typeFName,
+ const QString &containerSignature,
+ ContainerCreationFlags flags = {})
+{
+
+ // creation function from C++ reference, used by field accessors
+ // which are within extern "C"
+ s << "extern \"C\" PyObject *" << funcName << '(';
+ if (flags.testFlag(ContainerCreationFlag::Const))
+ s << "const ";
+ s << containerSignature << "* ct)\n{\n" << indent
+ << "auto *container = PyObject_New(ShibokenContainer, " << typeFName << "());\n"
+ << "auto *d = new ShibokenSequenceContainerPrivate<"
+ << containerSignature << ">();\n";
+ if (flags.testFlag(ContainerCreationFlag::Allocate)) {
+ s << "d->m_list = new " << containerSignature << "(*ct);\n"
+ << "d->m_ownsList = true;\n";
+ } else if (flags.testFlag(ContainerCreationFlag::Const)) {
+ s << "d->m_list = const_cast<" << containerSignature << " *>(ct);\n"
+ << "d->m_const = true;\n";
+ } else {
+ s << "d->m_list = ct;\n";
+ }
+ s << "container->d = d;\n";
+ s << "return reinterpret_cast<PyObject *>(container);\n" << outdent
+ << "}\n\n";
+}
+
+// Generate template specialization of value converter helper
+void CppGenerator::writeOpaqueContainerValueConverter(TextStream &s,
+ const AbstractMetaType &valueType) const
+{
+ // Generate template specialization of value converter helper unless it is already there
+ const QString valueTypeName = valueType.cppSignature();
+ const QString checkFunction = cpythonCheckFunction(valueType);
+
+ s << "template <>\nstruct ShibokenContainerValueConverter<"
+ << valueTypeName << ">\n{\n";
+ // Type check
+ s << indent << "static bool checkValue(PyObject *" << PYTHON_ARG << ")\n{\n"
+ << indent << "return " << checkFunction;
+ if (!checkFunction.contains(u'('))
+ s << '(';
+ s << PYTHON_ARG << ");\n"
+ << outdent << "}\n\n";
+
+ // C++ to Python
+ const bool passByConstRef = valueType.indirectionsV().isEmpty()
+ && !valueType.isCppPrimitive();
+ s << "static PyObject *convertValueToPython(";
+ if (passByConstRef)
+ s << "const ";
+ s << valueTypeName << ' ';
+ if (passByConstRef)
+ s << '&';
+ s << CPP_ARG << ")\n{\n" << indent << "return ";
+ writeToPythonConversion(s, valueType, nullptr, CPP_ARG);
+ s << ";\n" << outdent << "}\n\n";
+
+ // Python to C++
+ s << "static std::optional<" << valueTypeName << "> convertValueToCpp(PyObject *"
+ << PYTHON_ARG << ")\n{\n" << indent;
+ s << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR << ";\n"
+ << "if (!(";
+ writeTypeCheck(s, valueType, PYTHON_ARG), isNumber(valueType.typeEntry());
+ s << ")) {\n" << indent
+ << "Shiboken::Errors::setWrongContainerType();\n"
+ << "return {};\n" << outdent << "}\n";
+ writePythonToCppTypeConversion(s, valueType, PYTHON_ARG, CPP_ARG, nullptr, {});
+ s << "return " << CPP_ARG << ";\n" << outdent << "}\n" << outdent << "};\n\n";
+}
+
+// Generate code for a type wrapping a C++ container instantiation
+CppGenerator::OpaqueContainerData
+ CppGenerator::writeOpaqueContainerConverterFunctions(TextStream &s,
+ const AbstractMetaType &containerType,
+ QSet<AbstractMetaType> *valueTypes) const
+{
+ OpaqueContainerData result;
+ const auto &valueType = containerType.instantiations().constFirst();
+ const auto containerTypeEntry = std::static_pointer_cast<const ContainerTypeEntry>(containerType.typeEntry());
+ result.name =
+ containerTypeEntry->opaqueContainerName(containerType.instantiationCppSignatures());
+
+ const auto cppSignature = containerType.cppSignature();
+ s << "\n// Binding for " << cppSignature << "\n\n";
+
+ if (!valueTypes->contains(valueType)) {
+ valueTypes->insert(valueType);
+ writeOpaqueContainerValueConverter(s, valueType);
+ }
+
+ const QString privateObjType = u"ShibokenSequenceContainerPrivate<"_s
+ + cppSignature + u'>';
+
+ // methods
+ const QString &containerName = containerType.name();
+ const bool isStdVector = containerName == u"std::vector";
+ const auto kind = containerTypeEntry->containerKind();
+ const bool isFixed = kind == ContainerTypeEntry::SpanContainer || containerName == u"std::array";
+ const QString methods = result.name + u"_methods"_s;
+ s << "static PyMethodDef " << methods << "[] = {\n" << indent;
+ if (!isFixed) {
+ writeMethod(s, privateObjType, "push_back");
+ writeMethod(s, privateObjType, "push_back", "append"); // Qt convention
+ writeNoArgsMethod(s, privateObjType, "clear");
+ writeNoArgsMethod(s, privateObjType, "pop_back");
+ writeNoArgsMethod(s, privateObjType, "pop_back", "removeLast"); // Qt convention
+ if (!isStdVector) {
+ writeMethod(s, privateObjType, "push_front");
+ writeMethod(s, privateObjType, "push_front", "prepend"); // Qt convention
+ writeNoArgsMethod(s, privateObjType, "pop_front");
+ writeMethod(s, privateObjType, "pop_front", "removeFirst"); // Qt convention
+ }
+ writeMethod(s, privateObjType, "reserve"); // SFINAE'd out for list
+ writeNoArgsMethod(s, privateObjType, "capacity");
+ }
+ writeNoArgsMethod(s, privateObjType, "data");
+ writeNoArgsMethod(s, privateObjType, "constData");
+ s << "{nullptr, nullptr, 0, nullptr} // Sentinel\n"
+ << outdent << "};\n\n";
+
+ // slots
+ const QString slotsList = result.name + u"_slots"_s;
+ s << "static PyType_Slot " << slotsList << "[] = {\n" << indent;
+ writeSlot(s, privateObjType, "Py_tp_init", "tpInit");
+ const auto *tpNew = containerTypeEntry->viewOn() == nullptr ? "tpNew" : "tpNewInvalid";
+ writeSlot(s, privateObjType, "Py_tp_new", tpNew);
+ writeSlot(s, privateObjType, "Py_tp_free", "tpFree");
+ writeSlot(s, "Py_tp_dealloc", "Sbk_object_dealloc"); // FIXME?
+ writeSlot(s, "Py_tp_methods", methods.toUtf8().constData());
+ writeSlot(s, privateObjType, "Py_sq_ass_item", "sqSetItem");
+ writeSlot(s, privateObjType, "Py_sq_length", "sqLen");
+ writeSlot(s, privateObjType, "Py_sq_item", "sqGetItem");
+ s << "{0, nullptr}\n" << outdent << "};\n\n";
+
+ // spec
+ const QString specName = result.name + u"_spec"_s;
+ const QString name = TypeDatabase::instance()->defaultPackageName()
+ + u'.' + result.name;
+ s << "static PyType_Spec " << specName << " = {\n" << indent
+ << "\"" << name.count(u'.') << ':' << name << "\",\n"
+ << "sizeof(ShibokenContainer),\n0,\nPy_TPFLAGS_DEFAULT,\n"
+ << slotsList << outdent << "\n};\n\n";
+
+ // type creation function that sets a key in the type dict.
+ const QString typeCreationFName = u"create"_s + result.name + u"Type"_s;
+ s << "static inline PyTypeObject *" << typeCreationFName << "()\n{\n" << indent
+ << "auto *result = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&"
+ << specName << "));\nPy_INCREF(Py_True);\n"
+ << "Shiboken::AutoDecRef tpDict(PepType_GetDict(result));\n"
+ << "PyDict_SetItem(tpDict.object(), "
+ "Shiboken::PyMagicName::opaque_container(), Py_True);\n"
+ << "return result;\n" << outdent << "}\n\n";
+
+ // _TypeF() function
+ const QString typeFName = result.name + u"_TypeF"_s;
+ s << "static PyTypeObject *" << typeFName << "()\n{\n" << indent
+ << "static PyTypeObject *type = " << typeCreationFName
+ << "();\nreturn type;\n" << outdent << "}\n\n";
+
+ // creation functions from C++ references
+ ContainerCreationFlags flags;
+ if (kind == ContainerTypeEntry::SpanContainer)
+ flags.setFlag(ContainerCreationFlag::Allocate);
+
+ writeContainerCreationFunc(s, u"create"_s + result.name, typeFName,
+ containerType.cppSignature(), flags);
+ flags.setFlag(ContainerCreationFlag::Const);
+ writeContainerCreationFunc(s, u"createConst"_s + result.name, typeFName,
+ containerType.cppSignature(), flags);
+
+ // Check function
+ result.checkFunctionName = result.name + u"_Check"_s;
+ s << "extern \"C\" int " << result.checkFunctionName << "(PyObject *" << PYTHON_ARG
+ << ")\n{\n" << indent << "return " << PYTHON_ARG << " != nullptr && "
+ << PYTHON_ARG << " != Py_None && " << PYTHON_ARG << "->ob_type == "
+ << typeFName << "();\n" << outdent << "}\n\n";
+
+ // SBK converter Python to C++
+ result.pythonToConverterFunctionName = u"PythonToCpp"_s + result.name;
+ s << "extern \"C\" void " << result.pythonToConverterFunctionName
+ << "(PyObject *" << PYTHON_ARG << ", void *cppOut)\n{\n" << indent
+ << "auto *d = ShibokenSequenceContainerPrivate<" << cppSignature
+ << ">::get(" << PYTHON_ARG << ");\n"
+ << "*reinterpret_cast<" << cppSignature << "**>(cppOut) = d->m_list;\n"
+ << outdent << "}\n\n";
+
+ // SBK check function for converting Python to C++ that returns the converter
+ result.converterCheckFunctionName = u"is"_s + result.name + u"PythonToCppConvertible"_s;
+ s << "extern \"C\" PythonToCppFunc " << result.converterCheckFunctionName
+ << "(PyObject *" << PYTHON_ARG << ")\n{\n" << indent << "if ("
+ << result.checkFunctionName << '(' << PYTHON_ARG << "))\n" << indent
+ << "return " << result.pythonToConverterFunctionName << ";\n"
+ << outdent << "return {};\n" << outdent << "}\n\n";
+
+ QTextStream(&result.registrationCode) << "ob_type = reinterpret_cast<PyObject *>("
+ << typeFName
+ << "());\nPy_XINCREF(ob_type);\nPyModule_AddObject(module, \""
+ << result.name << "\", ob_type);\n";
+ return result;
+}
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
new file mode 100644
index 000000000..44b76f181
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
@@ -0,0 +1,476 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "cppgenerator.h"
+#include "generatorstrings.h"
+#include "generatorcontext.h"
+#include <apiextractorresult.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <codesnip.h>
+#include <exception.h>
+#include <messages.h>
+#include <textstream.h>
+#include <overloaddata.h>
+#include <smartpointertypeentry.h>
+
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+static const char smartPtrComment[] =
+ "// Try to find the 'name' attribute, by retrieving the PyObject for "
+ "the corresponding C++ object held by the smart pointer.\n";
+
+static QString smartPointerGetter(const GeneratorContext &context)
+{
+ const auto te = context.metaClass()->typeEntry();
+ Q_ASSERT(te->isSmartPointer());
+ return std::static_pointer_cast<const SmartPointerTypeEntry>(te)->getter();
+}
+
+struct callGetter
+{
+ explicit callGetter(const GeneratorContext &context) : m_context(context) {}
+
+ const GeneratorContext &m_context;
+};
+
+TextStream &operator<<(TextStream &str, const callGetter &c)
+{
+ str << "PyObject_CallMethod(self, \"" << smartPointerGetter(c.m_context) << "\", 0)";
+ return str;
+}
+
+// Helpers to collect all smart pointer pointee base classes
+static AbstractMetaClassCList
+ findSmartPointeeBaseClasses(const ApiExtractorResult &api,
+ const AbstractMetaType &smartPointerType)
+{
+ AbstractMetaClassCList result;
+ auto instantiationsTe = smartPointerType.instantiations().at(0).typeEntry();
+ auto targetClass = AbstractMetaClass::findClass(api.classes(), instantiationsTe);
+ if (targetClass != nullptr)
+ result = targetClass->allTypeSystemAncestors();
+ return result;
+}
+
+using ComparisonOperatorList = QList<AbstractMetaFunction::ComparisonOperatorType>;
+
+// Return the available comparison operators for smart pointers
+static ComparisonOperatorList smartPointeeComparisons(const GeneratorContext &context)
+{
+ Q_ASSERT(context.forSmartPointer());
+ auto te = context.preciseType().instantiations().constFirst().typeEntry();
+ if (isExtendedCppPrimitive(te)) { // Primitive pointee types have all
+ return {AbstractMetaFunction::OperatorEqual,
+ AbstractMetaFunction::OperatorNotEqual,
+ AbstractMetaFunction::OperatorLess,
+ AbstractMetaFunction::OperatorLessEqual,
+ AbstractMetaFunction::OperatorGreater,
+ AbstractMetaFunction::OperatorGreaterEqual};
+ }
+
+ const auto pointeeClass = context.pointeeClass();
+ if (!pointeeClass)
+ return {};
+
+ ComparisonOperatorList result;
+ const auto &comparisons =
+ pointeeClass->operatorOverloads(OperatorQueryOption::SymmetricalComparisonOp);
+ for (const auto &f : comparisons) {
+ const auto ct = f->comparisonOperatorType().value();
+ if (!result.contains(ct))
+ result.append(ct);
+ }
+ return result;
+}
+
+static bool hasParameterPredicate(const AbstractMetaFunctionCPtr &f)
+{
+ return !f->arguments().isEmpty();
+}
+
+void CppGenerator::generateSmartPointerClass(TextStream &s, const GeneratorContext &classContext)
+{
+ s.setLanguage(TextStream::Language::Cpp);
+ AbstractMetaClassCPtr metaClass = classContext.metaClass();
+ const auto typeEntry = std::static_pointer_cast<const SmartPointerTypeEntry>(metaClass->typeEntry());
+ const bool hasPointeeClass = classContext.pointeeClass() != nullptr;
+ const auto smartPointerType = typeEntry->smartPointerType();
+ const bool isValueHandle = smartPointerType ==TypeSystem::SmartPointerType::ValueHandle;
+
+ IncludeGroup includes{u"Extra includes"_s, typeEntry->extraIncludes()};
+ if (hasPointeeClass)
+ includes.append(classContext.pointeeClass()->typeEntry()->include());
+ includes.includes.append({Include::IncludePath, u"sbksmartpointer.h"_s});
+ generateIncludes(s, classContext, {includes});
+
+ s << '\n';
+
+ // class inject-code native/beginning
+ if (!typeEntry->codeSnips().isEmpty()) {
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
+ TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode,
+ classContext);
+ s << '\n';
+ }
+
+ StringStream smd(TextStream::Language::Cpp);
+ StringStream md(TextStream::Language::Cpp);
+ StringStream signatureStream(TextStream::Language::Cpp);
+
+ s << openTargetExternC;
+
+ const auto &functionGroups = getFunctionGroups(metaClass);
+
+ // Skip all public methods of the smart pointer except for the special
+ // methods declared in the type entry.
+
+ auto ctors = metaClass->queryFunctions(FunctionQueryOption::Constructors);
+ if (!hasPointeeClass && !isValueHandle) { // Cannot generate "int*"
+ auto end = std::remove_if(ctors.begin(), ctors.end(), hasParameterPredicate);
+ ctors.erase(end, ctors.end());
+ }
+
+ if (!ctors.isEmpty()) {
+ OverloadData overloadData(ctors, api());
+ writeConstructorWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ }
+
+ if (!typeEntry->resetMethod().isEmpty()) {
+ auto it = functionGroups.constFind(typeEntry->resetMethod());
+ if (it == functionGroups.cend())
+ throw Exception(msgCannotFindSmartPointerMethod(typeEntry, typeEntry->resetMethod()));
+ AbstractMetaFunctionCList resets = it.value();
+ if (!hasPointeeClass && !isValueHandle) { // Cannot generate "int*"
+ auto end = std::remove_if(resets.begin(), resets.end(), hasParameterPredicate);
+ resets.erase(end, resets.end());
+ }
+ if (!resets.isEmpty())
+ writeMethodWrapper(s, md, signatureStream, resets, classContext);
+ }
+
+ auto it = functionGroups.constFind(typeEntry->getter());
+ if (it == functionGroups.cend() || it.value().size() != 1)
+ throw Exception(msgCannotFindSmartPointerGetter(typeEntry));
+
+ writeMethodWrapper(s, md, signatureStream, it.value(), classContext);
+
+ QStringList optionalMethods;
+ if (!typeEntry->refCountMethodName().isEmpty())
+ optionalMethods.append(typeEntry->refCountMethodName());
+ const QString valueCheckMethod = typeEntry->valueCheckMethod();
+ if (!valueCheckMethod.isEmpty() && !valueCheckMethod.startsWith(u"operator"))
+ optionalMethods.append(valueCheckMethod);
+ if (!typeEntry->nullCheckMethod().isEmpty())
+ optionalMethods.append(typeEntry->nullCheckMethod());
+
+ for (const QString &optionalMethod : optionalMethods) {
+ auto it = functionGroups.constFind(optionalMethod);
+ if (it == functionGroups.cend() || it.value().size() != 1)
+ throw Exception(msgCannotFindSmartPointerMethod(typeEntry, optionalMethod));
+ writeMethodWrapper(s, md, signatureStream, it.value(), classContext);
+ }
+
+ writeCopyFunction(s, md, signatureStream, classContext);
+ writeSmartPointerDirFunction(s, md, signatureStream, classContext);
+
+ const QString methodsDefinitions = md.toString();
+ const QString singleMethodDefinitions = smd.toString();
+
+ const QString className = chopType(cpythonTypeName(typeEntry));
+
+ // Write single method definitions
+ s << singleMethodDefinitions;
+
+ // Write methods definition
+ writePyMethodDefs(s, className, methodsDefinitions);
+
+ // Write tp_s/getattro function
+ const auto boolCastOpt = boolCast(metaClass);
+ writeSmartPointerGetattroFunction(s, classContext, boolCastOpt);
+ writeSmartPointerSetattroFunction(s, classContext);
+
+ if (boolCastOpt.has_value())
+ writeNbBoolFunction(classContext, boolCastOpt.value(), s);
+
+ if (smartPointerType == TypeSystem::SmartPointerType::Shared)
+ writeSmartPointerRichCompareFunction(s, classContext);
+
+ s << closeExternC;
+
+ if (hasHashFunction(metaClass))
+ writeHashFunction(s, classContext);
+
+ // Write tp_traverse and tp_clear functions.
+ writeTpTraverseFunction(s, metaClass);
+ writeTpClearFunction(s, metaClass);
+
+ writeClassDefinition(s, metaClass, classContext);
+
+ s << '\n';
+
+ writeConverterFunctions(s, metaClass, classContext);
+ // Implicit smart pointers conversions
+ writeSmartPointerConverterFunctions(s, classContext.preciseType());
+ writeClassRegister(s, metaClass, classContext, signatureStream);
+
+ // class inject-code native/end
+ if (!typeEntry->codeSnips().isEmpty()) {
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
+ TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode,
+ classContext);
+ s << '\n';
+ }
+}
+
+void CppGenerator::writeSmartPointerConverterFunctions(TextStream &s,
+ const AbstractMetaType &smartPointerType) const
+{
+ const auto baseClasses = findSmartPointeeBaseClasses(api(), smartPointerType);
+ if (baseClasses.isEmpty())
+ return;
+
+ auto smartPointerTypeEntry =
+ std::static_pointer_cast<const SmartPointerTypeEntry>(smartPointerType.typeEntry());
+
+ // TODO: Missing conversion to smart pointer pointer type:
+
+ s << "// Register smartpointer conversion for all derived classes\n";
+ for (const auto &base : baseClasses) {
+ auto baseTe = base->typeEntry();
+ if (smartPointerTypeEntry->matchesInstantiation(baseTe)) {
+ if (auto opt = api().findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
+ const auto &smartTargetType = opt.value().type;
+ s << "// SmartPointer derived class: "
+ << smartTargetType.cppSignature() << "\n";
+ writePythonToCppConversionFunctions(s, smartPointerType,
+ smartTargetType, {}, {}, {});
+ }
+ }
+ }
+}
+
+void CppGenerator::writeSmartPointerCppSelfConversion(TextStream &s,
+ const GeneratorContext &context)
+{
+ Q_ASSERT(context.forSmartPointer());
+ s << cpythonWrapperCPtr(context.preciseType(), u"self"_s);
+}
+
+void CppGenerator::writeSmartPointerCppSelfDefinition(TextStream &s,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn,
+ CppSelfDefinitionFlags flags)
+{
+ Q_ASSERT(context.forSmartPointer());
+ writeInvalidPyObjectCheck(s, u"self"_s, errorReturn);
+ writeCppSelfVarDef(s, flags);
+ writeSmartPointerCppSelfConversion(s, context);
+ s << ";\n";
+}
+
+void CppGenerator::writeSmartPointerConverterInitialization(TextStream &s,
+ const AbstractMetaType &type) const
+{
+ const QByteArray cppSignature = type.cppSignature().toUtf8();
+ auto writeConversionRegister = [&s](const AbstractMetaType &sourceType,
+ const QString &targetTypeName,
+ const QString &targetConverter)
+ {
+ const QString sourceTypeName = fixedCppTypeName(sourceType);
+ const QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ const QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+
+ writeAddPythonToCppConversion(s, targetConverter, toCpp, isConv);
+ };
+
+ const auto classes = findSmartPointeeBaseClasses(api(), type);
+ if (classes.isEmpty())
+ return;
+
+ auto smartPointerTypeEntry = std::static_pointer_cast<const SmartPointerTypeEntry>(type.typeEntry());
+
+ s << "// Register SmartPointer converter for type '" << cppSignature << "'." << '\n'
+ << "///////////////////////////////////////////////////////////////////////////////////////\n\n";
+
+ for (const auto &base : classes) {
+ auto baseTe = base->typeEntry();
+ 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
+ + smartTargetType.cppSignature() + u"\")"_s;
+ writeConversionRegister(type, fixedCppTypeName(smartTargetType), converter);
+ } else {
+ s << "// Class not found:" << type.instantiations().at(0).cppSignature();
+ }
+ }
+
+ s << "///////////////////////////////////////////////////////////////////////////////////////" << '\n' << '\n';
+}
+
+void CppGenerator::writeSmartPointerRichCompareFunction(TextStream &s,
+ const GeneratorContext &context) const
+{
+ static const char selfPointeeVar[] = "cppSelfPointee";
+ static const char cppArg0PointeeVar[] = "cppArg0Pointee";
+
+ const auto metaClass = context.metaClass();
+ QString baseName = cpythonBaseName(metaClass);
+ writeRichCompareFunctionHeader(s, baseName, context);
+
+ s << "if (";
+ writeTypeCheck(s, context.preciseType(), PYTHON_ARG);
+ s << ") {\n" << indent;
+ writeArgumentConversion(s, context.preciseType(), CPP_ARG0,
+ PYTHON_ARG, ErrorReturn::Default, metaClass);
+
+ const auto te = context.preciseType().typeEntry();
+ Q_ASSERT(te->isSmartPointer());
+ const auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(te);
+
+ s << "const auto *" << selfPointeeVar << " = " << CPP_SELF_VAR
+ << '.' << ste->getter() << "();\n";
+ s << "const auto *" << cppArg0PointeeVar << " = " << CPP_ARG0
+ << '.' << ste->getter() << "();\n";
+
+ // If we have an object without any comparisons, only generate a simple
+ // equality check by pointee address
+ auto availableOps = smartPointeeComparisons(context);
+ const bool comparePointeeAddressOnly = availableOps.isEmpty();
+ if (comparePointeeAddressOnly) {
+ availableOps << AbstractMetaFunction::OperatorEqual
+ << AbstractMetaFunction::OperatorNotEqual;
+ } else {
+ // For value types with operators, we complain about nullptr
+ s << "if (" << selfPointeeVar << " == nullptr || " << cppArg0PointeeVar
+ << " == nullptr) {\n" << indent
+ << "PyErr_SetString(PyExc_NotImplementedError, \"nullptr passed to comparison.\");\n"
+ << ErrorReturn::Default << '\n' << outdent << "}\n";
+ }
+
+ s << "bool " << CPP_RETURN_VAR << "= false;\n"
+ << "switch (op) {\n";
+ for (auto op : availableOps) {
+ s << "case " << AbstractMetaFunction::pythonRichCompareOpCode(op) << ":\n"
+ << indent << CPP_RETURN_VAR << " = ";
+ if (comparePointeeAddressOnly) {
+ s << selfPointeeVar << ' ' << AbstractMetaFunction::cppComparisonOperator(op)
+ << ' ' << cppArg0PointeeVar << ";\n";
+ } else {
+ // Shortcut for equality: Check pointee address
+ if (op == AbstractMetaFunction::OperatorEqual
+ || op == AbstractMetaFunction::OperatorLessEqual
+ || op == AbstractMetaFunction::OperatorGreaterEqual) {
+ s << selfPointeeVar << " == " << cppArg0PointeeVar << " || ";
+ }
+ // Generate object's comparison
+ s << "*" << selfPointeeVar << ' '
+ << AbstractMetaFunction::cppComparisonOperator(op) << " *"
+ << cppArg0PointeeVar << ";\n";
+ }
+ s << "break;\n" << outdent;
+
+ }
+ if (availableOps.size() < 6) {
+ s << "default:\n" << indent
+ << richCompareComment
+ << "return FallbackRichCompare(self, " << PYTHON_ARG << ", op);\n" << outdent;
+ }
+ s << "}\n" << PYTHON_RETURN_VAR << " = " << CPP_RETURN_VAR
+ << " ? Py_True : Py_False;\n"
+ << "Py_INCREF(" << PYTHON_RETURN_VAR << ");\n"
+ << outdent << "}\n"
+ << "return Shiboken::returnFromRichCompare(" << PYTHON_RETURN_VAR << ");\n"
+ << outdent << "}\n\n";
+}
+
+void CppGenerator::writeSmartPointerSetattroFunction(TextStream &s,
+ const GeneratorContext &context)
+{
+ Q_ASSERT(context.forSmartPointer());
+ writeSetattroDefinition(s, context.metaClass());
+ s << smartPtrComment
+ << "if (auto *rawObj = " << callGetter(context) << ") {\n" << indent
+ << "if (PyObject_HasAttr(rawObj, name) != 0)\n" << indent
+ << "return PyObject_GenericSetAttr(rawObj, name, value);\n" << outdent
+ << "Py_DECREF(rawObj);\n" << outdent
+ << "}\n";
+ writeSetattroDefaultReturn(s);
+}
+
+void CppGenerator::writeSmartPointerGetattroFunction(TextStream &s,
+ const GeneratorContext &context,
+ const BoolCastFunctionOptional &boolCast)
+{
+ Q_ASSERT(context.forSmartPointer());
+ const auto metaClass = context.metaClass();
+ writeGetattroDefinition(s, metaClass);
+ s << "PyObject *tmp = PyObject_GenericGetAttr(self, name);\n"
+ << "if (tmp)\n" << indent << "return tmp;\n" << outdent
+ << "if (PyErr_ExceptionMatches(PyExc_AttributeError) == 0)\n"
+ << indent << "return nullptr;\n" << outdent
+ << "PyErr_Clear();\n";
+
+ if (boolCast.has_value()) {
+ writeSmartPointerCppSelfDefinition(s, context);
+ s << "if (";
+ writeNbBoolExpression(s, boolCast.value(), true /* invert */);
+ s << ") {\n" << indent
+ << R"(PyTypeObject *tp = Py_TYPE(self);
+PyErr_Format(PyExc_AttributeError, "Attempt to retrieve '%s' from null object '%s'.",
+ Shiboken::String::toCString(name), tp->tp_name);
+return nullptr;
+)" << outdent << "}\n";
+ }
+
+ // This generates the code which dispatches access to member functions
+ // and fields from the smart pointer to its pointee.
+ s << smartPtrComment
+ << "if (auto *rawObj = " << callGetter(context) << ") {\n" << indent
+ << "if (auto *attribute = PyObject_GetAttr(rawObj, name))\n"
+ << indent << "tmp = attribute;\n" << outdent
+ << "Py_DECREF(rawObj);\n" << outdent
+ << "}\n"
+ << "if (!tmp) {\n" << indent
+ << R"(PyTypeObject *tp = Py_TYPE(self);
+PyErr_Format(PyExc_AttributeError,
+ "'%.50s' object has no attribute '%.400s'",
+ tp->tp_name, Shiboken::String::toCString(name));
+)" << outdent
+ << "}\n"
+ << "return tmp;\n" << outdent << "}\n\n";
+}
+
+QString CppGenerator::writeSmartPointerReprFunction(TextStream &s,
+ const GeneratorContext &context)
+{
+ const auto metaClass = context.metaClass();
+ QString funcName = writeReprFunctionHeader(s, context);
+ s << "Shiboken::AutoDecRef pointee(" << callGetter(context) << ");\n"
+ << "return Shiboken::SmartPointer::repr(self, pointee);\n";
+ writeReprFunctionFooter(s);
+ return funcName;
+}
+
+QString CppGenerator::writeSmartPointerDirFunction(TextStream &s, TextStream &definitionStream,
+ TextStream &signatureStream,
+ const GeneratorContext &context)
+{
+ QString funcName = cpythonBaseName(context.metaClass()) + u"__dir__"_s;
+
+ signatureStream << fullPythonClassName(context.metaClass()) << ".__dir__()\n";
+ definitionStream << PyMethodDefEntry{u"__dir__"_s, funcName, {"METH_NOARGS"_ba}, {}}
+ << ",\n";
+
+ s << "extern \"C\"\n{\n"
+ << "static PyObject *" << funcName << "(PyObject *self)\n{\n" << indent
+ << "Shiboken::AutoDecRef pointee(" << callGetter(context) << ");\n"
+ << "return Shiboken::SmartPointer::dir(self, pointee);\n"
+ << outdent << "}\n} // extern C\n\n";
+ return funcName;
+}
diff --git a/sources/shiboken6/generator/shiboken/ctypenames.h b/sources/shiboken6/generator/shiboken/ctypenames.h
new file mode 100644
index 000000000..f665b30ff
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/ctypenames.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CTYPENAMES_H
+#define CTYPENAMES_H
+
+#include <QtCore/QString>
+
+constexpr auto boolT = QLatin1StringView("bool");
+constexpr auto intT = QLatin1StringView("int");
+constexpr auto unsignedT = QLatin1StringView("unsigned");
+constexpr auto unsignedIntT = QLatin1StringView("unsigned int");
+constexpr auto longT = QLatin1StringView("long");
+constexpr auto unsignedLongT = QLatin1StringView("unsigned long");
+constexpr auto shortT = QLatin1StringView("short");
+constexpr auto unsignedShortT = QLatin1StringView("unsigned short");
+constexpr auto unsignedCharT = QLatin1StringView("unsigned char");
+constexpr auto longLongT = QLatin1StringView("long long");
+constexpr auto unsignedLongLongT = QLatin1StringView("unsigned long long");
+constexpr auto charT = QLatin1StringView("char");
+constexpr auto floatT = QLatin1StringView("float");
+constexpr auto doubleT = QLatin1StringView("double");
+constexpr auto constCharPtrT = QLatin1StringView("const char*");
+
+constexpr auto qByteArrayT = QLatin1StringView("QByteArray");
+constexpr auto qMetaObjectT = QLatin1StringView("QMetaObject");
+constexpr auto qObjectT = QLatin1StringView("QObject");
+constexpr auto qStringT = QLatin1StringView("QString");
+constexpr auto qVariantT = QLatin1StringView("QVariant");
+
+#endif // CTYPENAMES_H
diff --git a/sources/shiboken6/generator/shiboken/generatorargument.cpp b/sources/shiboken6/generator/shiboken/generatorargument.cpp
new file mode 100644
index 000000000..e81ad0797
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/generatorargument.cpp
@@ -0,0 +1,110 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "generatorargument.h"
+#include <abstractmetatype.h>
+#include <messages.h>
+#include <typesystem.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QSet>
+
+static bool isCppPrimitiveString(const AbstractMetaType &type)
+{
+ return type.referenceType() == NoReference && type.indirections() == 1
+ && AbstractMetaType::cppSignedCharTypes().contains(type.name());
+}
+
+GeneratorArgument GeneratorArgument::fromMetaType(const AbstractMetaType &type)
+{
+ GeneratorArgument result;
+
+ const auto typeEntry = type.typeEntry();
+ if (typeEntry->isCustom() || typeEntry->isVarargs())
+ return result;
+
+ result.indirections = -type.indirectionsV().size();
+ if (isCppPrimitiveString(type)
+ || type.isVoidPointer()
+ || type.typeUsagePattern() == AbstractMetaType::NativePointerAsArrayPattern) {
+ result.indirections += 1;
+ }
+
+ if (typeEntry->isEnum()) {
+ result.type = Type::Enum;
+ } else if (typeEntry->isFlags()) {
+ result.type = Type::Flags;
+ } else if (typeEntry->isContainer()) {
+ result.type = Type::Container;
+ } else {
+ if (typeEntry->isPrimitive())
+ result.type = Type::Primitive;
+
+ const AbstractMetaTypeList &nestedArrayTypes = type.nestedArrayTypes();
+ if (!nestedArrayTypes.isEmpty()) {
+ if (nestedArrayTypes.constLast().isCppPrimitive()) {
+ result.type = Type::CppPrimitiveArray;
+ } else {
+ static QSet<QString> warnedTypes;
+ const QString &signature = type.cppSignature();
+ if (!warnedTypes.contains(signature)) {
+ warnedTypes.insert(signature);
+ qWarning("%s", qPrintable(msgUnknownArrayPointerConversion(signature)));
+ }
+ result.indirections -= 1;
+ }
+ }
+ }
+
+ if (result.type == Type::Other || result.type == Type::Primitive) {
+ if (type.valueTypeWithCopyConstructorOnlyPassed()) {
+ result.flags.setFlag(Flag::TreatAsPointer);
+ } else if ((type.isObjectType() || type.isPointer())
+ && !type.isUserPrimitive() && !type.isExtendedCppPrimitive()) {
+ result.flags.setFlag(Flag::PointerOrObjectType);
+ } else if (type.referenceType() == LValueReference
+ && !type.isUserPrimitive()
+ && !type.isExtendedCppPrimitive()) {
+ result.flags.setFlag(Flag::MayHaveImplicitConversion);
+ }
+ }
+
+ // For implicit conversions or containers, either value or pointer conversion
+ // may occur. An implicit conversion uses value conversion whereas the object
+ // itself uses pointer conversion. For containers, the PyList/container
+ // conversion is by value whereas opaque containers use pointer conversion.
+ // For a container passed by pointer, a local variable is also needed.
+ if (result.flags.testFlag(Flag::MayHaveImplicitConversion)
+ || type.generateOpaqueContainer()
+ || (result.type == Type::Container && result.indirections != 0)) {
+ result.flags.setFlag(Flag::ValueOrPointer);
+ }
+
+ if (result.type == Type::CppPrimitiveArray) {
+ result.conversion = Conversion::CppPrimitiveArray;
+ } else if (result.flags.testFlag(Flag::ValueOrPointer)) {
+ result.conversion = Conversion::ValueOrPointer;
+ ++result.indirections;
+ } else if (result.flags.testAnyFlags(Flag::TreatAsPointer | Flag::PointerOrObjectType)) {
+ result.conversion = Conversion::Pointer;
+ ++result.indirections;
+ }
+
+ return result;
+}
+
+QDebug operator<<(QDebug debug, const GeneratorArgument &a)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "GeneratorArgument(" << a.type;
+ if (a.conversion != GeneratorArgument::Conversion::Default)
+ debug << ", conversion=" << a.conversion;
+ if (a.flags)
+ debug << ", flags(" << a.flags;
+ if (a.indirections != 0)
+ debug << ", indirections=" << a.indirections;
+ debug << ')';
+ return debug;
+}
diff --git a/sources/shiboken6/generator/shiboken/generatorargument.h b/sources/shiboken6/generator/shiboken/generatorargument.h
new file mode 100644
index 000000000..385ad0f63
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/generatorargument.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef GENERATORARGUMENT_H
+#define GENERATORARGUMENT_H
+
+#include <QtCore/QFlags>
+#include <QtCore/qobjectdefs.h>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class AbstractMetaType;
+
+/// A struct containing information on how the generator processes a function argument.
+struct GeneratorArgument
+{
+ Q_GADGET
+
+public:
+ enum class Type {
+ Other,
+ Primitive,
+ Enum,
+ Flags,
+ Container,
+ CppPrimitiveArray
+ };
+ Q_ENUM(Type)
+
+ enum class Conversion {
+ Default,
+ CppPrimitiveArray, // Similar to Default except default values
+ Pointer,
+ ValueOrPointer
+ };
+ Q_ENUM(Conversion)
+
+ enum class Flag {
+ TreatAsPointer = 0x1,
+ PointerOrObjectType = 0x2,
+ MayHaveImplicitConversion = 0x4,
+ ValueOrPointer = 0x8,
+ };
+ Q_ENUM(Flag)
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ static GeneratorArgument fromMetaType(const AbstractMetaType &type);
+
+ Flags flags;
+ /// Indirections from generated "cppArg<n>" variable to function argument.
+ qsizetype indirections = 0;
+ Type type = Type::Other;
+ Conversion conversion = Conversion::Default;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(GeneratorArgument::Flags)
+
+QDebug operator<<(QDebug debug, const GeneratorArgument &a);
+
+#endif // GENERATORARGUMENT_H
diff --git a/sources/shiboken6/generator/shiboken/generatorstrings.h b/sources/shiboken6/generator/shiboken/generatorstrings.h
new file mode 100644
index 000000000..9ce91e599
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/generatorstrings.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef GENERATORSTRINGS_H
+#define GENERATORSTRINGS_H
+
+#include <QtCore/QString>
+
+QString CPP_ARG_N(int i);
+QString CPP_ARG_REMOVED(int i);
+
+constexpr auto CPP_RETURN_VAR = QLatin1StringView("cppResult");
+constexpr auto CPP_SELF_VAR = QLatin1StringView("cppSelf");
+constexpr auto CPP_ARG = QLatin1StringView("cppArg");
+constexpr auto NULL_PTR = QLatin1StringView("nullptr");
+constexpr auto PYTHON_ARG = QLatin1StringView("pyArg");
+constexpr auto PYTHON_ARGS = QLatin1StringView("pyArgs");
+constexpr auto PYTHON_OVERRIDE_VAR = QLatin1StringView("pyOverride");
+constexpr auto PYTHON_RETURN_VAR = QLatin1StringView("pyResult");
+constexpr auto PYTHON_SELF_VAR = QLatin1StringView("self");
+constexpr auto PYTHON_TO_CPP_VAR = QLatin1StringView("pythonToCpp");
+
+constexpr auto CONV_RULE_OUT_VAR_SUFFIX = QLatin1StringView("_out");
+constexpr auto BEGIN_ALLOW_THREADS
+ = QLatin1StringView("PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS");
+constexpr auto END_ALLOW_THREADS
+ = QLatin1StringView("PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS");
+
+constexpr auto REPR_FUNCTION = QLatin1StringView("__repr__");
+
+constexpr auto CPP_ARG0 = QLatin1StringView("cppArg0");
+
+extern const char *const METHOD_DEF_SENTINEL;
+extern const char *const PYTHON_TO_CPPCONVERSION_STRUCT;
+extern const char *const openTargetExternC;
+extern const char *const closeExternC;
+extern const char *const richCompareComment;
+
+#endif // GENERATORSTRINGS_H
diff --git a/sources/shiboken6/generator/shiboken/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp
new file mode 100644
index 000000000..7cec9c38e
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp
@@ -0,0 +1,961 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "headergenerator.h"
+#include "configurablescope.h"
+#include "generatorcontext.h"
+#include <apiextractorresult.h>
+#include <abstractmetaargument.h>
+#include <abstractmetaenum.h>
+#include <abstractmetafield.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetalang_helpers.h>
+#include <codesnip.h>
+#include <clangparser/compilersupport.h>
+#include <exception.h>
+#include <typedatabase.h>
+#include <reporthandler.h>
+#include <textstream.h>
+#include <fileout.h>
+#include "containertypeentry.h"
+#include "enumtypeentry.h"
+#include "flagstypeentry.h"
+#include <messages.h>
+#include "namespacetypeentry.h"
+#include "primitivetypeentry.h"
+#include "typedefentry.h"
+#include "typesystemtypeentry.h"
+
+#include "qtcompat.h"
+
+#include <algorithm>
+#include <set>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QVariant>
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+struct IndexValue
+{
+ QString name; // "SBK_..."
+ int value;
+ QString comment;
+};
+
+TextStream &operator<<(TextStream &s, const IndexValue &iv)
+{
+ s << " " << AlignedField(iv.name, 56) << " = " << iv.value << ',';
+ if (!iv.comment.isEmpty())
+ s << " // " << iv.comment;
+ s << '\n';
+ return s;
+}
+
+// PYSIDE-504: Handling the "protected hack"
+// The problem: Creating wrappers when the class has private destructors.
+// You can see an example on Windows in qclipboard_wrapper.h and others.
+// Simply search for the text "// C++11: need to declare (unimplemented) destructor".
+// The protected hack is the definition "#define protected public".
+// For most compilers, this "hack" is enabled, because the problem of private
+// destructors simply vanishes.
+//
+// If one does not want to use this hack, then a new problem arises:
+// C++11 requires that a destructor is declared in a wrapper class when it is
+// private in the base class. There is no implementation allowed!
+//
+// Unfortunately, MSVC in recent versions supports C++11, and due to restrictive
+// rules, it is impossible to use the hack with this compiler.
+// More unfortunate: Clang, when C++11 is enabled, also enforces a declaration
+// of a private destructor, but it falsely then creates a linker error!
+//
+// Originally, we wanted to remove the protected hack. But due to the Clang
+// problem, we gave up on removal of the protected hack and use it always
+// when we can. This might change again when the Clang problem is solved.
+
+static bool alwaysGenerateDestructorDeclaration()
+{
+ return clang::compiler() == Compiler::Msvc;
+}
+
+const char *HeaderGenerator::protectedHackDefine = R"(// Workaround to access protected functions
+#ifndef protected
+# define protected public
+#endif
+
+)";
+
+QString HeaderGenerator::fileNameForContext(const GeneratorContext &context) const
+{
+ return headerFileNameForContext(context);
+}
+
+void HeaderGenerator::writeCopyCtor(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ s << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName()
+ << "& self) : " << metaClass->qualifiedCppName() << "(self)\n{\n}\n\n";
+}
+
+static void writeProtectedEnums(TextStream &s, const AbstractMetaClassCPtr &metaClass)
+{
+ const QString name = metaClass->qualifiedCppName();
+ for (const auto &e : metaClass->enums()) {
+ if (e.isProtected())
+ s << "using " << name << "::" << e.name() << ";\n";
+ }
+}
+
+void HeaderGenerator::generateClass(TextStream &s, const GeneratorContext &classContext)
+{
+ const AbstractMetaClassCPtr metaClass = classContext.metaClass();
+
+ // write license comment
+ s << licenseComment();
+
+ QString wrapperName = classContext.effectiveClassName();
+ QString outerHeaderGuard = getFilteredCppSignatureString(wrapperName);
+
+ // Header
+ s << "#ifndef SBK_" << outerHeaderGuard << "_H\n";
+ s << "#define SBK_" << outerHeaderGuard << "_H\n\n";
+
+ if (!avoidProtectedHack())
+ s << protectedHackDefine;
+
+ // Includes
+ s << metaClass->typeEntry()->include() << '\n';
+ for (auto &inst : metaClass->templateBaseClassInstantiations())
+ s << inst.typeEntry()->include();
+
+ if (classContext.useWrapper())
+ writeWrapperClass(s, wrapperName, classContext);
+
+ s << "#endif // SBK_" << outerHeaderGuard << "_H\n\n";
+}
+
+void HeaderGenerator::writeWrapperClass(TextStream &s,
+ const QString &wrapperName,
+ const GeneratorContext &classContext) const
+{
+ const auto metaClass = classContext.metaClass();
+
+ if (avoidProtectedHack()) {
+ const auto includeGroups = classIncludes(metaClass);
+ for( const auto &includeGroup : includeGroups)
+ s << includeGroup;
+ }
+
+ if (usePySideExtensions() && isQObject(metaClass))
+ s << "namespace PySide { class DynamicQMetaObject; }\n\n";
+
+ writeWrapperClassDeclaration(s, wrapperName, classContext);
+
+ // PYSIDE-500: Use also includes for inherited wrapper classes other
+ // modules, because without the protected hack, we sometimes need to
+ // cast inherited wrappers. CppGenerator generates include statements for
+ // the classes of the current module. For other modules, we insert the
+ // declarations as recursive headers, since wrapper headers are not
+ // installed. This keeps the file structure as simple as before the
+ // enhanced inheritance.
+ if (avoidProtectedHack()) {
+ const auto &baseClasses = allBaseClasses(classContext.metaClass());
+ for (const auto &baseClass : baseClasses) {
+ const auto gen = baseClass->typeEntry()->codeGeneration();
+ if (gen == TypeEntry::GenerateForSubclass) { // other module
+ const auto baseContext = contextForClass(baseClass);
+ if (baseContext.useWrapper())
+ writeInheritedWrapperClassDeclaration(s, baseContext);
+ }
+ }
+ }
+}
+
+void HeaderGenerator::writeInheritedWrapperClassDeclaration(TextStream &s,
+ const GeneratorContext &classContext) const
+{
+ const QString wrapperName = classContext.effectiveClassName();
+ const QString innerHeaderGuard =
+ getFilteredCppSignatureString(wrapperName).toUpper();
+
+ s << "# ifndef SBK_" << innerHeaderGuard << "_H\n"
+ << "# define SBK_" << innerHeaderGuard << "_H\n\n"
+ << "// Inherited base class:\n";
+
+ writeWrapperClassDeclaration(s, wrapperName, classContext);
+
+ s << "# endif // SBK_" << innerHeaderGuard << "_H\n\n";
+}
+
+void HeaderGenerator::writeWrapperClassDeclaration(TextStream &s,
+ const QString &wrapperName,
+ const GeneratorContext &classContext) const
+{
+ const AbstractMetaClassCPtr metaClass = classContext.metaClass();
+ const auto typeEntry = metaClass->typeEntry();
+ InheritedOverloadSet inheritedOverloads;
+
+ // Class
+ s << "class " << wrapperName
+ << " : public " << metaClass->qualifiedCppName()
+ << "\n{\npublic:\n" << indent
+ << wrapperName << "(const " << wrapperName << " &) = delete;\n"
+ << wrapperName << "& operator=(const " << wrapperName << " &) = delete;\n"
+ << wrapperName << '(' << wrapperName << " &&) = delete;\n"
+ << wrapperName << "& operator=(" << wrapperName << " &&) = delete;\n\n";
+
+ // Make protected enums accessible
+ if (avoidProtectedHack()) {
+ recurseClassHierarchy(metaClass, [&s] (const AbstractMetaClassCPtr &metaClass) {
+ writeProtectedEnums(s, metaClass);
+ return false;
+ });
+ }
+
+ if (avoidProtectedHack() && metaClass->hasProtectedFields()) {
+ s << "\n// Make protected fields accessible\n";
+ const QString name = metaClass->qualifiedCppName();
+ for (const auto &f : metaClass->fields()) {
+ if (f.isProtected())
+ s << "using " << name << "::" << f.originalName() << ";\n";
+ }
+ s << '\n';
+ }
+
+ int maxOverrides = 0;
+ for (const auto &func : metaClass->functions()) {
+ const auto generation = functionGeneration(func);
+ writeFunction(s, func, &inheritedOverloads, generation);
+ // PYSIDE-803: Build a boolean cache for unused overrides.
+ if (generation.testFlag(FunctionGenerationFlag::VirtualMethod))
+ maxOverrides++;
+ }
+ if (!maxOverrides)
+ maxOverrides = 1;
+
+ //destructor
+ // PYSIDE-504: When C++ 11 is used, then the destructor must always be declared.
+ if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()
+ || alwaysGenerateDestructorDeclaration()) {
+ if (avoidProtectedHack() && metaClass->hasPrivateDestructor())
+ s << "// C++11: need to declare (unimplemented) destructor because "
+ "the base class destructor is private.\n";
+ s << '~' << wrapperName << "()";
+ if (metaClass->hasVirtualDestructor())
+ s << " override";
+ s << ";\n";
+ }
+
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
+ TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode,
+ classContext);
+
+ if (shouldGenerateMetaObjectFunctions(metaClass)) {
+ s << R"(
+const ::QMetaObject * metaObject() const override;
+int qt_metacall(QMetaObject::Call call, int id, void **args) override;
+void *qt_metacast(const char *_clname) override;
+)";
+ }
+
+ if (!inheritedOverloads.isEmpty()) {
+ s << "// Inherited overloads, because the using keyword sux\n";
+ for (const auto &func : std::as_const(inheritedOverloads))
+ writeMemberFunctionWrapper(s, func);
+ }
+
+ if (usePySideExtensions())
+ s << "static void pysideInitQtMetaTypes();\n";
+
+ s << "void resetPyMethodCache();\n"
+ << outdent << "private:\n" << indent;
+
+ if (!metaClass->userAddedPythonOverrides().isEmpty()) {
+ for (const auto &f : metaClass->userAddedPythonOverrides())
+ s << functionSignature(f, {}, {}, Generator::OriginalTypeDescription) << ";\n";
+ s << '\n';
+ }
+
+ s << "mutable bool m_PyMethodCache[" << maxOverrides << "];\n"
+ << outdent << "};\n\n";
+}
+
+// Write an inline wrapper around a function
+void HeaderGenerator::writeMemberFunctionWrapper(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const QString &postfix) const
+{
+ Q_ASSERT(!func->isConstructor() && !func->isOperatorOverload());
+ s << "inline ";
+ s << functionSignature(func, {}, postfix, Generator::OriginalTypeDescription)
+ << " { ";
+ if (!func->isVoid())
+ s << "return ";
+ if (!func->isAbstract()) {
+ // Use implementingClass() in case of multiple inheritance (for example
+ // function setProperty() being inherited from QObject and
+ // QDesignerPropertySheetExtension).
+ auto klass = func->implementingClass();
+ if (klass == nullptr)
+ klass = func->ownerClass();
+ s << klass->qualifiedCppName() << "::";
+ }
+ s << func->originalName() << '(';
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (qsizetype i = 0, size = arguments.size(); i < size; ++i) {
+ if (i > 0)
+ s << ", ";
+ const AbstractMetaArgument &arg = arguments.at(i);
+ const auto &type = arg.type();
+ TypeEntryCPtr enumTypeEntry;
+ if (type.isFlags())
+ enumTypeEntry = std::static_pointer_cast<const FlagsTypeEntry>(type.typeEntry())->originator();
+ else if (type.isEnum())
+ enumTypeEntry = type.typeEntry();
+ if (enumTypeEntry) {
+ s << type.cppSignature() << '(' << arg.name() << ')';
+ } else if (type.passByValue() && type.isUniquePointer()) {
+ s << stdMove(arg.name());
+ } else {
+ s << arg.name();
+ }
+ }
+ s << "); }\n";
+}
+
+void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ InheritedOverloadSet *inheritedOverloads,
+ FunctionGeneration generation) const
+{
+
+ // do not write copy ctors here.
+ if (generation.testFlag(FunctionGenerationFlag::WrapperSpecialCopyConstructor)) {
+ writeCopyCtor(s, func->ownerClass());
+ return;
+ }
+
+ if (generation.testFlag(FunctionGenerationFlag::ProtectedWrapper))
+ writeMemberFunctionWrapper(s, func, u"_protected"_s);
+
+ if (generation.testFlag(FunctionGenerationFlag::WrapperConstructor)) {
+ Options option = func->hasSignatureModifications()
+ ? Generator::OriginalTypeDescription : Generator::NoOption;
+ s << functionSignature(func, {}, {}, option) << ";\n";
+ return;
+ }
+
+ const bool isVirtual = generation.testFlag(FunctionGenerationFlag::VirtualMethod);
+ if (isVirtual) {
+ s << functionSignature(func, {}, {}, Generator::OriginalTypeDescription)
+ << " override;\n";
+ }
+
+ // Check if this method hide other methods in base classes
+ if (isVirtual) {
+ for (const auto &f : func->ownerClass()->functions()) {
+ if (f != func
+ && !f->isConstructor()
+ && !f->isPrivate()
+ && !f->isVirtual()
+ && !f->isAbstract()
+ && !f->isStatic()
+ && f->name() == func->name()) {
+ inheritedOverloads->insert(f);
+ }
+ }
+
+ // TODO: when modified an abstract method ceases to be virtual but stays abstract
+ //if (func->isModifiedRemoved() && func->isAbstract()) {
+ //}
+ }
+}
+
+// Find equivalent typedefs "using Foo=QList<int>", "using Bar=QList<int>"
+static AbstractMetaClassCPtr
+ findEquivalentTemplateTypedef(const AbstractMetaClassCList &haystack,
+ const AbstractMetaClassCPtr &needle)
+{
+ auto templateBaseClass = needle->templateBaseClass();
+ const auto &instantiations = needle->templateBaseClassInstantiations();
+ for (const auto &candidate : haystack) {
+ if (candidate->isTypeDef()
+ && candidate->templateBaseClass() == templateBaseClass
+ && candidate->templateBaseClassInstantiations() == instantiations) {
+ return candidate;
+ }
+ }
+ return nullptr;
+}
+
+void HeaderGenerator::collectTypeEntryTypeIndexes(const ApiExtractorResult &api,
+ const TypeEntryCPtr &typeEntry,
+ IndexValues *indexValues)
+{
+ if (!typeEntry || !typeEntry->generateCode())
+ return;
+ const int typeIndex = typeEntry->sbkIndex();
+ indexValues->append({getTypeIndexVariableName(typeEntry), typeIndex, {}});
+
+ if (typeEntry->isComplex()) {
+ // For a typedef "using Foo=QList<int>", write a type index
+ // SBK_QLIST_INT besides SBK_FOO which is then matched by function
+ // argument. Check against duplicate typedefs for the same types.
+ const auto cType = std::static_pointer_cast<const ComplexTypeEntry>(typeEntry);
+ if (cType->baseContainerType()) {
+ auto metaClass = AbstractMetaClass::findClass(api.classes(), cType);
+ Q_ASSERT(metaClass != nullptr);
+ if (metaClass->isTypeDef()
+ && metaClass->templateBaseClass() != nullptr
+ && findEquivalentTemplateTypedef(m_alternateTemplateIndexes,
+ metaClass) == nullptr) {
+ const QString indexVariable =
+ getTypeAlternateTemplateIndexVariableName(metaClass);
+ indexValues->append({indexVariable, typeIndex, {}});
+ m_alternateTemplateIndexes.append(m_alternateTemplateIndexes);
+ }
+ }
+ }
+ if (typeEntry->isEnum()) {
+ auto ete = std::static_pointer_cast<const EnumTypeEntry>(typeEntry);
+ if (ete->flags())
+ collectTypeEntryTypeIndexes(api, ete->flags(), indexValues);
+ }
+}
+
+void HeaderGenerator::collectClassTypeIndexes(const ApiExtractorResult &api,
+ const AbstractMetaClassCPtr &metaClass,
+ IndexValues *indexValues)
+{
+ auto typeEntry = metaClass->typeEntry();
+ if (!typeEntry->generateCode())
+ return;
+ // enum indices are required for invisible namespaces as well.
+ for (const AbstractMetaEnum &metaEnum : metaClass->enums()) {
+ if (!metaEnum.isPrivate())
+ collectTypeEntryTypeIndexes(api, metaEnum.typeEntry(), indexValues);
+ }
+ if (NamespaceTypeEntry::isVisibleScope(typeEntry))
+ collectTypeEntryTypeIndexes(api, typeEntry, indexValues);
+}
+
+// Format the typedefs for the typedef entries to be generated
+static void formatTypeDefEntries(TextStream &s)
+{
+ QList<TypedefEntryCPtr> entries;
+ const auto typeDbEntries = TypeDatabase::instance()->typedefEntries();
+ for (auto it = typeDbEntries.cbegin(), end = typeDbEntries.cend(); it != end; ++it) {
+ if (it.value()->generateCode() != 0)
+ entries.append(it.value());
+ }
+ if (entries.isEmpty())
+ return;
+ s << "\n// typedef entries\n";
+ for (const auto &e : entries) {
+ const QString name = e->qualifiedCppName();
+ // Fixme: simplify by using nested namespaces in C++ 17.
+ const auto components = QStringView{name}.split(u"::");
+ const auto nameSpaceCount = components.size() - 1;
+ for (qsizetype n = 0; n < nameSpaceCount; ++n)
+ s << "namespace " << components.at(n) << " {\n";
+ s << "using " << components.constLast() << " = " << e->sourceType() << ";\n";
+ for (qsizetype n = 0; n < nameSpaceCount; ++n)
+ s << "}\n";
+ }
+ s << '\n';
+}
+
+// Helpers for forward-declaring classes in the module header for the
+// specialization of the SbkType template functions. This is possible if the
+// class does not have inner types or enums which need to be known.
+static bool canForwardDeclare(const AbstractMetaClassCPtr &c)
+{
+ if (c->isNamespace() || !c->enums().isEmpty()
+ || !c->innerClasses().isEmpty() || c->isTypeDef()) {
+ return false;
+ }
+ if (auto encl = c->enclosingClass())
+ return encl->isNamespace();
+ return true;
+}
+
+static void writeForwardDeclaration(TextStream &s, const AbstractMetaClassCPtr &c)
+{
+ Q_ASSERT(!c->isNamespace());
+ const bool isStruct = c->attributes().testFlag(AbstractMetaClass::Struct);
+ s << (isStruct ? "struct " : "class ");
+ // Do not use name as this can be modified/renamed for target lang.
+ const QString qualifiedCppName = c->qualifiedCppName();
+ const auto lastQualifier = qualifiedCppName.lastIndexOf(u':');
+ if (lastQualifier != -1)
+ s << QStringView{qualifiedCppName}.mid(lastQualifier + 1);
+ else
+ s << qualifiedCppName;
+ s << ";\n";
+}
+
+// Helpers for writing out namespaces hierarchically when writing class
+// forward declarations to the module header. Ensure inline namespaces
+// are marked as such (else clang complains) and namespaces are ordered.
+struct NameSpace {
+ AbstractMetaClassCPtr nameSpace;
+ AbstractMetaClassCList classes;
+};
+
+static bool operator<(const NameSpace &n1, const NameSpace &n2)
+{
+ return n1.nameSpace->name() < n2.nameSpace->name();
+}
+
+using NameSpaces = QList<NameSpace>;
+
+static qsizetype indexOf(const NameSpaces &nsps, const AbstractMetaClassCPtr &needle)
+{
+ for (qsizetype i = 0, count = nsps.size(); i < count; ++i) {
+ if (nsps.at(i).nameSpace == needle)
+ return i;
+ }
+ return -1;
+}
+
+static void writeNamespaceForwardDeclarationRecursion(TextStream &s, qsizetype idx,
+ const NameSpaces &nameSpaces)
+{
+ auto &root = nameSpaces.at(idx);
+ s << '\n';
+ if (root.nameSpace->isInlineNamespace())
+ s << "inline ";
+ s << "namespace " << root.nameSpace->name() << " {\n" << indent;
+ for (const auto &c : root.classes)
+ writeForwardDeclaration(s, c);
+
+ for (qsizetype i = 0, count = nameSpaces.size(); i < count; ++i) {
+ if (i != idx && nameSpaces.at(i).nameSpace->enclosingClass() == root.nameSpace)
+ writeNamespaceForwardDeclarationRecursion(s, i, nameSpaces);
+ }
+ s << outdent << "}\n";
+}
+
+static void writeForwardDeclarations(TextStream &s,
+ const AbstractMetaClassCList &classList)
+{
+ NameSpaces nameSpaces;
+
+ s << '\n';
+ auto typeSystemEntry = TypeDatabase::instance()->defaultTypeSystemType();
+ if (!typeSystemEntry->namespaceBegin().isEmpty())
+ s << typeSystemEntry->namespaceBegin() << '\n';
+
+ for (const auto &c : classList) {
+ if (auto encl = c->enclosingClass()) {
+ Q_ASSERT(encl->isNamespace());
+ auto idx = indexOf(nameSpaces, encl);
+ if (idx != -1) {
+ nameSpaces[idx].classes.append(c);
+ } else {
+ nameSpaces.append(NameSpace{encl, {c}});
+ for (auto enclNsp = encl->enclosingClass(); enclNsp;
+ enclNsp = enclNsp->enclosingClass()) {
+ idx = indexOf(nameSpaces, enclNsp);
+ if (idx == -1)
+ nameSpaces.append(NameSpace{enclNsp, {}});
+ }
+ }
+ } else {
+ writeForwardDeclaration(s, c);
+ }
+ }
+
+ std::sort(nameSpaces.begin(), nameSpaces.end());
+
+ // Recursively write out namespaces starting at the root elements.
+ for (qsizetype i = 0, count = nameSpaces.size(); i < count; ++i) {
+ const auto &nsp = nameSpaces.at(i);
+ if (nsp.nameSpace->enclosingClass() == nullptr)
+ writeNamespaceForwardDeclarationRecursion(s, i, nameSpaces);
+ }
+
+ if (!typeSystemEntry->namespaceEnd().isEmpty())
+ s << typeSystemEntry->namespaceEnd() << '\n';
+}
+
+// Include parameters required for the module/private module header
+
+using ConditionalIncludeMap = QMap<QString, IncludeGroup>;
+
+static TextStream &operator<<(TextStream &s, const ConditionalIncludeMap &m)
+{
+ for (auto it = m.cbegin(), end = m.cend(); it != end; ++it)
+ s << it.key() << '\n' << it.value() << "#endif\n";
+ return s;
+}
+
+struct ModuleHeaderParameters
+{
+ AbstractMetaClassCList forwardDeclarations;
+ std::set<Include> includes;
+ ConditionalIncludeMap conditionalIncludes;
+ QString typeFunctions;
+};
+
+HeaderGenerator::IndexValues
+ HeaderGenerator::collectTypeIndexes(const AbstractMetaClassCList &classList)
+{
+ IndexValues result;
+
+ for (const auto &metaClass : classList)
+ collectClassTypeIndexes(api(), metaClass, &result);
+
+ for (const AbstractMetaEnum &metaEnum : api().globalEnums())
+ collectTypeEntryTypeIndexes(api(), metaEnum.typeEntry(), &result);
+
+ // Write the smart pointer define indexes.
+ int smartPointerCountIndex = getMaxTypeIndex();
+ int smartPointerCount = 0;
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ QString indexName = getTypeIndexVariableName(smp.type);
+ result.append({indexName, smartPointerCountIndex, smp.type.cppSignature()});
+ // Add a the same value for const pointees (shared_ptr<const Foo>).
+ const auto ptrName = smp.type.typeEntry()->entryName();
+ const auto pos = indexName.indexOf(ptrName, 0, Qt::CaseInsensitive);
+ if (pos >= 0) {
+ indexName.insert(pos + ptrName.size() + 1, u"const"_s);
+ result.append({indexName, smartPointerCountIndex, "(const)"_L1});
+ }
+ ++smartPointerCountIndex;
+ ++smartPointerCount;
+ }
+ result.append({"SBK_"_L1 + moduleName() + "_IDX_COUNT"_L1,
+ getMaxTypeIndex() + smartPointerCount, {}});
+ return result;
+}
+
+HeaderGenerator::IndexValues HeaderGenerator::collectConverterIndexes() const
+{
+ IndexValues result;
+ const auto &primitives = primitiveTypes();
+ int pCount = 0;
+ for (const auto &ptype : primitives) {
+ // Note: do not generate indices for typedef'd primitive types as
+ // they'll use the primitive type converters instead, so we
+ // don't need to create any other.
+ if (ptype->generateCode() && ptype->customConversion() != nullptr)
+ result.append({getTypeIndexVariableName(ptype), pCount++, {}});
+ }
+
+ for (const AbstractMetaType &container : api().instantiatedContainers()) {
+ result.append({getTypeIndexVariableName(container),
+ pCount++, container.cppSignature()});
+ }
+
+ // Because on win32 the compiler will not accept a zero length array.
+ if (pCount == 0)
+ pCount++;
+ result.append({"SBK_"_L1 + moduleName() + "_CONVERTERS_IDX_COUNT"_L1,
+ pCount, {}});
+ return result;
+}
+
+// PYSIDE-2404: Write the enums in unchanged case for reuse in type imports.
+// For conpatibility, we create them in uppercase, too and with
+// doubled index for emulating the former type-only case.
+//
+// FIXME: Remove in PySide 7. (See the note in `parser.py`)
+//
+static IndexValue typeIndexUpper(struct IndexValue const &ti)
+{
+ QString modi = ti.name.toUpper();
+ if (modi == ti.name)
+ modi = u"// "_s + modi;
+ return {modi, ti.value * 2, ti.comment};
+}
+
+bool HeaderGenerator::finishGeneration()
+{
+ // Generate the main header for this module. This header should be included
+ // by binding modules extending on top of this one.
+ ModuleHeaderParameters parameters;
+ ModuleHeaderParameters privateParameters;
+ StringStream macrosStream(TextStream::Language::Cpp);
+
+ const auto snips = TypeDatabase::instance()->defaultTypeSystemType()->codeSnips();
+ writeModuleCodeSnips(macrosStream, snips, TypeSystem::CodeSnipPositionDeclaration,
+ TypeSystem::TargetLangCode);
+
+ auto classList = api().classes();
+
+ std::sort(classList.begin(), classList.end(),
+ [](const AbstractMetaClassCPtr &a, const AbstractMetaClassCPtr &b) {
+ return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
+ });
+
+ const auto typeIndexes = collectTypeIndexes(classList);
+
+ macrosStream << "\n// Type indices\nenum [[deprecated]] : int {\n";
+ for (const auto &ti : typeIndexes)
+ macrosStream << typeIndexUpper(ti);
+ macrosStream << "};\n";
+
+ macrosStream << "\n// Type indices\nenum : int {\n";
+ for (const auto &ti : typeIndexes)
+ 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";
+ macrosStream << "extern SbkConverter **" << convertersVariableName() << ";\n\n";
+
+ // TODO-CONVERTER ------------------------------------------------------------------------------
+ // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex().
+ const auto converterIndexes = collectConverterIndexes();
+ macrosStream << "// Converter indices\nenum [[deprecated]] : int {\n";
+ for (const auto &ci : converterIndexes)
+ macrosStream << typeIndexUpper(ci);
+ macrosStream << "};\n\n";
+
+ macrosStream << "// Converter indices\nenum : int {\n";
+ for (const auto &ci : converterIndexes)
+ macrosStream << ci;
+ macrosStream << "};\n";
+
+ formatTypeDefEntries(macrosStream);
+
+ // TODO-CONVERTER ------------------------------------------------------------------------------
+
+ macrosStream << "// Macros for type check\n";
+
+ TextStream typeFunctions(&parameters.typeFunctions, TextStream::Language::Cpp);
+ TextStream privateTypeFunctions(&privateParameters.typeFunctions, TextStream::Language::Cpp);
+
+ for (const AbstractMetaEnum &cppEnum : api().globalEnums()) {
+ if (!cppEnum.isAnonymous()) {
+ const auto te = cppEnum.typeEntry();
+ if (te->hasConfigCondition())
+ parameters.conditionalIncludes[te->configCondition()].append(te->include());
+ else
+ parameters.includes.insert(cppEnum.typeEntry()->include());
+ writeSbkTypeFunction(typeFunctions, cppEnum);
+ }
+ }
+
+ StringStream protEnumsSurrogates(TextStream::Language::Cpp);
+ for (const auto &metaClass : classList) {
+ const auto classType = metaClass->typeEntry();
+ if (!shouldGenerate(classType))
+ continue;
+
+ // Includes
+ const bool isPrivate = classType->isPrivate();
+ auto &par = isPrivate ? privateParameters : parameters;
+ const auto classInclude = classType->include();
+ const bool hasConfigCondition = classType->hasConfigCondition();
+ if (leanHeaders() && canForwardDeclare(metaClass))
+ par.forwardDeclarations.append(metaClass);
+ else if (hasConfigCondition)
+ par.conditionalIncludes[classType->configCondition()].append(classInclude);
+ else
+ par.includes.insert(classInclude);
+
+ auto &typeFunctionsStr = isPrivate ? privateTypeFunctions : typeFunctions;
+
+ ConfigurableScope configScope(typeFunctionsStr, classType);
+ for (const AbstractMetaEnum &cppEnum : metaClass->enums()) {
+ if (cppEnum.isAnonymous() || cppEnum.isPrivate())
+ continue;
+ if (const auto inc = cppEnum.typeEntry()->include(); inc != classInclude)
+ par.includes.insert(inc);
+ writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum);
+ writeSbkTypeFunction(typeFunctionsStr, cppEnum);
+ }
+
+ if (!metaClass->isNamespace())
+ writeSbkTypeFunction(typeFunctionsStr, metaClass);
+ }
+
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ parameters.includes.insert(smp.type.typeEntry()->include());
+ writeSbkTypeFunction(typeFunctions, smp.type);
+ }
+
+ const QString moduleHeaderDir = outputDirectory() + u'/'
+ + subDirectoryForPackage(packageName()) + u'/';
+ const QString moduleHeaderFileName(moduleHeaderDir + getModuleHeaderFileName());
+
+ QString includeShield(u"SBK_"_s + moduleName().toUpper() + u"_PYTHON_H"_s);
+
+ FileOut file(moduleHeaderFileName);
+ TextStream &s = file.stream;
+ s.setLanguage(TextStream::Language::Cpp);
+
+ // write license comment
+ s << licenseComment()<< "\n\n";
+
+ s << "#ifndef " << includeShield<< '\n';
+ s << "#define " << includeShield<< "\n\n";
+ if (!avoidProtectedHack()) {
+ s << "//workaround to access protected functions\n";
+ s << "#define protected public\n\n";
+ }
+
+ s << "#include <sbkpython.h>\n";
+ s << "#include <sbkmodule.h>\n";
+ s << "#include <sbkconverter.h>\n";
+
+ QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports();
+ if (!requiredTargetImports.isEmpty()) {
+ s << "// Module Includes\n";
+ for (const QString &requiredModule : std::as_const(requiredTargetImports))
+ s << "#include <" << getModuleHeaderFileName(requiredModule) << ">\n";
+ s<< '\n';
+ }
+
+ s << "// Bound library includes\n";
+ for (const Include &include : parameters.includes)
+ s << include;
+ s << parameters.conditionalIncludes;
+
+ if (leanHeaders()) {
+ writeForwardDeclarations(s, parameters.forwardDeclarations);
+ } else {
+ if (!primitiveTypes().isEmpty()) {
+ s << "// Conversion Includes - Primitive Types\n";
+ const auto &primitiveTypeList = primitiveTypes();
+ for (const auto &ptype : primitiveTypeList)
+ s << ptype->include();
+ s<< '\n';
+ }
+
+ if (!containerTypes().isEmpty()) {
+ s << "// Conversion Includes - Container Types\n";
+ const ContainerTypeEntryCList &containerTypeList = containerTypes();
+ for (const auto &ctype : containerTypeList)
+ s << ctype->include();
+ s<< '\n';
+ }
+ }
+
+ s << macrosStream.toString() << '\n';
+
+ if (protEnumsSurrogates.size() > 0) {
+ s << "// Protected enum surrogates\n"
+ << protEnumsSurrogates.toString() << '\n';
+ }
+
+ writeTypeFunctions(s, parameters.typeFunctions);
+
+ s << "#endif // " << includeShield << "\n\n";
+
+ file.done();
+
+ if (hasPrivateClasses())
+ writePrivateHeader(moduleHeaderDir, includeShield, privateParameters);
+
+ return true;
+}
+
+void HeaderGenerator::writePrivateHeader(const QString &moduleHeaderDir,
+ const QString &publicIncludeShield,
+ const ModuleHeaderParameters &parameters)
+{
+ // Write includes and type functions of private classes
+
+ FileOut privateFile(moduleHeaderDir + getPrivateModuleHeaderFileName());
+ TextStream &ps = privateFile.stream;
+ ps.setLanguage(TextStream::Language::Cpp);
+ QString privateIncludeShield =
+ publicIncludeShield.left(publicIncludeShield.size() - 2) + "_P_H"_L1;
+
+ ps << licenseComment()<< "\n\n";
+
+ ps << "#ifndef " << privateIncludeShield << '\n';
+ ps << "#define " << privateIncludeShield << "\n\n";
+
+ for (const Include &include : parameters.includes)
+ ps << include;
+ ps << parameters.conditionalIncludes;
+ ps << '\n';
+
+ if (leanHeaders())
+ writeForwardDeclarations(ps, parameters.forwardDeclarations);
+
+ writeTypeFunctions(ps, parameters.typeFunctions);
+
+ ps << "#endif\n";
+ privateFile.done();
+}
+
+void HeaderGenerator::writeTypeFunctions(TextStream &s, const QString &typeFunctions)
+{
+ if (typeFunctions.isEmpty())
+ return;
+
+ if (usePySideExtensions())
+ s << "QT_WARNING_PUSH\nQT_WARNING_DISABLE_DEPRECATED\n";
+
+ s << "namespace Shiboken\n{\n\n"
+ << "// PyType functions, to get the PyObjectType for a type T\n"
+ << typeFunctions << '\n'
+ << "} // namespace Shiboken\n\n";
+
+ if (usePySideExtensions())
+ s << "QT_WARNING_POP\n";
+}
+
+void HeaderGenerator::writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum)
+{
+ if (avoidProtectedHack() && cppEnum.isProtected())
+ s << "enum " << protectedEnumSurrogateName(cppEnum) << " {};\n";
+}
+
+void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum)
+{
+ const QString enumName = avoidProtectedHack() && cppEnum.isProtected()
+ ? protectedEnumSurrogateName(cppEnum)
+ : cppEnum.qualifiedCppName();
+ const auto te = cppEnum.typeEntry();
+ ConfigurableScope configScope(s, te);
+ s << "template<> inline PyTypeObject *SbkType< " << m_gsp << enumName << " >() ";
+ s << "{ return " << cpythonTypeNameExt(te) << "; }\n";
+
+ const auto flag = cppEnum.typeEntry()->flags();
+ if (flag) {
+ s << "template<> inline PyTypeObject *SbkType< " << m_gsp << flag->name() << " >() "
+ << "{ return " << cpythonTypeNameExt(flag) << "; }\n";
+ }
+}
+
+void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaClassCPtr &cppClass)
+{
+ s << "template<> inline PyTypeObject *SbkType< "
+ << getFullTypeName(cppClass) << " >() "
+ << "{ return " << cpythonTypeNameExt(cppClass->typeEntry()) << "; }\n";
+}
+
+void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaType &metaType)
+{
+ s << "template<> inline PyTypeObject *SbkType< "
+ << m_gsp << metaType.cppSignature() << " >() "
+ << "{ return " << cpythonTypeNameExt(metaType) << "; }\n";
+}
+
+void HeaderGenerator::writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const
+{
+ if (!codeSnips.isEmpty()) {
+ try {
+ writeCodeSnips(s, codeSnips, position, language);
+ } catch (const std::exception &e) {
+ throw Exception(msgSnippetError("module header of "_L1 + moduleName(), e.what()));
+ }
+ }
+}
diff --git a/sources/shiboken6/generator/shiboken/headergenerator.h b/sources/shiboken6/generator/shiboken/headergenerator.h
new file mode 100644
index 000000000..03b98e743
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/headergenerator.h
@@ -0,0 +1,76 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef HEADERGENERATOR_H
+#define HEADERGENERATOR_H
+
+#include "shibokengenerator.h"
+#include "include.h"
+#include "modifications_typedefs.h"
+
+#include <QtCore/QList>
+#include <QtCore/QSet>
+
+struct IndexValue;
+class AbstractMetaFunction;
+struct ModuleHeaderParameters;
+
+/**
+ * The HeaderGenerator generate the declarations of C++ bindings classes.
+ */
+class HeaderGenerator : public ShibokenGenerator
+{
+public:
+ const char *name() const override { return "Header generator"; }
+
+ static const char *protectedHackDefine;
+
+protected:
+ QString fileNameForContext(const GeneratorContext &context) const override;
+ void generateClass(TextStream &s, const GeneratorContext &classContext) override;
+ bool finishGeneration() override;
+
+private:
+ using InheritedOverloadSet = QSet<AbstractMetaFunctionCPtr>;
+ using IndexValues = QList<IndexValue>;
+
+ IndexValues collectTypeIndexes(const AbstractMetaClassCList &classList);
+ IndexValues collectConverterIndexes() const;
+
+ static void writeCopyCtor(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+ void writeFunction(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ InheritedOverloadSet *inheritedOverloads,
+ FunctionGeneration generation) const;
+ static void writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum);
+ static void writeSbkTypeFunction(TextStream &s, const AbstractMetaClassCPtr &cppClass);
+ static void writeSbkTypeFunction(TextStream &s, const AbstractMetaType &metaType);
+ void collectTypeEntryTypeIndexes(const ApiExtractorResult &api,
+ const TypeEntryCPtr &typeEntry,
+ IndexValues *indexValues);
+ void collectClassTypeIndexes(const ApiExtractorResult &api,
+ const AbstractMetaClassCPtr &metaClass,
+ IndexValues *indexValues);
+ static void writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum);
+ void writeMemberFunctionWrapper(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const QString &postfix = {}) const;
+ void writePrivateHeader(const QString &moduleHeaderDir,
+ const QString &publicIncludeShield,
+ const ModuleHeaderParameters &parameters);
+ static void writeTypeFunctions(TextStream &s, const QString &typeFunctions);
+ void writeWrapperClassDeclaration(TextStream &s,
+ const QString &wrapperName,
+ const GeneratorContext &classContext) const;
+ void writeWrapperClass(TextStream &s, const QString &wrapperName, const GeneratorContext &classContext) const;
+ void writeInheritedWrapperClassDeclaration(TextStream &s,
+ const GeneratorContext &classContext) const;
+ void writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const;
+
+ AbstractMetaClassCList m_alternateTemplateIndexes;
+};
+
+#endif // HEADERGENERATOR_H
+
diff --git a/sources/shiboken6/generator/shiboken/overloaddata.cpp b/sources/shiboken6/generator/shiboken/overloaddata.cpp
new file mode 100644
index 000000000..c28fcdc1a
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/overloaddata.cpp
@@ -0,0 +1,1011 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <abstractmetafunction.h>
+#include <apiextractorresult.h>
+#include <abstractmetalang.h>
+#include <dotview.h>
+#include <reporthandler.h>
+#include <complextypeentry.h>
+#include <containertypeentry.h>
+#include <primitivetypeentry.h>
+#include <graph.h>
+#include "overloaddata.h"
+#include "messages.h"
+#include "ctypenames.h"
+#include "pytypenames.h"
+#include "textstream.h"
+#include "exception.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QTemporaryFile>
+
+#include <algorithm>
+#include <utility>
+
+using namespace Qt::StringLiterals;
+
+static QString getTypeName(const AbstractMetaType &type)
+{
+ TypeEntryCPtr typeEntry = type.typeEntry();
+ if (typeEntry->isPrimitive())
+ typeEntry = basicReferencedTypeEntry(typeEntry);
+ QString typeName = typeEntry->name();
+ if (typeEntry->isContainer()) {
+ QStringList types;
+ for (const auto &cType : type.instantiations()) {
+ TypeEntryCPtr typeEntry = cType.typeEntry();
+ if (typeEntry->isPrimitive())
+ typeEntry = basicReferencedTypeEntry(typeEntry);
+ types << typeEntry->name();
+ }
+ typeName += u'<' + types.join(u',') + u" >"_s;
+ }
+ return typeName;
+}
+
+static bool typesAreEqual(const AbstractMetaType &typeA, const AbstractMetaType &typeB)
+{
+ if (typeA.typeEntry() == typeB.typeEntry()) {
+ if (typeA.isContainer() || typeA.isSmartPointer()) {
+ if (typeA.instantiations().size() != typeB.instantiations().size())
+ return false;
+
+ for (qsizetype i = 0; i < typeA.instantiations().size(); ++i) {
+ if (!typesAreEqual(typeA.instantiations().at(i), typeB.instantiations().at(i)))
+ return false;
+ }
+ return true;
+ }
+
+ return !(typeA.isCString() ^ typeB.isCString());
+ }
+ return false;
+}
+
+/**
+ * Helper function that returns the name of a container get from containerType argument and
+ * an instantiation taken either from an implicit conversion expressed by the function argument,
+ * or from the string argument implicitConvTypeName.
+ */
+static QString getImplicitConversionTypeName(const AbstractMetaType &containerType,
+ const AbstractMetaType &instantiation,
+ const AbstractMetaFunctionCPtr &function,
+ const QString &implicitConvTypeName = QString())
+{
+ QString impConv;
+ if (!implicitConvTypeName.isEmpty())
+ impConv = implicitConvTypeName;
+ else if (function->isConversionOperator())
+ impConv = function->ownerClass()->typeEntry()->name();
+ else
+ impConv = getTypeName(function->arguments().constFirst().type());
+
+ QStringList types;
+ for (const auto &otherType : containerType.instantiations())
+ types << (otherType == instantiation ? impConv : getTypeName(otherType));
+
+ return containerType.typeEntry()->qualifiedCppName() + u'<'
+ + types.join(u", "_s) + u" >"_s;
+}
+
+static inline int overloadNumber(const OverloadDataNodePtr &o)
+{
+ return o->referenceFunction()->overloadNumber();
+}
+
+static bool sortByOverloadNumberModification(OverloadDataList &list)
+{
+ if (std::all_of(list.cbegin(), list.cend(),
+ [](const OverloadDataNodePtr &o) { return overloadNumber(o) == TypeSystem::OverloadNumberDefault; })) {
+ return false;
+ }
+ std::stable_sort(list.begin(), list.end(),
+ [] (const OverloadDataNodePtr &o1, const OverloadDataNodePtr &o2) {
+ return overloadNumber(o1) < overloadNumber(o2);
+ });
+ return true;
+}
+
+using OverloadGraph = Graph<QString>;
+
+/**
+ * Topologically sort the overloads by implicit convertion order
+ *
+ * This avoids using an implicit conversion if there's an explicit
+ * overload for the convertible type. So, if there's an implicit convert
+ * like TargetType(ConvertibleType foo) and both are in the overload list,
+ * ConvertibleType is checked before TargetType.
+ *
+ * Side effects: Modifies m_nextOverloadData
+ */
+void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api)
+{
+ QHash<QString, OverloadDataList> typeToOverloads;
+ using Edge = std::pair<QString, QString>;
+
+ bool checkPyObject = false;
+ bool checkPySequence = false;
+ bool checkQString = false;
+ bool checkQVariant = false;
+ bool checkPyBuffer = false;
+
+ // Primitive types that are not int, long, short,
+ // char and their respective unsigned counterparts.
+ static const QStringList nonIntegerPrimitives{floatT, doubleT, boolT};
+
+ // Signed integer primitive types.
+ static const QStringList signedIntegerPrimitives{intT, shortT, longT, longLongT};
+
+ // sort the children overloads
+ for (const auto &ov : std::as_const(m_children))
+ ov->sortNextOverloads(api);
+
+ if (m_children.size() <= 1 || sortByOverloadNumberModification(m_children))
+ return;
+
+ // Populates the OverloadSortData object containing map and reverseMap, to map type names to ids,
+ // these ids will be used by the topological sort algorithm, because is easier and faster to work
+ // with graph sorting using integers.
+
+ OverloadGraph graph;
+ for (const auto &ov : std::as_const(m_children)) {
+ const QString typeName = getTypeName(ov->modifiedArgType());
+ auto it = typeToOverloads.find(typeName);
+ if (it == typeToOverloads.end()) {
+ typeToOverloads.insert(typeName, {ov});
+ graph.addNode(typeName);
+ } else {
+ it.value().append(ov);
+ }
+
+ if (!checkPyObject && typeName == cPyObjectT)
+ checkPyObject = true;
+ else if (!checkPySequence && typeName == cPySequenceT)
+ checkPySequence = true;
+ else if (!checkPyBuffer && typeName == cPyBufferT)
+ checkPyBuffer = true;
+ else if (!checkQVariant && typeName == qVariantT)
+ checkQVariant = true;
+ else if (!checkQString && typeName == qStringT)
+ checkQString = true;
+
+ for (const auto &instantiation : ov->argType().instantiations()) {
+ // Add dependencies for type instantiation of container.
+ graph.addNode(getTypeName(instantiation));
+
+ // Build dependency for implicit conversion types instantiations for base container.
+ // For example, considering signatures "method(list<PointF>)" and "method(list<Point>)",
+ // and being PointF implicitly convertible from Point, an list<T> instantiation with T
+ // as Point must come before the PointF instantiation, or else list<Point> will never
+ // be called. In the case of primitive types, list<double> must come before list<int>.
+ if (instantiation.isPrimitive() && (signedIntegerPrimitives.contains(instantiation.name()))) {
+ for (const QString &primitive : std::as_const(nonIntegerPrimitives))
+ graph.addNode(getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive));
+ } else {
+ const auto &funcs = api.implicitConversions(instantiation);
+ for (const auto &function : funcs)
+ graph.addNode(getImplicitConversionTypeName(ov->argType(), instantiation, function));
+ }
+ }
+ }
+
+
+ // Create the graph of type dependencies based on implicit conversions.
+ // All C++ primitive types, add any forgotten type AT THE END OF THIS LIST!
+ static const QStringList primitiveTypes{intT, unsignedIntT, longT, unsignedLongT,
+ shortT, unsignedShortT, boolT, unsignedCharT, charT, floatT,
+ doubleT, constCharPtrT};
+
+ QStringList foundPrimitiveTypeIds;
+ for (const auto &p : primitiveTypes) {
+ if (graph.hasNode(p))
+ foundPrimitiveTypeIds.append(p);
+ }
+
+ if (checkPySequence && checkPyObject)
+ graph.addEdge(cPySequenceT, cPyObjectT);
+
+ QStringList classesWithIntegerImplicitConversion;
+
+ AbstractMetaFunctionCList involvedConversions;
+
+ for (const auto &ov : std::as_const(m_children)) {
+ const AbstractMetaType &targetType = ov->argType();
+ const QString targetTypeEntryName = getTypeName(ov->modifiedArgType());
+
+ // Process implicit conversions
+ const auto &functions = api.implicitConversions(targetType);
+ for (const auto &function : functions) {
+ QString convertibleType;
+ if (function->isConversionOperator())
+ convertibleType = function->ownerClass()->typeEntry()->name();
+ else
+ convertibleType = getTypeName(function->arguments().constFirst().type());
+
+ if (convertibleType == intT || convertibleType == unsignedIntT)
+ classesWithIntegerImplicitConversion << targetTypeEntryName;
+
+ if (!graph.hasNode(convertibleType))
+ continue;
+
+ // If a reverse pair already exists, remove it. Probably due to the
+ // container check (This happened to QVariant and QHash)
+ graph.removeEdge(targetTypeEntryName, convertibleType);
+ graph.addEdge(convertibleType, targetTypeEntryName);
+ involvedConversions.append(function);
+ }
+
+ // Process inheritance relationships
+ if (targetType.isValue() || targetType.isObject()) {
+ const auto te = targetType.typeEntry();
+ auto metaClass = AbstractMetaClass::findClass(api.classes(), te);
+ if (!metaClass)
+ throw Exception(msgArgumentClassNotFound(m_overloads.constFirst(), te));
+ const auto &ancestors = metaClass->allTypeSystemAncestors();
+ for (const auto &ancestor : ancestors) {
+ QString ancestorTypeName = ancestor->typeEntry()->name();
+ if (!graph.hasNode(ancestorTypeName))
+ continue;
+ graph.removeEdge(ancestorTypeName, targetTypeEntryName);
+ graph.addEdge(targetTypeEntryName, ancestorTypeName);
+ }
+ }
+
+ // Process template instantiations
+ for (const auto &instantiation : targetType.instantiations()) {
+ const QString convertible = getTypeName(instantiation);
+ if (graph.hasNode(convertible)) {
+ if (!graph.containsEdge(targetTypeEntryName, convertible)) // Avoid cyclic dependency.
+ graph.addEdge(convertible, targetTypeEntryName);
+
+ if (instantiation.isPrimitive() && (signedIntegerPrimitives.contains(instantiation.name()))) {
+ for (const QString &primitive : std::as_const(nonIntegerPrimitives)) {
+ QString convertibleTypeName =
+ getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive);
+ // Avoid cyclic dependency.
+ if (!graph.containsEdge(targetTypeEntryName, convertibleTypeName))
+ graph.addEdge(convertibleTypeName, targetTypeEntryName);
+ }
+
+ } else {
+ const auto &funcs = api.implicitConversions(instantiation);
+ for (const auto &function : funcs) {
+ QString convertibleTypeName =
+ getImplicitConversionTypeName(ov->argType(), instantiation, function);
+ // Avoid cyclic dependency.
+ if (!graph.containsEdge(targetTypeEntryName, convertibleTypeName)) {
+ graph.addEdge(convertibleTypeName, targetTypeEntryName);
+ involvedConversions.append(function);
+ }
+ }
+ }
+ }
+ }
+
+
+ if ((checkPySequence || checkPyObject || checkPyBuffer)
+ && !targetTypeEntryName.contains(cPyObjectT)
+ && !targetTypeEntryName.contains(cPyBufferT)
+ && !targetTypeEntryName.contains(cPySequenceT)) {
+ if (checkPySequence) {
+ // PySequence will be checked after all more specific types, but before PyObject.
+ graph.addEdge(targetTypeEntryName, cPySequenceT);
+ } else if (checkPyBuffer) {
+ // PySequence will be checked after all more specific types, but before PyObject.
+ graph.addEdge(targetTypeEntryName, cPyBufferT);
+ } else {
+ // Add dependency on PyObject, so its check is the last one (too generic).
+ graph.addEdge(targetTypeEntryName, cPyObjectT);
+ }
+ } else if (checkQVariant && targetTypeEntryName != qVariantT) {
+ if (!graph.containsEdge(qVariantT, targetTypeEntryName)) // Avoid cyclic dependency.
+ graph.addEdge(targetTypeEntryName, qVariantT);
+ } else if (checkQString && ov->argType().isPointer()
+ && targetTypeEntryName != qStringT
+ && targetTypeEntryName != qByteArrayT
+ && (!checkPyObject || targetTypeEntryName != cPyObjectT)) {
+ if (!graph.containsEdge(qStringT, targetTypeEntryName)) // Avoid cyclic dependency.
+ graph.addEdge(targetTypeEntryName, qStringT);
+ }
+
+ if (targetType.isEnum()) {
+ // Enum values must precede primitive types.
+ for (const auto &id : foundPrimitiveTypeIds)
+ graph.addEdge(targetTypeEntryName, id);
+ }
+ }
+
+ // QByteArray args need to be checked after QString args
+ if (graph.hasNode(qStringT) && graph.hasNode(qByteArrayT))
+ graph.addEdge(qStringT, qByteArrayT);
+
+ static const Edge rangeOrder[] =
+ {{doubleT, floatT},
+ {longLongT, longT}, {longLongT, intT}, {intT, shortT},
+ {unsignedLongLongT, unsignedLongT}, {unsignedLongLongT, unsignedT},
+ {unsignedLongLongT, unsignedIntT}, {unsignedT, unsignedShortT}
+ };
+ for (const auto &r : rangeOrder) {
+ if (graph.hasNode(r.first) && graph.hasNode(r.second))
+ graph.addEdge(r.first, r.second);
+ }
+
+ for (const auto &ov : std::as_const(m_children)) {
+ const AbstractMetaType &targetType = ov->argType();
+ if (!targetType.isEnum())
+ continue;
+
+ QString targetTypeEntryName = getTypeName(targetType);
+ // Enum values must precede types implicitly convertible from "int" or "unsigned int".
+ for (const QString &implicitFromInt : std::as_const(classesWithIntegerImplicitConversion))
+ graph.addEdge(targetTypeEntryName, implicitFromInt);
+ }
+
+
+ // Special case for double(int i) (not tracked by m_generator->implicitConversions
+ for (const QString &signedIntegerName : std::as_const(signedIntegerPrimitives)) {
+ if (graph.hasNode(signedIntegerName)) {
+ for (const QString &nonIntegerName : std::as_const(nonIntegerPrimitives)) {
+ if (graph.hasNode(nonIntegerName))
+ graph.addEdge(nonIntegerName, signedIntegerName);
+ }
+ }
+ }
+
+ // sort the overloads topologically based on the dependency graph.
+ const auto unmappedResult = graph.topologicalSort();
+ if (!unmappedResult.isValid()) {
+ QString funcName = referenceFunction()->name();
+ if (auto owner = referenceFunction()->ownerClass())
+ funcName.prepend(owner->name() + u'.');
+
+ // Dump overload graph
+ QString graphName = QDir::tempPath() + u'/' + funcName + u".dot"_s;
+ graph.dumpDot(graphName, [] (const QString &n) { return n; });
+ AbstractMetaFunctionCList cyclic;
+ for (const auto &typeName : unmappedResult.cyclic) {
+ const auto oit = typeToOverloads.constFind(typeName);
+ if (oit != typeToOverloads.cend())
+ cyclic.append(oit.value().constFirst()->referenceFunction());
+ }
+ qCWarning(lcShiboken, "%s", qPrintable(msgCyclicDependency(funcName, graphName, cyclic, involvedConversions)));
+ }
+
+ m_children.clear();
+ for (const auto &typeName : unmappedResult.result) {
+ const auto oit = typeToOverloads.constFind(typeName);
+ if (oit != typeToOverloads.cend()) {
+ std::copy(oit.value().crbegin(), oit.value().crend(),
+ std::back_inserter(m_children));
+ }
+ }
+}
+
+// Determine the minimum (first default argument)/maximum arguments (size)
+// of a function (taking into account the removed arguments).
+static std::pair<int, int> getMinMaxArgs(const AbstractMetaFunctionCPtr &func)
+{
+ int defaultValueIndex = -1;
+ const auto &arguments = func->arguments();
+ int argIndex = 0;
+ for (const auto &arg : arguments) {
+ if (!arg.isModifiedRemoved()) {
+ if (defaultValueIndex < 0 && arg.hasDefaultValueExpression())
+ defaultValueIndex = argIndex;
+ ++argIndex;
+ }
+ }
+ const int maxArgs = argIndex;
+ const int minArgs = defaultValueIndex >= 0 ? defaultValueIndex : maxArgs;
+ return {minArgs, maxArgs};
+}
+
+const OverloadDataRootNode *OverloadDataNode::parent() const
+{
+ return m_parent;
+}
+
+/**
+ * Root constructor for OverloadData
+ *
+ * This constructor receives the list of overloads for a given function and iterates generating
+ * the graph of OverloadData instances. Each OverloadDataNode instance references an argument/type
+ * combination.
+ *
+ * Example:
+ * addStuff(double, PyObject *)
+ * addStuff(double, int)
+ *
+ * Given these two overloads, there will be the following graph:
+ *
+ * addStuff - double - PyObject *
+ * \- int
+ *
+ */
+OverloadData::OverloadData(const AbstractMetaFunctionCList &overloads,
+ const ApiExtractorResult &api) :
+ OverloadDataRootNode(overloads)
+{
+ for (const auto &func : overloads) {
+ const auto minMaxArgs = getMinMaxArgs(func);
+ if (minMaxArgs.first < m_minArgs)
+ m_minArgs = minMaxArgs.first;
+ if (minMaxArgs.second > m_maxArgs)
+ m_maxArgs = minMaxArgs.second;
+ OverloadDataRootNode *currentOverloadData = this;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument &arg : arguments) {
+ if (!arg.isModifiedRemoved())
+ currentOverloadData = currentOverloadData->addOverloadDataNode(func, arg);
+ }
+ }
+
+ // Sort the overload possibilities so that the overload decisor code goes for the most
+ // important cases first, based on the topological order of the implicit conversions
+ sortNextOverloads(api);
+}
+
+OverloadDataNode::OverloadDataNode(const AbstractMetaFunctionCPtr &func,
+ OverloadDataRootNode *parent,
+ const AbstractMetaArgument &argument,
+ int argPos,
+ const QString argTypeReplaced) :
+ m_argument(argument),
+ m_argTypeReplaced(argTypeReplaced),
+ m_parent(parent),
+ m_argPos(argPos)
+{
+ if (func)
+ this->addOverload(func);
+}
+
+void OverloadDataNode::addOverload(const AbstractMetaFunctionCPtr &func)
+{
+ m_overloads.append(func);
+}
+
+OverloadDataNode *OverloadDataRootNode::addOverloadDataNode(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &arg)
+{
+ OverloadDataNodePtr overloadData;
+ if (!func->isOperatorOverload()) {
+ for (const auto &tmp : std::as_const(m_children)) {
+ // TODO: 'const char *', 'char *' and 'char' will have the same TypeEntry?
+
+ // If an argument have a type replacement, then we should create a new overloaddata
+ // for it, unless the next argument also have a identical type replacement.
+ if (typesAreEqual(tmp->modifiedArgType(), arg.modifiedType())) {
+ tmp->addOverload(func);
+ overloadData = tmp;
+ }
+ }
+ }
+
+ if (!overloadData) {
+ const int argpos = argPos() + 1;
+ overloadData.reset(new OverloadDataNode(func, this, arg, argpos));
+ m_children.append(overloadData);
+ }
+
+ return overloadData.get();
+}
+
+bool OverloadData::hasNonVoidReturnType() const
+{
+ for (const auto &func : m_overloads) {
+ if (func->isTypeModified()) {
+ if (func->modifiedTypeName() != u"void")
+ return true;
+ } else {
+ if (!func->argumentRemoved(0) && !func->type().isVoid())
+ return true;
+ }
+ }
+ return false;
+}
+
+bool OverloadData::hasVarargs() const
+{
+ for (const auto &func : m_overloads) {
+ AbstractMetaArgumentList args = func->arguments();
+ if (args.size() > 1 && args.constLast().type().isVarargs())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticFunction(const AbstractMetaFunctionCList &overloads)
+{
+ for (const auto &func : overloads) {
+ if (func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticFunction() const
+{
+ for (const auto &func : m_overloads) {
+ if (func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasClassMethod(const AbstractMetaFunctionCList &overloads)
+{
+ for (const auto &func : overloads) {
+ if (func->isClassMethod())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasClassMethod() const
+{
+ for (const auto &func : m_overloads) {
+ if (func->isClassMethod())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasInstanceFunction(const AbstractMetaFunctionCList &overloads)
+{
+ for (const auto &func : overloads) {
+ if (!func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasInstanceFunction() const
+{
+ for (const auto &func : m_overloads) {
+ if (!func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticAndInstanceFunctions(const AbstractMetaFunctionCList &overloads)
+{
+ return OverloadData::hasStaticFunction(overloads) && OverloadData::hasInstanceFunction(overloads);
+}
+
+bool OverloadData::hasStaticAndInstanceFunctions() const
+{
+ return OverloadData::hasStaticFunction() && OverloadData::hasInstanceFunction();
+}
+
+OverloadDataRootNode::OverloadDataRootNode(const AbstractMetaFunctionCList &o) :
+ m_overloads(o)
+{
+}
+
+OverloadDataRootNode::~OverloadDataRootNode() = default;
+
+AbstractMetaFunctionCPtr OverloadDataRootNode::referenceFunction() const
+{
+ return m_overloads.constFirst();
+}
+
+const AbstractMetaArgument *OverloadDataNode::overloadArgument(const AbstractMetaFunctionCPtr &func) const
+{
+ if (isRoot() || !m_overloads.contains(func))
+ return nullptr;
+
+ int argPos = 0;
+ int removed = 0;
+ for (int i = 0; argPos <= m_argPos; i++) {
+ if (func->arguments().at(i).isModifiedRemoved())
+ removed++;
+ else
+ argPos++;
+ }
+
+ return &func->arguments().at(m_argPos + removed);
+}
+
+bool OverloadDataRootNode::nextArgumentHasDefaultValue() const
+{
+ for (const auto &overloadData : m_children) {
+ if (overloadData->getFunctionWithDefaultValue())
+ return true;
+ }
+ return false;
+}
+
+static const OverloadDataRootNode *_findNextArgWithDefault(const OverloadDataRootNode *overloadData)
+{
+ if (overloadData->getFunctionWithDefaultValue())
+ return overloadData;
+
+ const OverloadDataRootNode *result = nullptr;
+ const OverloadDataList &data = overloadData->children();
+ for (const auto &odata : data) {
+ const auto *tmp = _findNextArgWithDefault(odata.get());
+ if (!result || (tmp && result->argPos() > tmp->argPos()))
+ result = tmp;
+ }
+ return result;
+}
+
+const OverloadDataRootNode *OverloadDataRootNode::findNextArgWithDefault() const
+{
+ return _findNextArgWithDefault(this);
+}
+
+bool OverloadDataRootNode::isFinalOccurrence(const AbstractMetaFunctionCPtr &func) const
+{
+ for (const auto &pd : m_children) {
+ if (pd->overloads().contains(func))
+ return false;
+ }
+ return true;
+}
+
+AbstractMetaFunctionCPtr OverloadDataRootNode::getFunctionWithDefaultValue() const
+{
+ const qsizetype argpos = argPos();
+ for (const auto &func : m_overloads) {
+ qsizetype removedArgs = 0;
+ for (qsizetype i = 0; i <= argpos + removedArgs; i++) {
+ if (func->arguments().at(i).isModifiedRemoved())
+ removedArgs++;
+ }
+ if (func->arguments().at(argpos + removedArgs).hasDefaultValueExpression())
+ return func;
+ }
+ return {};
+}
+
+QList<int> OverloadData::invalidArgumentLengths() const
+{
+ QSet<int> validArgLengths;
+
+ for (const auto &func : m_overloads) {
+ const AbstractMetaArgumentList args = func->arguments();
+ int offset = 0;
+ for (qsizetype i = 0; i < args.size(); ++i) {
+ if (func->arguments().at(i).isModifiedRemoved()) {
+ offset++;
+ } else {
+ if (args.at(i).hasDefaultValueExpression())
+ validArgLengths << i-offset;
+ }
+ }
+ validArgLengths << args.size() - offset;
+ }
+
+ QList<int> invalidArgLengths;
+ for (int i = m_minArgs + 1; i < m_maxArgs; i++) {
+ if (!validArgLengths.contains(i))
+ invalidArgLengths.append(i);
+ }
+
+ return invalidArgLengths;
+}
+
+int OverloadData::numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func)
+{
+ return std::count_if(func->arguments().cbegin(), func->arguments().cend(),
+ [](const AbstractMetaArgument &a) { return a.isModifiedRemoved(); });
+}
+
+int OverloadData::numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func, int finalArgPos)
+{
+ Q_ASSERT(finalArgPos >= 0);
+ int removed = 0;
+ const auto size = func->arguments().size();
+ for (qsizetype i = 0; i < qMin(size, qsizetype(finalArgPos + removed)); ++i) {
+ if (func->arguments().at(i).isModifiedRemoved())
+ ++removed;
+ }
+ return removed;
+}
+
+void OverloadData::dumpGraph(const QString &filename) const
+{
+ QFile file(filename);
+ if (file.open(QFile::WriteOnly)) {
+ QTextStream s(&file);
+ dumpRootGraph(s, m_minArgs, m_maxArgs);
+ }
+}
+
+QString OverloadData::dumpGraph() const
+{
+ QString result;
+ QTextStream s(&result);
+ dumpRootGraph(s, m_minArgs, m_maxArgs);
+ return result;
+}
+
+bool OverloadData::showGraph() const
+{
+ return showDotGraph(referenceFunction()->name(), dumpGraph());
+}
+
+static inline QString toHtml(QString s)
+{
+ s.replace(u'<', u"&lt;"_s);
+ s.replace(u'>', u"&gt;"_s);
+ s.replace(u'&', u"&amp;"_s);
+ return s;
+}
+
+void OverloadDataRootNode::dumpRootGraph(QTextStream &s, int minArgs, int maxArgs) const
+{
+ const auto rfunc = referenceFunction();
+ s << "digraph OverloadedFunction {\n";
+ s << " graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];\n";
+
+ // Shows all function signatures
+ s << "legend [fontsize=9 fontname=freemono shape=rect label=\"";
+ for (const auto &func : m_overloads) {
+ s << "f" << functionNumber(func) << " : "
+ << toHtml(func->type().cppSignature())
+ << ' ' << toHtml(func->minimalSignature()) << "\\l";
+ }
+ s << "\"];\n";
+
+ // Function box title
+ s << " \"" << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+ s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">";
+ if (rfunc->ownerClass())
+ s << rfunc->ownerClass()->name() << "::";
+ s << toHtml(rfunc->name()) << "</font>";
+ if (rfunc->isVirtual()) {
+ s << "<br/><font color=\"white\" point-size=\"10\">&lt;&lt;";
+ if (rfunc->isAbstract())
+ s << "pure ";
+ s << "virtual&gt;&gt;</font>";
+ }
+ s << "</td></tr>";
+
+ // Function return type
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">"
+ << toHtml(rfunc->type().cppSignature())
+ << "</td></tr>";
+
+ // Shows type changes for all function signatures
+ for (const auto &func : m_overloads) {
+ if (!func->isTypeModified())
+ continue;
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(func->modifiedTypeName()) << "</td></tr>";
+ }
+
+ // Minimum and maximum number of arguments
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">minArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << minArgs << "</td></tr>";
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">maxArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << maxArgs << "</td></tr>";
+
+ if (rfunc->ownerClass()) {
+ if (rfunc->implementingClass() != rfunc->ownerClass())
+ s << "<tr><td align=\"right\">implementor</td><td align=\"left\">" << rfunc->implementingClass()->name() << "</td></tr>";
+ if (rfunc->declaringClass() != rfunc->ownerClass() && rfunc->declaringClass() != rfunc->implementingClass())
+ s << "<tr><td align=\"right\">declarator</td><td align=\"left\">" << rfunc->declaringClass()->name() << "</td></tr>";
+ }
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ for (const auto &func : m_overloads)
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ s << "</table>> ];\n";
+
+ for (const auto &pd : m_children) {
+ s << " \"" << rfunc->name() << "\" -> ";
+ pd->dumpNodeGraph(s);
+ }
+
+ s << "}\n";
+}
+
+void OverloadDataNode::dumpNodeGraph(QTextStream &s) const
+{
+ QString argId = u"arg_"_s + QString::number(quintptr(this));
+ s << argId << ";\n";
+
+ s << " \"" << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+
+ // Argument box title
+ s << "<tr><td bgcolor=\"black\" align=\"left\" cellpadding=\"2\" colspan=\"2\">";
+ s << "<font color=\"white\" point-size=\"11\">arg #" << argPos() << "</font></td></tr>";
+
+ // Argument type information
+ const QString type = modifiedArgType().cppSignature();
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(type) << "</td></tr>";
+ if (isTypeModified()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">orig. type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(argType().cppSignature()) << "</td></tr>";
+ }
+
+ const OverloadDataRootNode *root = this;
+ while (!root->isRoot())
+ root = root->parent();
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ for (const auto &func : m_overloads)
+ s << 'f' << root->functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ // Show default values (original and modified) for various functions
+ for (const auto &func : m_overloads) {
+ const AbstractMetaArgument *arg = overloadArgument(func);
+ if (!arg)
+ continue;
+ const int n = root->functionNumber(func);
+ QString argDefault = arg->defaultValueExpression();
+ if (!argDefault.isEmpty() ||
+ argDefault != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << n;
+ s << "-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << argDefault << "</td></tr>";
+ }
+ if (argDefault != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << n;
+ s << "-orig-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << arg->originalDefaultValueExpression() << "</td></tr>";
+ }
+ }
+
+ s << "</table>>];\n";
+
+ for (const auto &pd : m_children) {
+ s << " " << argId << " -> ";
+ pd->dumpNodeGraph(s);
+ }
+}
+
+int OverloadDataRootNode::functionNumber(const AbstractMetaFunctionCPtr &func) const
+{
+ return m_overloads.indexOf(func);
+}
+
+bool OverloadData::pythonFunctionWrapperUsesListOfArguments() const
+{
+ auto referenceFunction = m_overloads.constFirst();
+ if (referenceFunction->isCallOperator())
+ return true;
+ if (referenceFunction->isOperatorOverload())
+ return false;
+ const int maxArgs = this->maxArgs();
+ const int minArgs = this->minArgs();
+ return (minArgs != maxArgs)
+ || (maxArgs > 1)
+ || referenceFunction->isConstructor()
+ || hasArgumentWithDefaultValue();
+}
+
+bool OverloadData::hasArgumentWithDefaultValue() const
+{
+ if (maxArgs() == 0)
+ return false;
+ for (const auto &func : m_overloads) {
+ if (hasArgumentWithDefaultValue(func))
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunctionCPtr &func)
+{
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument &arg : arguments) {
+ if (!arg.isModifiedRemoved() && arg.hasDefaultValueExpression())
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const AbstractMetaFunctionCPtr &func)
+{
+ AbstractMetaArgumentList args;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument &arg : arguments) {
+ if (!arg.hasDefaultValueExpression()
+ || arg.isModifiedRemoved())
+ continue;
+ args << arg;
+ }
+ return args;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+void OverloadDataRootNode::formatReferenceFunction(QDebug &d) const
+{
+ auto refFunc = referenceFunction();
+ d << '"';
+ if (auto owner = refFunc->ownerClass())
+ d << owner->qualifiedCppName() << "::";
+ d << refFunc->minimalSignature() << '"';
+ if (m_overloads.constFirst()->isReverseOperator())
+ d << " [reverseop]";
+}
+
+void OverloadDataRootNode::formatOverloads(QDebug &d) const
+{
+ const qsizetype count = m_overloads.size();
+ d << ", overloads[" << count << ']';
+ if (count < 2)
+ return;
+ d << "=(";
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ d << '\n';
+ d << m_overloads.at(i)->signature();
+ }
+ d << ')';
+}
+
+void OverloadDataRootNode::formatNextOverloadData(QDebug &d) const
+{
+ const qsizetype count = m_children.size();
+ d << ", next[" << count << ']';
+ if (d.verbosity() >= 3) {
+ d << "=(";
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ d << '\n';
+ m_children.at(i)->formatDebug(d);
+ }
+ d << ')';
+ }
+}
+
+void OverloadDataRootNode::formatDebug(QDebug &d) const
+{
+ formatReferenceFunction(d);
+ formatOverloads(d);
+ formatNextOverloadData(d);
+}
+
+void OverloadDataNode::formatDebug(QDebug &d) const
+{
+ d << "OverloadDataNode(";
+ formatReferenceFunction(d);
+ d << ", argPos=" << m_argPos;
+ if (m_argument.argumentIndex() != m_argPos)
+ d << ", argIndex=" << m_argument.argumentIndex();
+ d << ", argType=\"" << m_argument.type().cppSignature() << '"';
+ if (isTypeModified())
+ d << ", modifiedArgType=\"" << modifiedArgType().cppSignature() << '"';
+ formatOverloads(d);
+ formatNextOverloadData(d);
+ d << ')';
+}
+
+void OverloadData::formatDebug(QDebug &d) const
+{
+ d << "OverloadData(";
+ formatReferenceFunction(d);
+ d << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs;
+ formatOverloads(d);
+ formatNextOverloadData(d);
+ d << ')';
+}
+
+QDebug operator<<(QDebug d, const OverloadData &od)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ od.formatDebug(d);
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/generator/shiboken/overloaddata.h b/sources/shiboken6/generator/shiboken/overloaddata.h
new file mode 100644
index 000000000..875a5a8b5
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/overloaddata.h
@@ -0,0 +1,183 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OVERLOADDATA_H
+#define OVERLOADDATA_H
+
+#include <apiextractorresult.h>
+#include <abstractmetaargument.h>
+
+#include <QtCore/QBitArray>
+#include <QtCore/QList>
+
+#include <memory>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+
+class OverloadDataNode;
+using OverloadDataNodePtr = std::shared_ptr<OverloadDataNode>;
+using OverloadDataList = QList<OverloadDataNodePtr>;
+
+/// The root node of OverloadData. It contains all functions
+class OverloadDataRootNode
+{
+public:
+ virtual ~OverloadDataRootNode();
+
+ OverloadDataRootNode(const OverloadDataRootNode &) = delete;
+ OverloadDataRootNode &operator=(const OverloadDataRootNode &) = delete;
+ OverloadDataRootNode(OverloadDataRootNode &&) = delete;
+ OverloadDataRootNode &operator=(OverloadDataRootNode &&) = delete;
+
+ virtual int argPos() const { return -1; }
+ virtual const OverloadDataRootNode *parent() const { return nullptr; }
+
+ bool isRoot() const { return parent() == nullptr; }
+
+ AbstractMetaFunctionCPtr referenceFunction() const;
+
+ const AbstractMetaFunctionCList &overloads() const { return m_overloads; }
+ const OverloadDataList &children() const { return m_children; }
+
+ bool nextArgumentHasDefaultValue() const;
+
+ /// Returns the function that has a default value at the current OverloadData argument position, otherwise returns null.
+ AbstractMetaFunctionCPtr getFunctionWithDefaultValue() const;
+
+ /// Returns the nearest occurrence, including this instance, of an argument with a default value.
+ const OverloadDataRootNode *findNextArgWithDefault() const;
+ bool isFinalOccurrence(const AbstractMetaFunctionCPtr &func) const;
+
+ int functionNumber(const AbstractMetaFunctionCPtr &func) const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ virtual void formatDebug(QDebug &d) const;
+#endif
+
+ OverloadDataNode *addOverloadDataNode(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &arg);
+
+protected:
+ OverloadDataRootNode(const AbstractMetaFunctionCList &o= {});
+
+ void dumpRootGraph(QTextStream &s, int minArgs, int maxArgs) const;
+ void sortNextOverloads(const ApiExtractorResult &api);
+
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatReferenceFunction(QDebug &d) const;
+ void formatOverloads(QDebug &d) const;
+ void formatNextOverloadData(QDebug &d) const;
+#endif
+
+ AbstractMetaFunctionCList m_overloads;
+ OverloadDataList m_children;
+};
+
+/// OverloadDataNode references an argument/type combination.
+class OverloadDataNode : public OverloadDataRootNode
+{
+public:
+ explicit OverloadDataNode(const AbstractMetaFunctionCPtr &func,
+ OverloadDataRootNode *parent,
+ const AbstractMetaArgument &arg, int argPos,
+ const QString argTypeReplaced = {});
+ void addOverload(const AbstractMetaFunctionCPtr &func);
+
+ int argPos() const override { return m_argPos; }
+ const OverloadDataRootNode *parent() const override;
+ void dumpNodeGraph(QTextStream &s) const;
+
+ const AbstractMetaArgument &argument() const
+ { return m_argument; }
+ const AbstractMetaType &argType() const { return m_argument.type(); }
+ const AbstractMetaType &modifiedArgType() const { return m_argument.modifiedType(); }
+
+ bool isTypeModified() const { return m_argument.isTypeModified(); }
+
+ const AbstractMetaArgument *overloadArgument(const AbstractMetaFunctionCPtr &func) const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ AbstractMetaArgument m_argument;
+ QString m_argTypeReplaced;
+ OverloadDataRootNode *m_parent = nullptr;
+
+ int m_argPos = -1; // Position excluding modified/removed arguments.
+};
+
+class OverloadData : public OverloadDataRootNode
+{
+public:
+ explicit OverloadData(const AbstractMetaFunctionCList &overloads,
+ const ApiExtractorResult &api);
+
+ int minArgs() const { return m_minArgs; }
+ int maxArgs() const { return m_maxArgs; }
+
+ /// Returns true if any of the overloads for the current OverloadData has a return type different from void.
+ bool hasNonVoidReturnType() const;
+
+ /// Returns true if any of the overloads for the current OverloadData has a varargs argument.
+ bool hasVarargs() const;
+
+ /// Returns true if any of the overloads for the current OverloadData is static.
+ bool hasStaticFunction() const;
+
+ /// Returns true if any of the overloads passed as argument is static.
+ static bool hasStaticFunction(const AbstractMetaFunctionCList &overloads);
+
+ /// Returns true if any of the overloads for the current OverloadData is classmethod.
+ bool hasClassMethod() const;
+
+ /// Returns true if any of the overloads passed as argument is classmethod.
+ static bool hasClassMethod(const AbstractMetaFunctionCList &overloads);
+
+ /// Returns true if any of the overloads for the current OverloadData is not static.
+ bool hasInstanceFunction() const;
+
+ /// Returns true if any of the overloads passed as argument is not static.
+ static bool hasInstanceFunction(const AbstractMetaFunctionCList &overloads);
+
+ /// Returns true if among the overloads for the current OverloadData there are static and non-static methods altogether.
+ bool hasStaticAndInstanceFunctions() const;
+
+ /// Returns true if among the overloads passed as argument there are static and non-static methods altogether.
+ static bool hasStaticAndInstanceFunctions(const AbstractMetaFunctionCList &overloads);
+
+ QList<int> invalidArgumentLengths() const;
+
+ static int numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func);
+ static int numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func, int finalArgPos);
+
+ void dumpGraph(const QString &filename) const;
+ QString dumpGraph() const;
+ bool showGraph() const;
+
+ /// Returns true if a list of arguments is used (METH_VARARGS)
+ bool pythonFunctionWrapperUsesListOfArguments() const;
+
+ bool hasArgumentWithDefaultValue() const;
+ static bool hasArgumentWithDefaultValue(const AbstractMetaFunctionCPtr &func);
+
+ /// Returns a list of function arguments which have default values and were not removed.
+ static AbstractMetaArgumentList getArgumentsWithDefaultValues(const AbstractMetaFunctionCPtr &func);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &) const override;
+#endif
+
+private:
+ int m_minArgs = 256;
+ int m_maxArgs = 0;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug, const OverloadData &);
+#endif
+
+#endif // OVERLOADDATA_H
diff --git a/sources/shiboken6/generator/shiboken/pytypenames.h b/sources/shiboken6/generator/shiboken/pytypenames.h
new file mode 100644
index 000000000..6c7658ff6
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/pytypenames.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PYTYPENAMES_H
+#define PYTYPENAMES_H
+
+#include <QtCore/QString>
+
+constexpr auto pyBoolT = QLatin1StringView ("PyBool");
+constexpr auto pyFloatT = QLatin1StringView ("PyFloat");
+constexpr auto pyLongT = QLatin1StringView ("PyLong");
+constexpr auto pyObjectT = QLatin1StringView ("object");
+constexpr auto pyStrT = QLatin1StringView ("str");
+
+// PYSIDE-1499: A custom type determined by existence of an `__fspath__` attribute.
+constexpr auto pyPathLikeT = QLatin1StringView ("PyPathLike");
+
+constexpr auto cPyBufferT = QLatin1StringView ("PyBuffer");
+constexpr auto cPyListT = QLatin1StringView ("PyList");
+constexpr auto cPyObjectT = QLatin1StringView ("PyObject");
+constexpr auto cPySequenceT = QLatin1StringView ("PySequence");
+constexpr auto cPyTypeObjectT = QLatin1StringView ("PyTypeObject");
+
+// numpy
+constexpr auto cPyArrayObjectT = QLatin1StringView ("PyArrayObject");
+
+constexpr auto sbkCharT = QLatin1StringView ("SbkChar");
+
+#endif // PYTYPENAMES_H
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
new file mode 100644
index 000000000..67fd9c994
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
@@ -0,0 +1,2650 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "shibokengenerator.h"
+#include "generatorstrings.h"
+#include "generatorargument.h"
+#include "defaultvalue.h"
+#include "generatorcontext.h"
+#include "apiextractorresult.h"
+#include "codesnip.h"
+#include "customconversion.h"
+#include "ctypenames.h"
+#include <abstractmetabuilder.h>
+#include <abstractmetaenum.h>
+#include <abstractmetafield.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetalang_helpers.h>
+#include <usingmember.h>
+#include <exception.h>
+#include <messages.h>
+#include <modifications.h>
+#include "overloaddata.h"
+#include <optionsparser.h>
+#include "propertyspec.h"
+#include "pytypenames.h"
+#include <reporthandler.h>
+#include <textstream.h>
+#include <typedatabase.h>
+#include <containertypeentry.h>
+#include <customtypenentry.h>
+#include <enumtypeentry.h>
+#include <flagstypeentry.h>
+#include <namespacetypeentry.h>
+#include <primitivetypeentry.h>
+#include <pythontypeentry.h>
+#include <smartpointertypeentry.h>
+#include <valuetypeentry.h>
+
+#include <iostream>
+
+#include "qtcompat.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QRegularExpression>
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <utility>
+
+using namespace Qt::StringLiterals;
+
+static constexpr auto PARENT_CTOR_HEURISTIC = "enable-parent-ctor-heuristic"_L1;
+static constexpr auto RETURN_VALUE_HEURISTIC = "enable-return-value-heuristic"_L1;
+static constexpr auto DISABLE_VERBOSE_ERROR_MESSAGES = "disable-verbose-error-messages"_L1;
+static constexpr auto USE_ISNULL_AS_NB_BOOL = "use-isnull-as-nb-bool"_L1;
+// FIXME PYSIDE 7: Remove USE_ISNULL_AS_NB_NONZERO/USE_OPERATOR_BOOL_AS_NB_NONZERO
+static constexpr auto USE_ISNULL_AS_NB_NONZERO = "use-isnull-as-nb_nonzero"_L1;
+static constexpr auto USE_OPERATOR_BOOL_AS_NB_BOOL = "use-operator-bool-as-nb-bool"_L1;
+static constexpr auto USE_OPERATOR_BOOL_AS_NB_NONZERO = "use-operator-bool-as-nb-nonzero"_L1;
+static constexpr auto WRAPPER_DIAGNOSTICS = "wrapper-diagnostics"_L1;
+static constexpr auto NO_IMPLICIT_CONVERSIONS = "no-implicit-conversions"_L1;
+static constexpr auto LEAN_HEADERS = "lean-headers"_L1;
+
+QString CPP_ARG_N(int i)
+{
+ return CPP_ARG + QString::number(i);
+}
+
+constexpr auto CPP_ARG_REMOVED_PREFIX = "removed_cppArg"_L1;
+
+QString CPP_ARG_REMOVED(int i)
+{
+ return CPP_ARG_REMOVED_PREFIX + QString::number(i);
+}
+
+const char *const METHOD_DEF_SENTINEL = "{nullptr, nullptr, 0, nullptr} // Sentinel\n";
+const char *const PYTHON_TO_CPPCONVERSION_STRUCT = "Shiboken::Conversions::PythonToCppConversion";
+
+const char *const openTargetExternC = R"(
+// Target ---------------------------------------------------------
+
+extern "C" {
+)";
+const char *const closeExternC = "} // extern \"C\"\n\n";
+const char *const richCompareComment =
+ "// PYSIDE-74: By default, we redirect to object's tp_richcompare (which is `==`, `!=`).\n";
+
+struct ShibokenGeneratorOptions
+{
+ bool useCtorHeuristic = false;
+ bool userReturnValueHeuristic = false;
+ bool verboseErrorMessagesDisabled = false;
+ bool useIsNullAsNbBool = false;
+ // FIXME PYSIDE 7 Flip m_leanHeaders default or remove?
+ bool leanHeaders = false;
+ bool useOperatorBoolAsNbBool = false;
+ // FIXME PYSIDE 7 Flip generateImplicitConversions default or remove?
+ bool generateImplicitConversions = true;
+ bool wrapperDiagnostics = false;
+};
+
+struct GeneratorClassInfoCacheEntry
+{
+ ShibokenGenerator::FunctionGroups functionGroups;
+ QList<AbstractMetaFunctionCList> numberProtocolOperators;
+ BoolCastFunctionOptional boolCastFunctionO;
+ bool needsGetattroFunction = false;
+};
+
+using GeneratorClassInfoCache = QHash<AbstractMetaClassCPtr, GeneratorClassInfoCacheEntry>;
+
+Q_GLOBAL_STATIC(GeneratorClassInfoCache, generatorClassInfoCache)
+
+static const char CHECKTYPE_REGEX[] = R"(%CHECKTYPE\[([^\[]*)\]\()";
+static const char ISCONVERTIBLE_REGEX[] = R"(%ISCONVERTIBLE\[([^\[]*)\]\()";
+static const char CONVERTTOPYTHON_REGEX[] = R"(%CONVERTTOPYTHON\[([^\[]*)\]\()";
+// Capture a '*' leading the variable name into the target
+// so that "*valuePtr = %CONVERTTOCPP..." works as expected.
+static const char CONVERTTOCPP_REGEX[] =
+ R"((\*?%?[a-zA-Z_][\w\.]*(?:\[[^\[^<^>]+\])*)(?:\s+)=(?:\s+)%CONVERTTOCPP\[([^\[]*)\]\()";
+
+const ShibokenGenerator::TypeSystemConverterRegExps &
+ ShibokenGenerator::typeSystemConvRegExps()
+{
+ static const TypeSystemConverterRegExps result = {
+ QRegularExpression(QLatin1StringView(CHECKTYPE_REGEX)),
+ QRegularExpression(QLatin1StringView(ISCONVERTIBLE_REGEX)),
+ QRegularExpression(QLatin1StringView(CONVERTTOCPP_REGEX)),
+ QRegularExpression(QLatin1StringView(CONVERTTOPYTHON_REGEX))
+ };
+ return result;
+}
+
+// Options are static to avoid duplicated handling since ShibokenGenerator
+// is instantiated for HeaderGenerator and CppGenerator.
+ShibokenGeneratorOptions ShibokenGenerator::m_options;
+
+ShibokenGenerator::ShibokenGenerator() = default;
+
+ShibokenGenerator::~ShibokenGenerator() = default;
+
+// Correspondences between primitive and Python types.
+static const QHash<QString, QString> &primitiveTypesCorrespondences()
+{
+ static const QHash<QString, QString> result = {
+ {u"bool"_s, pyBoolT},
+ {u"char"_s, sbkCharT},
+ {u"signed char"_s, sbkCharT},
+ {u"unsigned char"_s, sbkCharT},
+ {intT, pyLongT},
+ {u"signed int"_s, pyLongT},
+ {u"uint"_s, pyLongT},
+ {u"unsigned int"_s, pyLongT},
+ {shortT, pyLongT},
+ {u"ushort"_s, pyLongT},
+ {u"signed short"_s, pyLongT},
+ {u"signed short int"_s, pyLongT},
+ {unsignedShortT, pyLongT},
+ {u"unsigned short int"_s, pyLongT},
+ {longT, pyLongT},
+ {doubleT, pyFloatT},
+ {floatT, pyFloatT},
+ {u"unsigned long"_s, pyLongT},
+ {u"signed long"_s, pyLongT},
+ {u"ulong"_s, pyLongT},
+ {u"unsigned long int"_s, pyLongT},
+ {u"long long"_s, pyLongT},
+ {u"__int64"_s, pyLongT},
+ {u"unsigned long long"_s, pyLongT},
+ {u"unsigned __int64"_s, pyLongT},
+ {u"size_t"_s, pyLongT}
+ };
+ return result;
+}
+
+const QHash<QString, QChar> &ShibokenGenerator::formatUnits()
+{
+ static const QHash<QString, QChar> result = {
+ {u"char"_s, u'b'},
+ {u"unsigned char"_s, u'B'},
+ {intT, u'i'},
+ {u"unsigned int"_s, u'I'},
+ {shortT, u'h'},
+ {unsignedShortT, u'H'},
+ {longT, u'l'},
+ {unsignedLongLongT, u'k'},
+ {longLongT, u'L'},
+ {u"__int64"_s, u'L'},
+ {unsignedLongLongT, u'K'},
+ {u"unsigned __int64"_s, u'K'},
+ {doubleT, u'd'},
+ {floatT, u'f'},
+ };
+ return result;
+}
+
+QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType &cType,
+ const AbstractMetaClassCPtr &context,
+ Options options) const
+{
+ if (cType.isArray()) {
+ return translateTypeForWrapperMethod(*cType.arrayElementType(), context, options)
+ + u"[]"_s;
+ }
+
+ if (avoidProtectedHack() && cType.isEnum()) {
+ auto metaEnum = api().findAbstractMetaEnum(cType.typeEntry());
+ if (metaEnum && metaEnum->isProtected())
+ return protectedEnumSurrogateName(metaEnum.value());
+ }
+
+ return translateType(cType, context, options);
+}
+
+bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClassCPtr &metaClass)
+{
+ const auto wrapper = metaClass->cppWrapper();
+ return wrapper.testFlag(AbstractMetaClass::CppVirtualMethodWrapper)
+ || (avoidProtectedHack()
+ && wrapper.testFlag(AbstractMetaClass::CppProtectedHackWrapper));
+}
+
+bool ShibokenGenerator::shouldGenerateMetaObjectFunctions(const AbstractMetaClassCPtr &metaClass)
+{
+ return usePySideExtensions()
+ && (!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
+ && !metaClass->typeEntry()->typeFlags()
+ .testFlag(ComplexTypeEntry::DisableQtMetaObjectFunctions)
+ && isQObject(metaClass);
+}
+
+ShibokenGenerator::FunctionGeneration ShibokenGenerator::functionGeneration(
+ const AbstractMetaFunctionCPtr &func)
+{
+ FunctionGeneration result;
+
+ const auto functionType = func->functionType();
+ switch (functionType) {
+ case AbstractMetaFunction::ConversionOperator:
+ case AbstractMetaFunction::AssignmentOperatorFunction:
+ case AbstractMetaFunction::MoveAssignmentOperatorFunction:
+ case AbstractMetaFunction::DestructorFunction:
+ case AbstractMetaFunction::SignalFunction:
+ case AbstractMetaFunction::GetAttroFunction:
+ case AbstractMetaFunction::SetAttroFunction:
+ return result;
+ default:
+ if (func->isUserAdded() || func->usesRValueReferences() || !func->isWhiteListed())
+ return result;
+ break;
+ }
+
+ const bool notModifiedRemoved = !func->isModifiedRemoved();
+ const bool isPrivate = func->isPrivate() && !func->isVisibilityModifiedToPrivate();
+ switch (functionType) {
+ case AbstractMetaFunction::ConstructorFunction:
+ if (!isPrivate && notModifiedRemoved)
+ result.setFlag(FunctionGenerationFlag::WrapperConstructor);
+ return result;
+ case AbstractMetaFunction::CopyConstructorFunction:
+ if (!isPrivate && notModifiedRemoved)
+ result.setFlag(FunctionGenerationFlag::WrapperSpecialCopyConstructor);
+ return result;
+ case AbstractMetaFunction::NormalFunction:
+ case AbstractMetaFunction::SlotFunction:
+ if (avoidProtectedHack() && func->isProtected())
+ result.setFlag(FunctionGenerationFlag::ProtectedWrapper);
+ break;
+ default:
+ break;
+ }
+
+ // Check on virtuals (including operators).
+ const bool isAbstract = func->isAbstract();
+ if (!(isAbstract || func->isVirtual())
+ || func->cppAttributes().testFlag(FunctionAttribute::Final)
+ || func->isModifiedFinal()) {
+ return result;
+ }
+
+ // MetaObject virtuals only need to be declared; CppGenerator creates a
+ // special implementation.
+ if (functionType == AbstractMetaFunction::NormalFunction
+ && usePySideExtensions() && isQObject(func->ownerClass())) {
+ const QString &name = func->name();
+ if (name == u"metaObject"_s || name == u"qt_metacall") {
+ result.setFlag(FunctionGenerationFlag::QMetaObjectMethod);
+ return result;
+ }
+ }
+
+ // Pure virtual functions need a default implementation even if private.
+ if (isAbstract || (notModifiedRemoved && !isPrivate))
+ result.setFlag(FunctionGenerationFlag::VirtualMethod);
+
+ return result;
+}
+
+AbstractMetaFunctionCList ShibokenGenerator::implicitConversions(const TypeEntryCPtr &t) const
+{
+ if (!generateImplicitConversions() || !t->isValue())
+ return {};
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(t);
+ auto customConversion = vte->customConversion();
+ if (customConversion && customConversion->replaceOriginalTargetToNativeConversions())
+ return {};
+
+ auto result = api().implicitConversions(t);
+ auto end = std::remove_if(result.begin(), result.end(),
+ [](const AbstractMetaFunctionCPtr &f) {
+ return f->isUserAdded();
+ });
+ result.erase(end, result.end());
+ return result;
+}
+
+QString ShibokenGenerator::wrapperName(const AbstractMetaClassCPtr &metaClass)
+{
+ Q_ASSERT(shouldGenerateCppWrapper(metaClass));
+ QString result = metaClass->name();
+ if (metaClass->enclosingClass()) // is a inner class
+ result.replace(u"::"_s, u"_"_s);
+ return result + u"Wrapper"_s;
+}
+
+QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClassCPtr &metaClass)
+{
+ QString fullClassName = metaClass->name();
+ auto enclosing = metaClass->enclosingClass();
+ while (enclosing) {
+ if (NamespaceTypeEntry::isVisibleScope(enclosing->typeEntry()))
+ fullClassName.prepend(enclosing->name() + u'.');
+ enclosing = enclosing->enclosingClass();
+ }
+ fullClassName.prepend(metaClass->typeEntry()->targetLangPackage() + u'.');
+ return fullClassName;
+}
+
+QString ShibokenGenerator::headerFileNameForContext(const GeneratorContext &context)
+{
+ return fileNameForContextHelper(context, u"_wrapper.h"_s);
+}
+
+// PYSIDE-500: When avoiding the protected hack, also include the inherited
+// wrapper classes of the *current* module, because without the protected hack,
+// we sometimes need to cast inherited wrappers. Inherited classes
+// of *other* modules are completely regenerated by the header generator
+// since the wrapper headers are not installed.
+
+IncludeGroup ShibokenGenerator::baseWrapperIncludes(const GeneratorContext &classContext) const
+{
+ IncludeGroup result{u"Wrappers"_s, {}};
+ if (!classContext.useWrapper() || !avoidProtectedHack()
+ || classContext.forSmartPointer()) {
+ return result;
+ }
+
+ const auto moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
+ const auto &baseClasses = allBaseClasses(classContext.metaClass());
+ for (const auto &base : baseClasses) {
+ const auto te = base->typeEntry();
+ if (te->codeGeneration() == TypeEntry::GenerateCode) { // current module
+ const auto context = contextForClass(base);
+ if (context.useWrapper()) {
+ const QString header = headerFileNameForContext(context);
+ const auto type = typeSystemTypeEntry(te) == moduleEntry
+ ? Include::LocalPath : Include::IncludePath;
+ result.append(Include(type, header));
+ }
+ }
+ }
+ return result;
+}
+
+QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunctionCPtr &func, bool forceFunc)
+{
+ QString funcName;
+ if (func->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(func);
+ else
+ funcName = func->name();
+ if (func->ownerClass()) {
+ QString fullClassName = fullPythonClassName(func->ownerClass());
+ if (func->isConstructor()) {
+ funcName = fullClassName;
+ if (forceFunc)
+ funcName.append(u".__init__"_s);
+ }
+ else {
+ funcName.prepend(fullClassName + u'.');
+ }
+ }
+ else {
+ funcName = packageName() + u'.' + func->name();
+ }
+ return funcName;
+}
+
+bool ShibokenGenerator::wrapperDiagnostics()
+{
+ return m_options.wrapperDiagnostics;
+}
+
+QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum &metaEnum)
+{
+ QString result = metaEnum.fullName();
+ result.replace(u'.', u'_');
+ result.replace(u"::"_s, u"_"_s);
+ return result + u"_Surrogate"_s;
+}
+
+QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunctionCPtr &func)
+{
+ QString result;
+
+ // PYSIDE-331: For inherited functions, we need to find the same labels.
+ // Therefore we use the implementing class.
+ if (func->implementingClass()) {
+ result = cpythonBaseName(func->implementingClass()->typeEntry());
+ if (func->isConstructor()) {
+ result += u"_Init"_s;
+ } else {
+ result += u"Func_"_s;
+ if (func->isOperatorOverload())
+ result += ShibokenGenerator::pythonOperatorFunctionName(func);
+ else
+ result += func->name();
+ }
+ } else {
+ result = u"Sbk"_s + moduleName() + u"Module_"_s + func->name();
+ }
+
+ return result;
+}
+
+QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunctionCPtr &func)
+{
+ if (!func->ownerClass())
+ return {};
+ return cpythonBaseName(func->ownerClass()->typeEntry()) + u"Method_"_s
+ + func->name();
+}
+
+QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonBaseName(metaClass) + u"_getsetlist"_s;
+}
+
+QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonBaseName(metaClass) + u"_setattro"_s;
+}
+
+
+QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonBaseName(metaClass) + u"_getattro"_s;
+}
+
+QString ShibokenGenerator::cpythonGetterFunctionName(const QString &name,
+ const AbstractMetaClassCPtr &enclosingClass)
+{
+ return cpythonBaseName(enclosingClass) + "_get_"_L1 + name;
+}
+
+QString ShibokenGenerator::cpythonSetterFunctionName(const QString &name,
+ const AbstractMetaClassCPtr &enclosingClass)
+{
+ return cpythonBaseName(enclosingClass) + "_set_"_L1 + name;
+}
+
+QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField &metaField)
+{
+ return cpythonGetterFunctionName(metaField.name(), metaField.enclosingClass());
+}
+
+QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField &metaField)
+{
+ return cpythonSetterFunctionName(metaField.name(), metaField.enclosingClass());
+}
+
+QString ShibokenGenerator::cpythonGetterFunctionName(const QPropertySpec &property,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonGetterFunctionName(property.name(), metaClass);
+}
+
+QString ShibokenGenerator::cpythonSetterFunctionName(const QPropertySpec &property,
+ const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonSetterFunctionName(property.name(), metaClass);
+}
+
+static QString cpythonEnumFlagsName(const QString &moduleName,
+ const QString &qualifiedCppName)
+{
+ QString result = u"Sbk"_s + moduleName + u'_' + qualifiedCppName;
+ result.replace(u"::"_s, u"_"_s);
+ return result;
+}
+
+QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntryCPtr &enumEntry)
+{
+ QString p = enumEntry->targetLangPackage();
+ p.replace(u'.', u'_');
+ return cpythonEnumFlagsName(p, enumEntry->qualifiedCppName());
+}
+
+QString ShibokenGenerator::cpythonEnumName(const AbstractMetaEnum &metaEnum)
+{
+ return cpythonEnumName(metaEnum.typeEntry());
+}
+
+QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntryCPtr &flagsEntry)
+{
+ QString p = flagsEntry->targetLangPackage();
+ p.replace(u'.', u'_');
+ return cpythonEnumFlagsName(p, flagsEntry->originalName());
+}
+
+QString ShibokenGenerator::cpythonFlagsName(const AbstractMetaEnum *metaEnum)
+{
+ const auto flags = metaEnum->typeEntry()->flags();
+ return flags ? cpythonFlagsName(flags) : QString{};
+}
+
+QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonBaseName(metaClass->typeEntry()) + u"SpecialCastFunction"_s;
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClassCPtr &metaClass,
+ const QString &argName)
+{
+ return cpythonWrapperCPtr(metaClass->typeEntry(), argName);
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType &metaType,
+ const QString &argName)
+{
+ if (!metaType.isWrapperType())
+ return {};
+ return u"reinterpret_cast< ::"_s + metaType.cppSignature()
+ + u" *>(Shiboken::Conversions::cppPointer("_s + cpythonTypeNameExt(metaType)
+ + u", reinterpret_cast<SbkObject *>("_s + argName + u")))"_s;
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntryCPtr &type,
+ const QString &argName)
+{
+ if (!type->isWrapperType())
+ return QString();
+ return u"reinterpret_cast< "_s + getFullTypeName(type)
+ + u" *>(Shiboken::Conversions::cppPointer("_s + cpythonTypeNameExt(type)
+ + u", reinterpret_cast<SbkObject *>("_s + argName + u")))"_s;
+}
+
+void ShibokenGenerator::writeToPythonConversion(TextStream & s, const AbstractMetaType &type,
+ const AbstractMetaClassCPtr & /* context */,
+ const QString &argumentName)
+{
+ s << cpythonToPythonConversionFunction(type) << argumentName << ')';
+}
+
+void ShibokenGenerator::writeToCppConversion(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const QString &inArgName, const QString &outArgName)
+{
+ s << cpythonToCppConversionFunction(metaClass) << inArgName << ", &" << outArgName << ')';
+}
+
+void ShibokenGenerator::writeToCppConversion(TextStream &s, const AbstractMetaType &type,
+ const QString &inArgName,
+ const QString &outArgName)
+{
+ s << cpythonToCppConversionFunction(type) << inArgName << ", &" << outArgName << ')';
+}
+
+bool ShibokenGenerator::shouldRejectNullPointerArgument(const AbstractMetaFunctionCPtr &func,
+ int argIndex)
+{
+ if (argIndex < 0 || argIndex >= func->arguments().size())
+ return false;
+
+ const AbstractMetaArgument &arg = func->arguments().at(argIndex);
+ if (arg.type().isValueTypeWithCopyConstructorOnly())
+ return true;
+
+ // Argument type is not a pointer, a None rejection should not be
+ // necessary because the type checking would handle that already.
+ if (!arg.type().isPointer())
+ return false;
+ if (arg.isModifiedRemoved())
+ return false;
+ for (const auto &funcMod : func->modifications()) {
+ for (const ArgumentModification &argMod : funcMod.argument_mods()) {
+ if (argMod.index() == argIndex + 1 && argMod.noNullPointers())
+ return true;
+ }
+ }
+ return false;
+}
+
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType &type)
+{
+ if (type.isCString())
+ return u"PyString"_s;
+ return cpythonBaseName(type.typeEntry());
+}
+
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonBaseName(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::containerCpythonBaseName(const ContainerTypeEntryCPtr &ctype)
+{
+ switch (ctype->containerKind()) {
+ case ContainerTypeEntry::SetContainer:
+ return u"PySet"_s;
+ case ContainerTypeEntry::MapContainer:
+ case ContainerTypeEntry::MultiMapContainer:
+ return u"PyDict"_s;
+ case ContainerTypeEntry::ListContainer:
+ case ContainerTypeEntry::PairContainer:
+ case ContainerTypeEntry::SpanContainer:
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ return cPySequenceT;
+}
+
+QString ShibokenGenerator::cpythonBaseName(const TypeEntryCPtr &type)
+{
+ QString baseName;
+ if (type->isWrapperType() || type->isNamespace()) { // && type->referenceType() == NoReference) {
+ baseName = u"Sbk_"_s + type->name();
+ } else if (type->isPrimitive()) {
+ const auto ptype = basicReferencedTypeEntry(type);
+ baseName = ptype->hasTargetLangApiType()
+ ? ptype->targetLangApiName() : pythonPrimitiveTypeName(ptype->name());
+ } else if (type->isEnum()) {
+ baseName = cpythonEnumName(std::static_pointer_cast<const EnumTypeEntry>(type));
+ } else if (type->isFlags()) {
+ baseName = cpythonFlagsName(std::static_pointer_cast<const FlagsTypeEntry>(type));
+ } else if (type->isContainer()) {
+ const auto ctype = std::static_pointer_cast<const ContainerTypeEntry>(type);
+ baseName = containerCpythonBaseName(ctype);
+ } else {
+ baseName = cPyObjectT;
+ }
+ return baseName.replace(u"::"_s, u"_"_s);
+}
+
+QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonTypeName(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonTypeName(const TypeEntryCPtr &type)
+{
+ return cpythonBaseName(type) + u"_TypeF()"_s;
+}
+
+QString ShibokenGenerator::converterObject(const AbstractMetaType &type)
+{
+ if (type.isCString())
+ return u"Shiboken::Conversions::PrimitiveTypeConverter<const char *>()"_s;
+ if (type.isVoidPointer())
+ return u"Shiboken::Conversions::PrimitiveTypeConverter<void *>()"_s;
+ const AbstractMetaTypeList nestedArrayTypes = type.nestedArrayTypes();
+ if (!nestedArrayTypes.isEmpty() && nestedArrayTypes.constLast().isCppPrimitive()) {
+ return "Shiboken::Conversions::ArrayTypeConverter<"_L1
+ + nestedArrayTypes.constLast().minimalSignature()
+ + u">("_s + QString::number(nestedArrayTypes.size())
+ + u')';
+ }
+
+ auto typeEntry = type.typeEntry();
+ if (typeEntry->isContainer() || typeEntry->isSmartPointer()) {
+ return convertersVariableName(typeEntry->targetLangPackage())
+ + u'[' + getTypeIndexVariableName(type) + u']';
+ }
+ return converterObject(typeEntry);
+}
+
+QString ShibokenGenerator::converterObject(const TypeEntryCPtr &type)
+{
+ if (isExtendedCppPrimitive(type))
+ return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()")
+ .arg(type->qualifiedCppName());
+ if (type->isWrapperType())
+ return QString::fromLatin1("PepType_SOTP(reinterpret_cast<PyTypeObject *>(%1))->converter")
+ .arg(cpythonTypeNameExt(type));
+ if (type->isEnum() || type->isFlags())
+ return QString::fromLatin1("PepType_SETP(reinterpret_cast<SbkEnumType *>(%1))->converter")
+ .arg(cpythonTypeNameExt(type));
+
+ if (type->isArray()) {
+ qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName();
+ return {};
+ }
+
+ /* the typedef'd primitive types case */
+ auto pte = std::dynamic_pointer_cast<const PrimitiveTypeEntry>(type);
+ if (!pte) {
+ qDebug() << "Warning: the Qt5 primitive type is unknown" << type->qualifiedCppName();
+ return {};
+ }
+ pte = basicReferencedTypeEntry(pte);
+ if (pte->isPrimitive() && !isCppPrimitive(pte) && !pte->customConversion()) {
+ return u"Shiboken::Conversions::PrimitiveTypeConverter<"_s
+ + pte->qualifiedCppName() + u">()"_s;
+ }
+
+ return convertersVariableName(type->targetLangPackage())
+ + u'[' + getTypeIndexVariableName(type) + u']';
+}
+
+QString ShibokenGenerator::cpythonTypeNameExtSet(const TypeEntryCPtr &type)
+{
+ return cppApiVariableName(type->targetLangPackage()) + u'['
+ + getTypeIndexVariableName(type) + "].type"_L1;
+}
+
+QString ShibokenGenerator::cpythonTypeNameExtSet(const AbstractMetaType &type)
+{
+ return cppApiVariableName(type.typeEntry()->targetLangPackage()) + u'['
+ + getTypeIndexVariableName(type) + "].type"_L1;
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntryCPtr &type)
+{
+ return "Shiboken::Module::get("_L1 + cppApiVariableName(type->targetLangPackage())
+ + u'[' + getTypeIndexVariableName(type) + "])"_L1;
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType &type)
+{
+ return u"Shiboken::Module::get("_s + cppApiVariableName(type.typeEntry()->targetLangPackage())
+ + u'[' + getTypeIndexVariableName(type) + "])"_L1;
+}
+
+QString ShibokenGenerator::fixedCppTypeName(const TargetToNativeConversion &toNative)
+{
+ if (toNative.sourceType())
+ return fixedCppTypeName(toNative.sourceType());
+ return toNative.sourceTypeName();
+}
+QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType &type)
+{
+ return fixedCppTypeName(type.typeEntry(), type.cppSignature());
+}
+
+static QString _fixedCppTypeName(QString typeName)
+{
+ typeName.remove(u' ');
+ typeName.replace(u'.', u'_');
+ typeName.replace(u',', u'_');
+ typeName.replace(u'<', u'_');
+ typeName.replace(u'>', u'_');
+ typeName.replace(u"::"_s, u"_"_s);
+ typeName.replace(u"*"_s, u"PTR"_s);
+ typeName.replace(u"&"_s, u"REF"_s);
+ return typeName;
+}
+QString ShibokenGenerator::fixedCppTypeName(const TypeEntryCPtr &type, QString typeName)
+{
+ if (typeName.isEmpty())
+ typeName = type->qualifiedCppName();
+ if (!type->generateCode()) {
+ typeName.prepend(u'_');
+ typeName.prepend(type->targetLangPackage());
+ }
+ return _fixedCppTypeName(typeName);
+}
+
+QString ShibokenGenerator::pythonPrimitiveTypeName(const QString &cppTypeName)
+{
+ const auto &mapping = primitiveTypesCorrespondences();
+ const auto it = mapping.constFind(cppTypeName);
+ if (it == mapping.cend())
+ throw Exception(u"Primitive type not found: "_s + cppTypeName);
+ return it.value();
+}
+
+QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunctionCPtr &func)
+{
+ QString op = Generator::pythonOperatorFunctionName(func->originalName());
+ if (op.isEmpty()) {
+ qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func.get());
+ return "__UNKNOWN_OPERATOR__"_L1;
+ }
+ if (func->arguments().isEmpty()) {
+ if (op == u"__sub__")
+ op = u"__neg__"_s;
+ else if (op == u"__add__")
+ op = u"__pos__"_s;
+ } else if (func->isStatic() && func->arguments().size() == 2) {
+ // If a operator overload function has 2 arguments and
+ // is static we assume that it is a reverse operator.
+ op = op.insert(2, u'r');
+ }
+ return op;
+}
+
+bool ShibokenGenerator::isNumber(const QString &cpythonApiName)
+{
+ return cpythonApiName == pyFloatT || cpythonApiName == pyLongT
+ || cpythonApiName == pyBoolT;
+}
+
+static std::optional<TypeSystem::CPythonType>
+ targetLangApiCPythonType(const PrimitiveTypeEntryCPtr &t)
+{
+ if (!t->hasTargetLangApiType())
+ return {};
+ const auto cte = t->targetLangApiType();
+ if (cte->type() != TypeEntry::PythonType)
+ return {};
+ return std::static_pointer_cast<const PythonTypeEntry>(cte)->cPythonType();
+}
+
+bool ShibokenGenerator::isNumber(const TypeEntryCPtr &type)
+{
+ if (!type->isPrimitive())
+ return false;
+ const auto pte = basicReferencedTypeEntry(type);
+ const auto cPythonTypeOpt = targetLangApiCPythonType(pte);
+ // FIXME PYSIDE-1660: Return false here after making primitive types built-in?
+ if (!cPythonTypeOpt.has_value()) {
+ const auto &mapping = primitiveTypesCorrespondences();
+ const auto it = mapping.constFind(pte->name());
+ return it != mapping.cend() && isNumber(it.value());
+ }
+ const auto cPythonType = cPythonTypeOpt.value();
+ return cPythonType == TypeSystem::CPythonType::Bool
+ || cPythonType == TypeSystem::CPythonType::Float
+ || cPythonType == TypeSystem::CPythonType::Integer;
+}
+
+bool ShibokenGenerator::isNumber(const AbstractMetaType &type)
+{
+ return isNumber(type.typeEntry());
+}
+
+bool ShibokenGenerator::isPyInt(const TypeEntryCPtr &type)
+{
+ if (!type->isPrimitive())
+ return false;
+ const auto pte = basicReferencedTypeEntry(type);
+ const auto cPythonTypeOpt = targetLangApiCPythonType(pte);
+ // FIXME PYSIDE-1660: Return false here after making primitive types built-in?
+ if (!cPythonTypeOpt.has_value()) {
+ const auto &mapping = primitiveTypesCorrespondences();
+ const auto it = mapping.constFind(pte->name());
+ return it != mapping.cend() && it.value() == pyLongT;
+ }
+ return cPythonTypeOpt.value() == TypeSystem::CPythonType::Integer;
+}
+
+bool ShibokenGenerator::isPyInt(const AbstractMetaType &type)
+{
+ return isPyInt(type.typeEntry());
+}
+
+bool ShibokenGenerator::isNullPtr(const QString &value)
+{
+ return value == u"0" || value == u"nullptr"
+ || value == u"NULLPTR" || value == u"{}";
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType)
+{
+ const auto typeEntry = metaType.typeEntry();
+ if (typeEntry->isCustom()) {
+ const auto cte = std::static_pointer_cast<const CustomTypeEntry>(typeEntry);
+ if (cte->hasCheckFunction())
+ return cte->checkFunction();
+ throw Exception(msgUnknownCheckFunction(typeEntry));
+ }
+
+ if (metaType.isExtendedCppPrimitive()) {
+ if (metaType.isCString())
+ return u"Shiboken::String::check"_s;
+ if (metaType.isVoidPointer())
+ return u"true"_s;
+ return cpythonCheckFunction(typeEntry);
+ }
+
+ if (typeEntry->isContainer()) {
+ QString typeCheck = u"Shiboken::Conversions::"_s;
+ ContainerTypeEntry::ContainerKind type =
+ std::static_pointer_cast<const ContainerTypeEntry>(typeEntry)->containerKind();
+ if (type == ContainerTypeEntry::ListContainer
+ || type == ContainerTypeEntry::SetContainer) {
+ const QString containerType = type == ContainerTypeEntry::SetContainer
+ ? u"Iterable"_s : u"Sequence"_s;
+ const AbstractMetaType &type = metaType.instantiations().constFirst();
+ if (type.isPointerToWrapperType()) {
+ typeCheck += u"check"_s + containerType + u"Types("_s
+ + cpythonTypeNameExt(type) + u", "_s;
+ } else if (type.isWrapperType()) {
+ typeCheck += u"convertible"_s + containerType
+ + u"Types("_s + cpythonTypeNameExt(type) + u", "_s;
+ } else {
+ typeCheck += u"convertible"_s + containerType
+ + u"Types("_s + converterObject(type) + u", "_s;
+ }
+ } else if (type == ContainerTypeEntry::MapContainer
+ || type == ContainerTypeEntry::MultiMapContainer
+ || type == ContainerTypeEntry::PairContainer) {
+
+ QString pyType;
+ if (type == ContainerTypeEntry::PairContainer)
+ pyType = u"Pair"_s;
+ else if (type == ContainerTypeEntry::MultiMapContainer)
+ pyType = u"MultiDict"_s;
+ else
+ pyType = u"Dict"_s;
+
+ const AbstractMetaType &firstType = metaType.instantiations().constFirst();
+ const AbstractMetaType &secondType = metaType.instantiations().constLast();
+ if (firstType.isPointerToWrapperType() && secondType.isPointerToWrapperType()) {
+ QTextStream(&typeCheck) << "check" << pyType << "Types("
+ << cpythonTypeNameExt(firstType) << ", "
+ << cpythonTypeNameExt(secondType) << ", ";
+ } else {
+ QTextStream(&typeCheck) << "convertible" << pyType << "Types("
+ << converterObject(firstType) << ", "
+ << (firstType.isPointerToWrapperType() ? "true" : "false")
+ << ", " << converterObject(secondType) << ", "
+ << (secondType.isPointerToWrapperType() ? "true" :"false")
+ << ", ";
+ }
+ }
+ return typeCheck;
+ }
+ return cpythonCheckFunction(typeEntry);
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(TypeEntryCPtr type)
+{
+ if (type->isCustom()) {
+ const auto cte = std::static_pointer_cast<const CustomTypeEntry>(type);
+ if (cte->hasCheckFunction())
+ return cte->checkFunction();
+ throw Exception(msgUnknownCheckFunction(type));
+ }
+
+ if (type->isEnum() || type->isFlags() || type->isWrapperType())
+ return u"SbkObject_TypeCheck("_s + cpythonTypeNameExt(type) + u", "_s;
+
+ if (type->isPrimitive())
+ type = basicReferencedTypeEntry(type);
+
+ if (auto tla = type->targetLangApiType()) {
+ if (tla->hasCheckFunction())
+ return tla->checkFunction();
+ }
+
+ if (isExtendedCppPrimitive(type))
+ return pythonPrimitiveTypeName(type->name()) + u"_Check"_s;
+
+ return cpythonIsConvertibleFunction(type);
+}
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntryCPtr &type)
+{
+ if (type->isWrapperType()) {
+ QString result = u"Shiboken::Conversions::"_s;
+ bool isValue = false;
+ if (type->isValue()) {
+ const auto cte = std::static_pointer_cast<const ComplexTypeEntry>(type);
+ isValue = !cte->isValueTypeWithCopyConstructorOnly();
+ }
+ result += isValue ? u"isPythonToCppValueConvertible"_s
+ : u"isPythonToCppPointerConvertible"_s;
+ result += u"("_s + cpythonTypeNameExt(type) + u", "_s;
+ return result;
+ }
+ return QString::fromLatin1("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
+ .arg(converterObject(type));
+}
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType &metaType)
+{
+ const auto typeEntry = metaType.typeEntry();
+ if (typeEntry->isCustom()) {
+ const auto cte = std::static_pointer_cast<const CustomTypeEntry>(typeEntry);
+ if (cte->hasCheckFunction())
+ return cte->checkFunction();
+ throw Exception(msgUnknownCheckFunction(typeEntry));
+ }
+
+ QString result = u"Shiboken::Conversions::"_s;
+ if (metaType.generateOpaqueContainer()) {
+ result += u"pythonToCppReferenceConversion("_s
+ + converterObject(metaType) + u", "_s;
+ return result;
+ }
+ if (metaType.isWrapperType()) {
+ if (metaType.isPointer() || metaType.isValueTypeWithCopyConstructorOnly()) {
+ result += u"pythonToCppPointerConversion"_s;
+ } else if (metaType.referenceType() == LValueReference
+ || (metaType.referenceType() == RValueReference && typeEntry->isObject())) {
+ result += u"pythonToCppReferenceConversion"_s;
+ } else {
+ result += u"pythonToCppValueConversion"_s;
+ }
+ result += u'(' + cpythonTypeNameExt(metaType) + u", "_s;
+ return result;
+ }
+ result += u"pythonToCppConversion("_s + converterObject(metaType);
+ // Write out array sizes if known
+ const AbstractMetaTypeList nestedArrayTypes = metaType.nestedArrayTypes();
+ if (!nestedArrayTypes.isEmpty() && nestedArrayTypes.constLast().isCppPrimitive()) {
+ const int dim1 = metaType.arrayElementCount();
+ const int dim2 = nestedArrayTypes.constFirst().isArray()
+ ? nestedArrayTypes.constFirst().arrayElementCount() : -1;
+ result += u", "_s + QString::number(dim1)
+ + u", "_s + QString::number(dim2);
+ }
+ result += u", "_s;
+ return result;
+}
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgument &metaArg)
+{
+ return cpythonIsConvertibleFunction(metaArg.type());
+}
+
+QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClassCPtr &metaClass)
+{
+ return u"Shiboken::Conversions::pythonToCppPointer("_s
+ + cpythonTypeNameExt(metaClass->typeEntry()) + u", "_s;
+}
+
+QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType &type)
+{
+ if (type.isWrapperType()) {
+ return u"Shiboken::Conversions::pythonToCpp"_s
+ + (type.isPointer() ? u"Pointer"_s : u"Copy"_s)
+ + u'(' + cpythonTypeNameExt(type) + u", "_s;
+ }
+ return "Shiboken::Conversions::pythonToCppCopy("_L1
+ + converterObject(type) + ", "_L1;
+}
+
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType &type)
+{
+ if (type.isWrapperType()) {
+ QString conversion;
+ if (type.referenceType() == LValueReference
+ && !(type.isValue() && type.isConstant()) && !type.isPointer()) {
+ conversion = u"reference"_s;
+ } else if (type.isValue() || type.isSmartPointer()) {
+ conversion = u"copy"_s;
+ } else {
+ conversion = u"pointer"_s;
+ }
+ QString result = u"Shiboken::Conversions::"_s + conversion
+ + u"ToPython("_s
+ + cpythonTypeNameExt(type) + u", "_s;
+ if (conversion != u"pointer")
+ result += u'&';
+ return result;
+ }
+
+ const auto indirections = type.indirections() - 1;
+ return u"Shiboken::Conversions::copyToPython("_s + converterObject(type)
+ + u", "_s + AbstractMetaType::dereferencePrefix(indirections);
+}
+
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClassCPtr &metaClass)
+{
+ return cpythonToPythonConversionFunction(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntryCPtr &type)
+{
+ if (type->isWrapperType()) {
+ const QString conversion = type->isValue() ? u"copy"_s : u"pointer"_s;
+ QString result = u"Shiboken::Conversions::"_s + conversion
+ + u"ToPython("_s + cpythonTypeNameExt(type)
+ + u", "_s;
+ if (conversion != u"pointer")
+ result += u'&';
+ return result;
+ }
+
+ return u"Shiboken::Conversions::copyToPython("_s
+ + converterObject(type) + u", &"_s;
+}
+
+QString ShibokenGenerator::argumentString(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &argument,
+ Options options) const
+{
+ auto type = options.testFlag(OriginalTypeDescription)
+ ? argument.type() : argument.modifiedType();
+
+
+ QString arg = translateType(type, func->implementingClass(), options);
+
+ if (argument.isTypeModified())
+ arg.replace(u'$', u'.'); // Haehh?
+
+ // "int a", "int a[]"
+ const auto arrayPos = arg.indexOf(u'[');
+ if (arrayPos != -1)
+ arg.insert(arrayPos, u' ' + argument.name());
+ else
+ arg.append(u' ' + argument.name());
+
+ if ((options & Generator::SkipDefaultValues) != Generator::SkipDefaultValues &&
+ !argument.originalDefaultValueExpression().isEmpty())
+ {
+ QString default_value = argument.originalDefaultValueExpression();
+ if (default_value == u"NULL")
+ default_value = NULL_PTR;
+
+ //WORKAROUND: fix this please
+ if (default_value.startsWith(u"new "))
+ default_value.remove(0, 4);
+
+ arg += u" = "_s + default_value;
+ }
+
+ return arg;
+}
+
+void ShibokenGenerator::writeArgument(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &argument,
+ Options options) const
+{
+ s << argumentString(func, argument, options);
+}
+
+void ShibokenGenerator::writeFunctionArguments(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ Options options) const
+{
+ int argUsed = 0;
+ if (func->isUserAddedPythonOverride()) {
+ s << "Shiboken::GilState &gil, PyObject *" << PYTHON_OVERRIDE_VAR;
+ argUsed += 2;
+ }
+ for (const auto &arg : func->arguments()) {
+ if (options.testFlag(Generator::SkipRemovedArguments) && arg.isModifiedRemoved())
+ continue;
+
+ if (argUsed != 0)
+ s << ", ";
+ writeArgument(s, func, arg, options);
+ argUsed++;
+ }
+}
+
+GeneratorContext ShibokenGenerator::contextForClass(const AbstractMetaClassCPtr &c) const
+{
+ GeneratorContext result = Generator::contextForClass(c);
+ if (shouldGenerateCppWrapper(c)) {
+ result.m_type = GeneratorContext::WrappedClass;
+ result.m_wrappername = wrapperName(c);
+ }
+ return result;
+}
+
+QString ShibokenGenerator::functionReturnType(const AbstractMetaFunctionCPtr &func, Options options) const
+{
+ if (func->isTypeModified() && !options.testFlag(OriginalTypeDescription))
+ return func->modifiedTypeName();
+ return translateType(func->type(), func->implementingClass(), options);
+}
+
+QString ShibokenGenerator::functionSignature(const AbstractMetaFunctionCPtr &func,
+ const QString &prepend,
+ const QString &append,
+ Options options,
+ int /* argCount */) const
+{
+ StringStream s(TextStream::Language::Cpp);
+ // The actual function
+ if (!options.testFlag(Option::SkipDefaultValues) && func->isStatic()) // Declaration
+ s << "static ";
+ if (func->isEmptyFunction() || func->needsReturnType())
+ s << functionReturnType(func, options) << ' ';
+ else
+ options |= Generator::SkipReturnType;
+
+ // name
+ QString name(func->originalName());
+ if (func->isConstructor())
+ name = wrapperName(func->ownerClass());
+
+ s << prepend << name << append << '(';
+ writeFunctionArguments(s, func, options);
+ s << ')';
+
+ if (func->isConstant())
+ s << " const";
+
+ if (func->exceptionSpecification() == ExceptionSpecification::NoExcept)
+ s << " noexcept";
+
+ return s;
+}
+
+void ShibokenGenerator::writeArgumentNames(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ Options options)
+{
+ const AbstractMetaArgumentList arguments = func->arguments();
+ int argCount = 0;
+ for (const auto &argument : arguments) {
+ const int index = argument.argumentIndex() + 1;
+ if (options.testFlag(Generator::SkipRemovedArguments) && argument.isModifiedRemoved())
+ continue;
+ const auto &type = argument.type();
+ if (argCount > 0)
+ s << ", ";
+ const bool isVirtualCall = options.testFlag(Option::VirtualCall);
+ const bool useStdMove = isVirtualCall && type.isUniquePointer() && type.passByValue();
+ s << (useStdMove ? stdMove(argument.name()) : argument.name());
+
+ if (!isVirtualCall
+ && (func->hasConversionRule(TypeSystem::NativeCode, index)
+ || func->hasConversionRule(TypeSystem::TargetLangCode, index))
+ && !func->isConstructor()) {
+ s << CONV_RULE_OUT_VAR_SUFFIX;
+ }
+
+ argCount++;
+ }
+}
+
+void ShibokenGenerator::writeFunctionCall(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ Options options)
+{
+ s << (func->isConstructor() ? func->ownerClass()->qualifiedCppName() : func->originalName())
+ << '(';
+ writeArgumentNames(s, func, options);
+ s << ')';
+}
+
+ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverters() const
+{
+ ExtendedConverterData extConvs;
+ for (const auto &metaClass : api().classes()) {
+ // Use only the classes for the current module.
+ if (!shouldGenerate(metaClass->typeEntry()))
+ continue;
+ const auto &overloads = metaClass->operatorOverloads(OperatorQueryOption::ConversionOp);
+ for (const auto &convOp : overloads) {
+ // Get only the conversion operators that return a type from another module,
+ // that are value-types and were not removed in the type system.
+ const auto convType = convOp->type().typeEntry();
+ if (convType->generateCode() || !convType->isValue()
+ || convOp->isModifiedRemoved())
+ continue;
+ extConvs[convType].append(convOp->ownerClass());
+ }
+ }
+ return extConvs;
+}
+
+QList<CustomConversionPtr> ShibokenGenerator::getPrimitiveCustomConversions()
+{
+ QList<CustomConversionPtr> conversions;
+ const auto &primitiveTypeList = primitiveTypes();
+ for (const auto &type : primitiveTypeList) {
+ if (type->shouldGenerate() && isUserPrimitive(type) && type->hasCustomConversion())
+ conversions << type->customConversion();
+ }
+ return conversions;
+}
+
+static QString getArgumentsFromMethodCall(const QString &str)
+{
+ // It would be way nicer to be able to use a Perl like
+ // regular expression that accepts temporary variables
+ // to count the parenthesis.
+ // For more information check this:
+ // http://perl.plover.com/yak/regex/samples/slide083.html
+ static QLatin1String funcCall("%CPPSELF.%FUNCTION_NAME");
+ auto pos = str.indexOf(funcCall);
+ if (pos == -1)
+ return QString();
+ pos = pos + funcCall.size();
+ while (str.at(pos) == u' ' || str.at(pos) == u'\t')
+ ++pos;
+ if (str.at(pos) == u'(')
+ ++pos;
+ int begin = pos;
+ int counter = 1;
+ while (counter != 0) {
+ if (str.at(pos) == u'(')
+ ++counter;
+ else if (str.at(pos) == u')')
+ --counter;
+ ++pos;
+ }
+ return str.mid(begin, pos-begin-1);
+}
+
+QString ShibokenGenerator::getCodeSnippets(const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language)
+{
+ QString code;
+ for (const CodeSnip &snip : codeSnips) {
+ if ((position != TypeSystem::CodeSnipPositionAny && snip.position != position) || !(snip.language & language))
+ continue;
+ code.append(snip.code());
+ }
+ return code;
+}
+
+void ShibokenGenerator::processClassCodeSnip(QString &code, const GeneratorContext &context) const
+{
+ auto metaClass = context.metaClass();
+ // Replace template variable by the Python Type object
+ // for the class context in which the variable is used.
+ code.replace(u"%PYTHONTYPEOBJECT"_s,
+ u"(*"_s + cpythonTypeName(metaClass) + u')');
+ const QString className = context.effectiveClassName();
+ code.replace(u"%TYPE"_s, className);
+ code.replace(u"%CPPTYPE"_s, metaClass->name());
+
+ processCodeSnip(code, context.effectiveClassName());
+}
+
+void ShibokenGenerator::processCodeSnip(QString &code) const
+{
+ // replace "toPython" converters
+ replaceConvertToPythonTypeSystemVariable(code);
+
+ // replace "toCpp" converters
+ replaceConvertToCppTypeSystemVariable(code);
+
+ // replace "isConvertible" check
+ replaceIsConvertibleToCppTypeSystemVariable(code);
+
+ // replace "checkType" check
+ replaceTypeCheckTypeSystemVariable(code);
+}
+
+void ShibokenGenerator::processCodeSnip(QString &code, const QString &context) const
+{
+ try {
+ processCodeSnip(code);
+ } catch (const std::exception &e) {
+ throw Exception(msgSnippetError(context, e.what()));
+ }
+}
+
+ShibokenGenerator::ArgumentVarReplacementList
+ ShibokenGenerator::getArgumentReplacement(const AbstractMetaFunctionCPtr &func,
+ bool usePyArgs, TypeSystem::Language language,
+ const AbstractMetaArgument *lastArg)
+{
+ ArgumentVarReplacementList argReplacements;
+ TypeSystem::Language convLang = (language == TypeSystem::TargetLangCode)
+ ? TypeSystem::NativeCode : TypeSystem::TargetLangCode;
+ int removed = 0;
+ for (qsizetype i = 0; i < func->arguments().size(); ++i) {
+ const AbstractMetaArgument &arg = func->arguments().at(i);
+ QString argValue;
+ if (language == TypeSystem::TargetLangCode) {
+ const bool hasConversionRule = func->hasConversionRule(convLang, i + 1);
+ const bool argRemoved = arg.isModifiedRemoved();
+ if (argRemoved)
+ ++removed;
+ if (argRemoved && hasConversionRule)
+ argValue = arg.name() + CONV_RULE_OUT_VAR_SUFFIX;
+ else if (argRemoved || (lastArg && arg.argumentIndex() > lastArg->argumentIndex()))
+ argValue = CPP_ARG_REMOVED(i);
+ if (!argRemoved && argValue.isEmpty()) {
+ int argPos = i - removed;
+ AbstractMetaType type = arg.modifiedType();
+ if (type.typeEntry()->isCustom()) {
+ argValue = usePyArgs
+ ? pythonArgsAt(argPos) : PYTHON_ARG;
+ } else {
+ argValue = hasConversionRule
+ ? arg.name() + CONV_RULE_OUT_VAR_SUFFIX
+ : CPP_ARG_N(argPos);
+ const auto generatorArg = GeneratorArgument::fromMetaType(type);
+ AbstractMetaType::applyDereference(&argValue, generatorArg.indirections);
+ }
+ }
+ } else {
+ argValue = arg.name();
+ }
+ if (!argValue.isEmpty())
+ argReplacements << ArgumentVarReplacementPair(arg, argValue);
+
+ }
+ return argReplacements;
+}
+
+void ShibokenGenerator::writeClassCodeSnips(TextStream &s,
+ const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const GeneratorContext &context) const
+{
+ QString code = getCodeSnippets(codeSnips, position, language);
+ if (code.isEmpty())
+ return;
+ processClassCodeSnip(code, context);
+ s << "// Begin code injection\n" << code << "// End of code injection\n\n";
+}
+
+void ShibokenGenerator::writeCodeSnips(TextStream &s,
+ const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const
+{
+ QString code = getCodeSnippets(codeSnips, position, language);
+ if (code.isEmpty())
+ return;
+ processCodeSnip(code);
+ s << "// Begin code injection\n" << code << "// End of code injection\n\n";
+}
+
+static void replacePyArg0(TypeSystem::Language language, QString *code)
+{
+ static constexpr auto pyArg0 = "%PYARG_0"_L1;
+
+ if (!code->contains(pyArg0))
+ return;
+ if (language != TypeSystem::NativeCode) {
+ code->replace(pyArg0, PYTHON_RETURN_VAR);
+ return;
+ }
+
+ // pyResult is an AutoDecRef in overridden methods of wrapper classes which
+ // has a cast operator for PyObject *. This may however not work in all
+ // situations (fex _PyVarObject_CAST(op) defined as ((PyVarObject*)(op))).
+ // Append ".object()" unless it is followed by a '.' indicating explicit
+ // AutoDecRef member invocation.
+ static const QString pyObject = PYTHON_RETURN_VAR + u".object()"_s;
+ qsizetype pos{};
+ while ( (pos = code->indexOf(pyArg0)) >= 0) {
+ const auto next = pos + pyArg0.size();
+ const bool memberInvocation = next < code->size() && code->at(next) == u'.';
+ code->replace(pos, pyArg0.size(),
+ memberInvocation ? PYTHON_RETURN_VAR : pyObject);
+ }
+}
+
+void ShibokenGenerator::writeCodeSnips(TextStream &s,
+ const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaFunctionCPtr &func,
+ bool usePyArgs,
+ const AbstractMetaArgument *lastArg) const
+{
+ QString code = getCodeSnippets(codeSnips, position, language);
+ if (code.isEmpty())
+ return;
+
+ // Replace %PYARG_# variables.
+ replacePyArg0(language, &code);
+
+ static const QRegularExpression pyArgsRegex("%PYARG_(\\d+)"_L1);
+ Q_ASSERT(pyArgsRegex.isValid());
+ if (language == TypeSystem::TargetLangCode) {
+ if (usePyArgs) {
+ code.replace(pyArgsRegex, PYTHON_ARGS + u"[\\1-1]"_s);
+ } else {
+ static const QRegularExpression pyArgsRegexCheck("%PYARG_([2-9]+)"_L1);
+ Q_ASSERT(pyArgsRegexCheck.isValid());
+ const QRegularExpressionMatch match = pyArgsRegexCheck.match(code);
+ if (match.hasMatch()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << msgWrongIndex("%PYARG", match.captured(1), func.get());
+ return;
+ }
+ code.replace(u"%PYARG_1"_s, PYTHON_ARG);
+ }
+ } else {
+ // Replaces the simplest case of attribution to a
+ // Python argument on the binding virtual method.
+ static const QRegularExpression pyArgsAttributionRegex("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"_L1);
+ Q_ASSERT(pyArgsAttributionRegex.isValid());
+ code.replace(pyArgsAttributionRegex, u"PyTuple_SET_ITEM("_s
+ + PYTHON_ARGS + u".object(), \\1-1, \\2)"_s);
+ code.replace(pyArgsRegex, u"PyTuple_GET_ITEM("_s
+ + PYTHON_ARGS + u".object(), \\1-1)"_s);
+ }
+
+ // Replace %ARG#_TYPE variables.
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument &arg : arguments) {
+ QString argTypeVar = u"%ARG"_s + QString::number(arg.argumentIndex() + 1)
+ + u"_TYPE"_s;
+ QString argTypeVal = arg.type().cppSignature();
+ code.replace(argTypeVar, argTypeVal);
+ }
+
+ static const QRegularExpression cppArgTypeRegexCheck("%ARG(\\d+)_TYPE"_L1);
+ Q_ASSERT(cppArgTypeRegexCheck.isValid());
+ QRegularExpressionMatchIterator rit = cppArgTypeRegexCheck.globalMatch(code);
+ while (rit.hasNext()) {
+ QRegularExpressionMatch match = rit.next();
+ qCWarning(lcShiboken).noquote().nospace()
+ << msgWrongIndex("%ARG#_TYPE", match.captured(1), func.get());
+ }
+
+ // Replace template variable for return variable name.
+ if (func->isConstructor()) {
+ code.replace(u"%0."_s, u"cptr->"_s);
+ code.replace(u"%0"_s, u"cptr"_s);
+ } else if (!func->isVoid()) {
+ QString returnValueOp = func->type().isPointerToWrapperType()
+ ? u"%1->"_s : u"%1."_s;
+ if (func->type().isWrapperType())
+ code.replace(u"%0."_s, returnValueOp.arg(CPP_RETURN_VAR));
+ code.replace(u"%0"_s, CPP_RETURN_VAR);
+ }
+
+ // Replace template variable for self Python object.
+ QString pySelf = language == TypeSystem::NativeCode
+ ? u"pySelf"_s : u"self"_s;
+ code.replace(u"%PYSELF"_s, pySelf);
+
+ // Replace template variable for a pointer to C++ of this object.
+ if (func->implementingClass()) {
+ QString replacement = func->isStatic() ? u"%1::"_s : u"%1->"_s;
+ QString cppSelf;
+ if (func->isStatic())
+ cppSelf = func->ownerClass()->qualifiedCppName();
+ else if (language == TypeSystem::NativeCode)
+ cppSelf = u"this"_s;
+ else
+ cppSelf = CPP_SELF_VAR;
+
+ // On comparison operator CPP_SELF_VAR is always a reference.
+ if (func->isComparisonOperator())
+ replacement = u"%1."_s;
+
+ if (func->isVirtual() && !func->isAbstract() && (!avoidProtectedHack() || !func->isProtected())) {
+ QString methodCallArgs = getArgumentsFromMethodCall(code);
+ if (!methodCallArgs.isEmpty()) {
+ const QString pattern = u"%CPPSELF.%FUNCTION_NAME("_s + methodCallArgs + u')';
+ QString replacement = u"(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>("_s
+ + pySelf + u")) ? "_s;
+ if (func->name() == u"metaObject") {
+ QString wrapperClassName = wrapperName(func->ownerClass());
+ QString cppSelfVar = avoidProtectedHack()
+ ? u"%CPPSELF"_s
+ : u"reinterpret_cast<"_s + wrapperClassName + u" *>(%CPPSELF)"_s;
+ replacement += cppSelfVar + u"->::"_s + wrapperClassName
+ + u"::%FUNCTION_NAME("_s + methodCallArgs
+ + u") : %CPPSELF.%FUNCTION_NAME("_s + methodCallArgs + u"))"_s;
+ } else {
+ replacement += u"%CPPSELF->::%TYPE::%FUNCTION_NAME("_s + methodCallArgs
+ + u") : %CPPSELF.%FUNCTION_NAME("_s + methodCallArgs + u"))"_s;
+ }
+ code.replace(pattern, replacement);
+ }
+ }
+
+ code.replace(u"%CPPSELF."_s, replacement.arg(cppSelf));
+ code.replace(u"%CPPSELF"_s, cppSelf);
+
+ if (code.indexOf(u"%BEGIN_ALLOW_THREADS") > -1) {
+ if (code.count(u"%BEGIN_ALLOW_THREADS"_s) == code.count(u"%END_ALLOW_THREADS"_s)) {
+ code.replace(u"%BEGIN_ALLOW_THREADS"_s, BEGIN_ALLOW_THREADS);
+ code.replace(u"%END_ALLOW_THREADS"_s, END_ALLOW_THREADS);
+ } else {
+ qCWarning(lcShiboken) << "%BEGIN_ALLOW_THREADS and %END_ALLOW_THREADS mismatch";
+ }
+ }
+
+ // replace template variable for the Python Type object for the
+ // class implementing the method in which the code snip is written
+ if (func->isStatic()) {
+ code.replace(u"%PYTHONTYPEOBJECT"_s,
+ u"(*"_s + cpythonTypeName(func->implementingClass()) + u')');
+ } else {
+ code.replace(u"%PYTHONTYPEOBJECT."_s, pySelf + u"->ob_type->"_s);
+ code.replace(u"%PYTHONTYPEOBJECT"_s, pySelf + u"->ob_type"_s);
+ }
+ }
+
+ // Replaces template %ARGUMENT_NAMES and %# variables by argument variables and values.
+ // Replaces template variables %# for individual arguments.
+ const ArgumentVarReplacementList &argReplacements = getArgumentReplacement(func, usePyArgs, language, lastArg);
+
+ QStringList args;
+ for (const ArgumentVarReplacementPair &pair : argReplacements) {
+ if (pair.second.startsWith(CPP_ARG_REMOVED_PREFIX))
+ continue;
+ args << pair.second;
+ }
+ code.replace(u"%ARGUMENT_NAMES"_s, args.join(u", "_s));
+
+ for (const ArgumentVarReplacementPair &pair : argReplacements) {
+ const AbstractMetaArgument &arg = pair.first;
+ int idx = arg.argumentIndex() + 1;
+ AbstractMetaType type = arg.modifiedType();
+ if (type.isWrapperType()) {
+ QString replacement = pair.second;
+ const auto generatorArg = GeneratorArgument::fromMetaType(type);
+ if (generatorArg.indirections > 0)
+ AbstractMetaType::stripDereference(&replacement);
+ if (type.referenceType() == LValueReference || type.isPointer())
+ code.replace(u'%' + QString::number(idx) + u'.', replacement + u"->"_s);
+ }
+ code.replace(CodeSnipAbstract::placeHolderRegex(idx), pair.second);
+ }
+
+ if (language == TypeSystem::NativeCode) {
+ // Replaces template %PYTHON_ARGUMENTS variable with a pointer to the Python tuple
+ // containing the converted virtual method arguments received from C++ to be passed
+ // to the Python override.
+ code.replace(u"%PYTHON_ARGUMENTS"_s, PYTHON_ARGS);
+
+ // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method
+ // override for the C++ virtual method in which this piece of code was inserted
+ code.replace(u"%PYTHON_METHOD_OVERRIDE"_s, PYTHON_OVERRIDE_VAR);
+ }
+
+ if (avoidProtectedHack()) {
+ // If the function being processed was added by the user via type system,
+ // Shiboken needs to find out if there are other overloads for the same method
+ // name and if any of them is of the protected visibility. This is used to replace
+ // calls to %FUNCTION_NAME on user written custom code for calls to the protected
+ // dispatcher.
+ bool isProtected = func->isProtected();
+ auto owner = func->ownerClass();
+ if (!isProtected && func->isUserAdded() && owner != nullptr) {
+ const auto &funcs = getFunctionGroups(owner).value(func->name());
+ isProtected = std::any_of(funcs.cbegin(), funcs.cend(),
+ [](const AbstractMetaFunctionCPtr &f) {
+ return f->isProtected();
+ });
+ }
+
+ if (isProtected) {
+ code.replace(u"%TYPE::%FUNCTION_NAME"_s,
+ wrapperName(func->ownerClass()) + "::"_L1
+ + func->originalName() + "_protected"_L1);
+ code.replace(u"%FUNCTION_NAME"_s,
+ func->originalName() + u"_protected"_s);
+ }
+ }
+
+ if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass()))
+ code.replace(u"%TYPE"_s, wrapperName(func->ownerClass()));
+
+ if (func->ownerClass())
+ code.replace(u"%CPPTYPE"_s, func->ownerClass()->name());
+
+ replaceTemplateVariables(code, func);
+
+ processCodeSnip(code, func->classQualifiedSignature());
+ s << "// Begin code injection\n" << code << "// End of code injection\n\n";
+}
+
+// Returns true if the string is an expression,
+// and false if it is a variable.
+static bool isVariable(const QString &code)
+{
+ static const QRegularExpression expr("^\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*$"_L1);
+ Q_ASSERT(expr.isValid());
+ return expr.match(code.trimmed()).hasMatch();
+}
+
+// A miniature normalizer that puts a type string into a format
+// suitable for comparison with AbstractMetaType::cppSignature()
+// result.
+static QString miniNormalizer(const QString &varType)
+{
+ QString normalized = varType.trimmed();
+ if (normalized.isEmpty())
+ return normalized;
+ if (normalized.startsWith(u"::"))
+ normalized.remove(0, 2);
+ QString suffix;
+ while (normalized.endsWith(u'*') || normalized.endsWith(u'&')) {
+ suffix.prepend(normalized.at(normalized.size() - 1));
+ normalized.chop(1);
+ normalized = normalized.trimmed();
+ }
+ const QString result = normalized + u' ' + suffix;
+ return result.trimmed();
+}
+// The position must indicate the first character after the opening '('.
+// ATTENTION: do not modify this function to trim any resulting string!
+// This must be done elsewhere.
+static QString getConverterTypeSystemVariableArgument(const QString &code, int pos)
+{
+ QString arg;
+ int parenthesisDepth = 0;
+ int count = 0;
+ while (pos + count < code.size()) {
+ char c = code.at(pos+count).toLatin1(); // toAscii is gone
+ if (c == '(') {
+ ++parenthesisDepth;
+ } else if (c == ')') {
+ if (parenthesisDepth == 0) {
+ arg = code.mid(pos, count).trimmed();
+ break;
+ }
+ --parenthesisDepth;
+ }
+ ++count;
+ }
+ if (parenthesisDepth != 0)
+ throw Exception("Unbalanced parenthesis on type system converter variable call.");
+ return arg;
+}
+
+const QHash<int, QString> &ShibokenGenerator::typeSystemConvName()
+{
+ static const QHash<int, QString> result = {
+ {TypeSystemCheckFunction, u"checkType"_s},
+ {TypeSystemIsConvertibleFunction, u"isConvertible"_s},
+ {TypeSystemToCppFunction, u"toCpp"_s},
+ {TypeSystemToPythonFunction, u"toPython"_s}
+ };
+ return result;
+}
+
+using StringPair = std::pair<QString, QString>;
+
+void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable,
+ QString &code) const
+{
+ QList<StringPair> replacements;
+ QRegularExpressionMatchIterator rit = typeSystemConvRegExps()[converterVariable].globalMatch(code);
+ while (rit.hasNext()) {
+ const QRegularExpressionMatch match = rit.next();
+ const QStringList list = match.capturedTexts();
+ QString conversionString = list.constFirst();
+ const QString &conversionTypeName = list.constLast();
+ QString message;
+ const auto conversionTypeO = AbstractMetaType::fromString(conversionTypeName, &message);
+ if (!conversionTypeO.has_value()) {
+ throw Exception(msgCannotFindType(conversionTypeName,
+ typeSystemConvName().value(converterVariable),
+ message));
+ }
+ const auto conversionType = conversionTypeO.value();
+ QString conversion;
+ switch (converterVariable) {
+ case TypeSystemToCppFunction: {
+ StringStream c(TextStream::Language::Cpp);
+ int end = match.capturedStart();
+ int start = end;
+ while (start > 0 && code.at(start) != u'\n')
+ --start;
+ while (code.at(start).isSpace())
+ ++start;
+ QString varType = code.mid(start, end - start);
+ conversionString = varType + list.constFirst();
+ varType = miniNormalizer(varType);
+ QString varName = list.at(1).trimmed();
+ if (!varType.isEmpty()) {
+ c << getFullTypeName(conversionType) << ' ' << varName
+ << minimalConstructorExpression(api(), conversionType) << ";\n";
+ }
+ c << cpythonToCppConversionFunction(conversionType);
+ QString prefix;
+ if (!AbstractMetaType::stripDereference(&varName))
+ prefix = u'&';
+ QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd());
+ conversionString += arg;
+ c << arg << ", " << prefix << '(' << varName << ')';
+ conversion = c.toString();
+ break;
+ }
+ case TypeSystemCheckFunction:
+ conversion = cpythonCheckFunction(conversionType);
+ if (conversionType.typeEntry()->isPrimitive()
+ && (conversionType.typeEntry()->name() == cPyObjectT
+ || !conversion.endsWith(u' '))) {
+ conversion += u'(';
+ break;
+ }
+ Q_FALLTHROUGH();
+ case TypeSystemIsConvertibleFunction:
+ if (conversion.isEmpty())
+ conversion = cpythonIsConvertibleFunction(conversionType);
+ Q_FALLTHROUGH();
+ case TypeSystemToPythonFunction:
+ if (conversion.isEmpty())
+ conversion = cpythonToPythonConversionFunction(conversionType);
+ Q_FALLTHROUGH();
+ default: {
+ QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd());
+ conversionString += arg;
+ if (converterVariable == TypeSystemToPythonFunction && !isVariable(arg)) {
+ QString m;
+ QTextStream(&m) << "Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '"
+ << code << '\'';
+ throw Exception(m);
+ }
+ if (conversion.contains(u"%in")) {
+ conversion.prepend(u'(');
+ conversion.replace(u"%in"_s, arg);
+ } else {
+ conversion += arg;
+ }
+ }
+ }
+ replacements.append(std::make_pair(conversionString, conversion));
+ }
+ for (const StringPair &rep : std::as_const(replacements))
+ code.replace(rep.first, rep.second);
+}
+
+bool ShibokenGenerator::injectedCodeCallsCppFunction(const GeneratorContext &context,
+ const AbstractMetaFunctionCPtr &func)
+{
+ if (func->injectedCodeContains(u"%FUNCTION_NAME("))
+ return true;
+ QString funcCall = func->originalName() + u'(';
+ if (func->isConstructor())
+ funcCall.prepend(u"new "_s);
+ if (func->injectedCodeContains(funcCall))
+ return true;
+ if (!func->isConstructor())
+ return false;
+ if (func->injectedCodeContains(u"new %TYPE("))
+ return true;
+ const auto owner = func->ownerClass();
+ if (!owner->isPolymorphic())
+ return false;
+ const QString wrappedCtorCall = u"new "_s + context.effectiveClassName() + u'(';
+ return func->injectedCodeContains(wrappedCtorCall);
+}
+
+bool ShibokenGenerator::useOverrideCaching(const AbstractMetaClassCPtr &metaClass)
+{
+ return metaClass->isPolymorphic();
+}
+
+ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(
+ const AbstractMetaClassCPtr &metaClass)
+{
+ AttroCheck result;
+ if (metaClass->typeEntry()->isSmartPointer()) {
+ result |= AttroCheckFlag::GetattroSmartPointer | AttroCheckFlag::SetattroSmartPointer;
+ } else {
+ if (getGeneratorClassInfo(metaClass).needsGetattroFunction)
+ result |= AttroCheckFlag::GetattroOverloads;
+ if (metaClass->queryFirstFunction(metaClass->functions(),
+ FunctionQueryOption::GetAttroFunction)) {
+ result |= AttroCheckFlag::GetattroUser;
+ }
+ if (usePySideExtensions() && metaClass->qualifiedCppName() == qObjectT)
+ result |= AttroCheckFlag::SetattroQObject;
+ if (useOverrideCaching(metaClass))
+ result |= AttroCheckFlag::SetattroMethodOverride;
+ if (metaClass->queryFirstFunction(metaClass->functions(),
+ FunctionQueryOption::SetAttroFunction)) {
+ result |= AttroCheckFlag::SetattroUser;
+ }
+ // PYSIDE-1255: If setattro is generated for a class inheriting
+ // QObject, the property code needs to be generated, too.
+ if ((result & AttroCheckFlag::SetattroMask) != 0
+ && !result.testFlag(AttroCheckFlag::SetattroQObject)
+ && isQObject(metaClass)) {
+ result |= AttroCheckFlag::SetattroQObject;
+ }
+ }
+ return result;
+}
+
+bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClassCPtr &metaClass)
+{
+ if (!metaClass)
+ return false;
+ if (metaClass->typeEntry()->isSmartPointer())
+ return true;
+ const auto &functionGroup = getFunctionGroups(metaClass);
+ for (auto it = functionGroup.cbegin(), end = functionGroup.cend(); it != end; ++it) {
+ AbstractMetaFunctionCList overloads;
+ for (const auto &func : std::as_const(it.value())) {
+ if (func->isAssignmentOperator() || func->isConversionOperator()
+ || func->isModifiedRemoved()
+ || func->isPrivate() || func->ownerClass() != func->implementingClass()
+ || func->isConstructor() || func->isOperatorOverload())
+ continue;
+ overloads.append(func);
+ }
+ if (overloads.isEmpty())
+ continue;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads))
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaFunctionCList
+ ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClassCPtr &metaClass)
+{
+ AbstractMetaFunctionCList methods;
+ if (metaClass) {
+ const auto &functionGroups = getFunctionGroups(metaClass);
+ for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ AbstractMetaFunctionCList overloads;
+ for (const auto &func : std::as_const(it.value())) {
+ if (func->isAssignmentOperator() || func->isConversionOperator()
+ || func->isModifiedRemoved()
+ || func->isPrivate() || func->ownerClass() != func->implementingClass()
+ || func->isConstructor() || func->isOperatorOverload())
+ continue;
+ overloads.append(func);
+ }
+ if (overloads.isEmpty())
+ continue;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads))
+ methods.append(overloads.constFirst());
+ }
+ }
+ return methods;
+}
+
+AbstractMetaClassCPtr
+ ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClassCPtr &metaClass)
+{
+ if (!metaClass || metaClass->baseClassNames().isEmpty())
+ return nullptr;
+ if (metaClass->baseClassNames().size() > 1)
+ return metaClass;
+ return getMultipleInheritingClass(metaClass->baseClass());
+}
+
+QString ShibokenGenerator::getModuleHeaderFileBaseName(const QString &moduleName)
+{
+ return moduleCppPrefix(moduleName).toLower() + "_python"_L1;
+}
+
+QString ShibokenGenerator::getModuleHeaderFileName(const QString &moduleName)
+{
+ return getModuleHeaderFileBaseName(moduleName) + ".h"_L1;
+}
+
+QString ShibokenGenerator::getPrivateModuleHeaderFileName(const QString &moduleName)
+{
+ return getModuleHeaderFileBaseName(moduleName) + "_p.h"_L1;
+}
+
+IncludeGroupList ShibokenGenerator::classIncludes(const AbstractMetaClassCPtr &metaClass) const
+{
+ IncludeGroupList result;
+ const auto typeEntry = metaClass->typeEntry();
+ //Extra includes
+ result.append(IncludeGroup{u"Extra includes"_s,
+ typeEntry->extraIncludes()});
+
+ result.append({u"Enum includes"_s, {}});
+ for (const auto &cppEnum : metaClass->enums())
+ result.back().includes.append(cppEnum.typeEntry()->extraIncludes());
+
+ result.append({u"Argument includes"_s, typeEntry->argumentIncludes()});
+ const auto implicitConvs = implicitConversions(typeEntry);
+ for (const auto &f : implicitConvs) {
+ if (f->isConversionOperator()) {
+ const auto source = f->ownerClass();
+ Q_ASSERT(source);
+ result.back().append(source->typeEntry()->include());
+ }
+ }
+ return result;
+}
+
+/*
+static void dumpFunction(AbstractMetaFunctionList lst)
+{
+ qDebug() << "DUMP FUNCTIONS: ";
+ for (AbstractMetaFunction *func : std::as_const(lst))
+ qDebug() << "*" << func->ownerClass()->name()
+ << func->signature()
+ << "Private: " << func->isPrivate()
+ << "Empty: " << func->isEmptyFunction()
+ << "Static:" << func->isStatic()
+ << "Signal:" << func->isSignal()
+ << "ClassImplements: " << (func->ownerClass() != func->implementingClass())
+ << "is operator:" << func->isOperatorOverload()
+ << "is global:" << func->isInGlobalScope();
+}
+*/
+
+static bool isGroupable(const AbstractMetaFunctionCPtr &func)
+{
+ switch (func->functionType()) {
+ case AbstractMetaFunction::DestructorFunction:
+ case AbstractMetaFunction::SignalFunction:
+ case AbstractMetaFunction::GetAttroFunction:
+ case AbstractMetaFunction::SetAttroFunction:
+ case AbstractMetaFunction::ArrowOperator: // weird operator overloads
+ case AbstractMetaFunction::SubscriptOperator:
+ return false;
+ default:
+ break;
+ }
+ if (func->isModifiedRemoved() && !func->isAbstract())
+ return false;
+ return true;
+}
+
+static void insertIntoFunctionGroups(const AbstractMetaFunctionCList &lst,
+ ShibokenGenerator::FunctionGroups *results)
+{
+ for (const auto &func : lst) {
+ if (isGroupable(func))
+ (*results)[func->name()].append(func);
+ }
+}
+
+ShibokenGenerator::FunctionGroups ShibokenGenerator::getGlobalFunctionGroups() const
+{
+ FunctionGroups results;
+ insertIntoFunctionGroups(api().globalFunctions(), &results);
+ for (const auto &nsp : invisibleTopNamespaces())
+ insertIntoFunctionGroups(nsp->functions(), &results);
+ return results;
+}
+
+const GeneratorClassInfoCacheEntry &
+ ShibokenGenerator::getGeneratorClassInfo(const AbstractMetaClassCPtr &scope)
+{
+ auto cache = generatorClassInfoCache();
+ auto it = cache->find(scope);
+ if (it == cache->end()) {
+ it = cache->insert(scope, {});
+ auto &entry = it.value();
+ entry.functionGroups = getFunctionGroupsImpl(scope);
+ entry.needsGetattroFunction = classNeedsGetattroFunctionImpl(scope);
+ entry.numberProtocolOperators = getNumberProtocolOperators(scope);
+ entry.boolCastFunctionO = getBoolCast(scope);
+ }
+ return it.value();
+}
+
+ShibokenGenerator::FunctionGroups
+ ShibokenGenerator::getFunctionGroups(const AbstractMetaClassCPtr &scope)
+{
+ Q_ASSERT(scope);
+ return getGeneratorClassInfo(scope).functionGroups;
+}
+
+QList<AbstractMetaFunctionCList>
+ ShibokenGenerator::numberProtocolOperators(const AbstractMetaClassCPtr &scope)
+{
+ Q_ASSERT(scope);
+ return getGeneratorClassInfo(scope).numberProtocolOperators;
+}
+
+BoolCastFunctionOptional ShibokenGenerator::boolCast(const AbstractMetaClassCPtr &scope)
+{
+ Q_ASSERT(scope);
+ return getGeneratorClassInfo(scope).boolCastFunctionO;
+}
+
+// Use non-const overloads only, for example, "foo()" and "foo()const"
+// the second is removed.
+static void removeConstOverloads(AbstractMetaFunctionCList *overloads)
+{
+ for (qsizetype i = overloads->size() - 1; i >= 0; --i) {
+ const auto &f = overloads->at(i);
+ if (f->isConstant()) {
+ for (qsizetype c = 0, size = overloads->size(); c < size; ++c) {
+ if (f->isConstOverloadOf(overloads->at(c).get())) {
+ overloads->removeAt(i);
+ break;
+ }
+ }
+ }
+ }
+}
+
+ShibokenGenerator::FunctionGroups
+ ShibokenGenerator::getFunctionGroupsImpl(const AbstractMetaClassCPtr &scope)
+{
+ AbstractMetaFunctionCList lst = scope->functions();
+ scope->getFunctionsFromInvisibleNamespacesToBeGenerated(&lst);
+
+ FunctionGroups results;
+ for (const auto &func : lst) {
+ if (isGroupable(func)
+ && func->ownerClass() == func->implementingClass()
+ && func->generateBinding()) {
+ auto it = results.find(func->name());
+ if (it == results.end()) {
+ it = results.insert(func->name(), AbstractMetaFunctionCList(1, func));
+ } else {
+ // If there are virtuals methods in the mix (PYSIDE-570,
+ // QFileSystemModel::index(QString,int) and
+ // QFileSystemModel::index(int,int,QModelIndex)) override, make sure
+ // the overriding method of the most-derived class is seen first
+ // and inserted into the "seenSignatures" set.
+ if (func->isVirtual())
+ it.value().prepend(func);
+ else
+ it.value().append(func);
+ }
+ getInheritedOverloads(scope, &it.value());
+ removeConstOverloads(&it.value());
+ }
+ }
+ return results;
+}
+
+static bool removeNumberProtocolOperator(const AbstractMetaFunctionCPtr &f)
+{
+ return !f->generateBinding()
+ || (f->ownerClass() != f->implementingClass() && !f->isAbstract());
+}
+
+QList<AbstractMetaFunctionCList>
+ ShibokenGenerator::getNumberProtocolOperators(const AbstractMetaClassCPtr &metaClass)
+{
+ QList<AbstractMetaFunctionCList> result;
+ if (metaClass->isNamespace())
+ return result;
+ result = filterGroupedOperatorFunctions(
+ metaClass,
+ OperatorQueryOption::ArithmeticOp
+ | OperatorQueryOption::IncDecrementOp
+ | OperatorQueryOption::LogicalOp
+ | OperatorQueryOption::BitwiseOp
+ | OperatorQueryOption::ConversionOp);
+
+ for (auto i = result.size() - 1; i >= 0; --i) {
+ AbstractMetaFunctionCList &l = result[i];
+ auto rend = std::remove_if(l.begin(), l.end(), removeNumberProtocolOperator);
+ l.erase(rend, l.end());
+ if (l.isEmpty())
+ result.removeAt(i);
+ }
+
+ return result;
+}
+
+BoolCastFunctionOptional
+ShibokenGenerator::getBoolCast(const AbstractMetaClassCPtr &metaClass)
+{
+ if (metaClass->isNamespace())
+ return std::nullopt;
+
+ const auto te = metaClass->typeEntry();
+ if (te->isSmartPointer()) {
+ auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(te);
+
+ auto valueCheckMethod = ste->valueCheckMethod();
+ if (!valueCheckMethod.isEmpty()) {
+ const auto func = metaClass->findFunction(valueCheckMethod);
+ if (!func)
+ throw Exception(msgMethodNotFound(metaClass, valueCheckMethod));
+ return BoolCastFunction{func, false};
+ }
+
+ auto nullCheckMethod = ste->nullCheckMethod();
+ if (!nullCheckMethod.isEmpty()) {
+ const auto func = metaClass->findFunction(nullCheckMethod);
+ if (!func)
+ throw Exception(msgMethodNotFound(metaClass, nullCheckMethod));
+ return BoolCastFunction{func, true};
+ }
+ }
+
+ auto mode = te->operatorBoolMode();
+ if (useOperatorBoolAsNbBool()
+ ? mode != TypeSystem::BoolCast::Disabled : mode == TypeSystem::BoolCast::Enabled) {
+ const auto func = metaClass->findOperatorBool();
+ if (func)
+ return BoolCastFunction{func, false};
+ }
+
+ mode = te->isNullMode();
+ if (useIsNullAsNbBool()
+ ? mode != TypeSystem::BoolCast::Disabled : mode == TypeSystem::BoolCast::Enabled) {
+ const auto func = metaClass->findQtIsNullMethod();
+ if (func)
+ return BoolCastFunction{func, true};
+ }
+ return std::nullopt;
+}
+
+static bool isInplaceAdd(const AbstractMetaFunctionCPtr &func)
+{
+ return func->name() == u"operator+=";
+}
+
+static bool isIncrementOperator(const AbstractMetaFunctionCPtr &func)
+{
+ return func->functionType() == AbstractMetaFunction::IncrementOperator;
+}
+
+static bool isDecrementOperator(const AbstractMetaFunctionCPtr &func)
+{
+ return func->functionType() == AbstractMetaFunction::DecrementOperator;
+}
+
+// Filter predicate for operator functions
+static bool skipOperatorFunc(const AbstractMetaFunctionCPtr &func)
+{
+ if (func->isModifiedRemoved() || func->usesRValueReferences())
+ return true;
+ const auto &name = func->name();
+ return name == u"operator[]" || name == u"operator->" || name == u"operator!"
+ || name == u"operator/="; // __idiv__ is not needed in Python3
+}
+
+QList<AbstractMetaFunctionCList>
+ShibokenGenerator::filterGroupedOperatorFunctions(const AbstractMetaClassCPtr &metaClass,
+ OperatorQueryOptions query)
+{
+ // ( func_name, num_args ) => func_list
+ QMap<std::pair<QString, int>, AbstractMetaFunctionCList> results;
+ auto funcs = metaClass->operatorOverloads(query);
+ auto end = std::remove_if(funcs.begin(), funcs.end(), skipOperatorFunc);
+ funcs.erase(end, funcs.end());
+ // If we have operator+=, we remove the operator++/-- which would
+ // otherwise be used for emulating __iadd__, __isub__.
+ if (std::any_of(funcs.cbegin(), funcs.cend(), isInplaceAdd)) {
+ end = std::remove_if(funcs.begin(), funcs.end(),
+ [] (const AbstractMetaFunctionCPtr &func) {
+ return func->isIncDecrementOperator();
+ });
+ funcs.erase(end, funcs.end());
+ } else {
+ // If both prefix/postfix ++/-- are present, remove one
+ if (std::count_if(funcs.begin(), funcs.end(), isIncrementOperator) > 1)
+ funcs.erase(std::find_if(funcs.begin(), funcs.end(), isIncrementOperator));
+ if (std::count_if(funcs.begin(), funcs.end(), isDecrementOperator) > 1)
+ funcs.erase(std::find_if(funcs.begin(), funcs.end(), isDecrementOperator));
+ }
+ for (const auto &func : funcs) {
+ int args;
+ if (func->isComparisonOperator()) {
+ args = -1;
+ } else {
+ args = func->arguments().size();
+ }
+ auto op = std::make_pair(func->name(), args);
+ results[op].append(func);
+ }
+ QList<AbstractMetaFunctionCList> result;
+ result.reserve(results.size());
+ for (auto it = results.cbegin(), end = results.cend(); it != end; ++it)
+ result.append(it.value());
+ return result;
+}
+
+static bool hidesBaseClassFunctions(const AbstractMetaFunctionCPtr &f)
+{
+ auto attributes = f->cppAttributes();
+ return !attributes.testFlag(FunctionAttribute::Override)
+ && !attributes.testFlag(FunctionAttribute::Final);
+}
+
+void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClassCPtr &scope,
+ AbstractMetaFunctionCList *overloads)
+{
+ if (overloads->isEmpty() || scope->isNamespace() || scope->baseClasses().isEmpty())
+ return;
+
+ // PYSIDE-331: look also into base classes. Check for any non-overriding
+ // function hiding the base class functions.
+ const bool hideBaseClassFunctions =
+ std::any_of(overloads->cbegin(), overloads->cend(), hidesBaseClassFunctions);
+
+ const QString &functionName = overloads->constFirst()->name();
+ const bool hasUsingDeclarations = scope->hasUsingMemberFor(functionName);
+ if (hideBaseClassFunctions && !hasUsingDeclarations)
+ return; // No base function is visible
+
+ // Collect base candidates by name and signature
+ bool staticEncountered = false;
+ QSet<QString> seenSignatures;
+ for (const auto &func : *overloads) {
+ seenSignatures.insert(func->minimalSignature());
+ staticEncountered |= func->isStatic();
+ }
+
+ AbstractMetaFunctionCList baseCandidates;
+
+ auto basePredicate = [&functionName, &seenSignatures, &baseCandidates]
+ (const AbstractMetaClassCPtr &b) {
+ for (const auto &f : b->functions()) {
+ if (f->generateBinding() && f->name() == functionName) {
+ const QString signature = f->minimalSignature();
+ if (!seenSignatures.contains(signature)) {
+ seenSignatures.insert(signature);
+ baseCandidates.append(f);
+ }
+ }
+ }
+ return false; // Keep going
+ };
+
+ for (const auto &baseClass : scope->baseClasses())
+ recurseClassHierarchy(baseClass, basePredicate);
+
+ // Remove the ones that are not made visible with using declarations
+ if (hideBaseClassFunctions && hasUsingDeclarations) {
+ const auto pred = [scope](const AbstractMetaFunctionCPtr &f) {
+ return !scope->isUsingMember(f->ownerClass(), f->name(), f->access());
+ };
+ auto end = std::remove_if(baseCandidates.begin(), baseCandidates.end(), pred);
+ baseCandidates.erase(end, baseCandidates.end());
+ }
+
+ // PYSIDE-886: If the method does not have any static overloads declared
+ // in the class in question, remove all inherited static methods as setting
+ // METH_STATIC in that case can cause crashes for the instance methods.
+ // Manifested as crash when calling QPlainTextEdit::find() (clash with
+ // static QWidget::find(WId)).
+ if (!staticEncountered) {
+ auto end = std::remove_if(baseCandidates.begin(), baseCandidates.end(),
+ [](const AbstractMetaFunctionCPtr &f) { return f->isStatic(); });
+ baseCandidates.erase(end, baseCandidates.end());
+ }
+
+ for (const auto &baseCandidate : baseCandidates) {
+ AbstractMetaFunction *newFunc = baseCandidate->copy();
+ newFunc->setImplementingClass(scope);
+ overloads->append(AbstractMetaFunctionCPtr(newFunc));
+ }
+}
+
+QList<OptionDescription> ShibokenGenerator::options()
+{
+ return {
+ {DISABLE_VERBOSE_ERROR_MESSAGES,
+ u"Disable verbose error messages. Turn the python code hard to debug\n"
+ "but safe few kB on the generated bindings."_s},
+ {PARENT_CTOR_HEURISTIC,
+ u"Enable heuristics to detect parent relationship on constructors."_s},
+ {RETURN_VALUE_HEURISTIC,
+ u"Enable heuristics to detect parent relationship on return values\n"
+ "(USE WITH CAUTION!)"_s},
+ {USE_ISNULL_AS_NB_BOOL,
+ u"If a class have an isNull() const method, it will be used to compute\n"
+ "the value of boolean casts"_s},
+ {LEAN_HEADERS,
+ u"Forward declare classes in module headers"_s},
+ {USE_OPERATOR_BOOL_AS_NB_BOOL,
+ u"If a class has an operator bool, it will be used to compute\n"
+ "the value of boolean casts"_s},
+ {NO_IMPLICIT_CONVERSIONS,
+ u"Do not generate implicit_conversions for function arguments."_s},
+ {WRAPPER_DIAGNOSTICS,
+ u"Generate diagnostic code around wrappers"_s}
+ };
+}
+
+class ShibokenGeneratorOptionsParser : public OptionsParser
+{
+public:
+ explicit ShibokenGeneratorOptionsParser(ShibokenGeneratorOptions *o) : m_options(o) {}
+
+ bool handleBoolOption(const QString & key, OptionSource source) override;
+
+private:
+ ShibokenGeneratorOptions *m_options;
+};
+
+bool ShibokenGeneratorOptionsParser::handleBoolOption(const QString &key, OptionSource source)
+{
+ if (source == OptionSource::CommandLineSingleDash)
+ return false;
+ if (key == PARENT_CTOR_HEURISTIC)
+ return (m_options->useCtorHeuristic = true);
+ if (key == RETURN_VALUE_HEURISTIC)
+ return (m_options->userReturnValueHeuristic = true);
+ if (key == DISABLE_VERBOSE_ERROR_MESSAGES)
+ return (m_options->verboseErrorMessagesDisabled = true);
+ if (key == USE_ISNULL_AS_NB_BOOL || key == USE_ISNULL_AS_NB_NONZERO) {
+ return (m_options->useIsNullAsNbBool = true);
+ }
+ if (key == LEAN_HEADERS)
+ return (m_options->leanHeaders= true);
+ if (key == USE_OPERATOR_BOOL_AS_NB_BOOL || key == USE_OPERATOR_BOOL_AS_NB_NONZERO) {
+ return (m_options->useOperatorBoolAsNbBool = true);
+ }
+ if (key == NO_IMPLICIT_CONVERSIONS) {
+ m_options->generateImplicitConversions = false;
+ return true;
+ }
+ if (key == WRAPPER_DIAGNOSTICS)
+ return (m_options->wrapperDiagnostics = true);
+ return false;
+}
+
+std::shared_ptr<OptionsParser> ShibokenGenerator::createOptionsParser()
+{
+ return std::make_shared<ShibokenGeneratorOptionsParser>(&m_options);
+}
+
+bool ShibokenGenerator::doSetup()
+{
+ return true;
+}
+
+bool ShibokenGenerator::useCtorHeuristic()
+{
+ return m_options.useCtorHeuristic;
+}
+
+bool ShibokenGenerator::useReturnValueHeuristic()
+{
+ return m_options.userReturnValueHeuristic;
+}
+
+bool ShibokenGenerator::useIsNullAsNbBool()
+{
+ return m_options.useIsNullAsNbBool;
+}
+
+bool ShibokenGenerator::leanHeaders()
+{
+ return m_options.leanHeaders;
+}
+
+bool ShibokenGenerator::useOperatorBoolAsNbBool()
+{
+ return m_options.useOperatorBoolAsNbBool;
+}
+
+bool ShibokenGenerator::generateImplicitConversions()
+{
+ return m_options.generateImplicitConversions;
+}
+
+QString ShibokenGenerator::moduleCppPrefix(const QString &moduleName)
+ {
+ QString result = moduleName.isEmpty() ? packageName() : moduleName;
+ result.replace(u'.', u'_');
+ return result;
+}
+
+QString ShibokenGenerator::cppApiVariableNameOld(const QString &moduleName)
+{
+ return "Sbk"_L1 + moduleCppPrefix(moduleName) + "Types"_L1;
+}
+
+QString ShibokenGenerator::cppApiVariableName(const QString &moduleName)
+{
+ return "Sbk"_L1 + moduleCppPrefix(moduleName) + "TypeStructs"_L1;
+}
+
+QString ShibokenGenerator::pythonModuleObjectName(const QString &moduleName)
+{
+ return "Sbk"_L1 + moduleCppPrefix(moduleName) + "ModuleObject"_L1;
+}
+
+QString ShibokenGenerator::convertersVariableName(const QString &moduleName)
+{
+ QString result = cppApiVariableNameOld(moduleName);
+ result.chop(1);
+ result.append(u"Converters"_s);
+ return result;
+}
+
+static QString processInstantiationsVariableName(const AbstractMetaType &type)
+{
+ QString res = u'_' + _fixedCppTypeName(type.typeEntry()->qualifiedCppName());
+ for (const auto &instantiation : type.instantiations()) {
+ res += instantiation.isContainer()
+ ? processInstantiationsVariableName(instantiation)
+ : u'_' + _fixedCppTypeName(instantiation.cppSignature());
+ }
+ return res;
+}
+
+static void appendIndexSuffix(QString *s)
+{
+ if (!s->endsWith(u'_'))
+ s->append(u'_');
+ s->append("IDX"_L1);
+}
+
+QString
+ ShibokenGenerator::getTypeAlternateTemplateIndexVariableName(const AbstractMetaClassCPtr &metaClass)
+{
+ const auto templateBaseClass = metaClass->templateBaseClass();
+ Q_ASSERT(templateBaseClass);
+ QString result = u"SBK_"_s
+ + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName());
+ for (const auto &instantiation : metaClass->templateBaseClassInstantiations())
+ result += processInstantiationsVariableName(instantiation);
+ appendIndexSuffix(&result);
+ return result;
+}
+
+QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClassCPtr &metaClass)
+{
+ return getTypeIndexVariableName(metaClass->typeEntry());
+}
+QString ShibokenGenerator::getTypeIndexVariableName(TypeEntryCPtr type)
+{
+ if (isCppPrimitive(type))
+ type = basicReferencedTypeEntry(type);
+ QString result = u"SBK_"_s;
+ // Disambiguate namespaces per module to allow for extending them.
+ if (type->isNamespace()) {
+ QString package = type->targetLangPackage();
+ const int dot = package.lastIndexOf(u'.');
+ result += QStringView{package}.right(package.size() - (dot + 1));
+ }
+ result += _fixedCppTypeName(type->qualifiedCppName());
+ appendIndexSuffix(&result);
+ return result;
+}
+QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType &type)
+{
+ QString result = u"SBK"_s;
+ if (type.typeEntry()->isContainer())
+ result += u'_' + moduleName();
+ result += processInstantiationsVariableName(type);
+ appendIndexSuffix(&result);
+ return result;
+}
+
+void collectfromTypeEntry(TypeEntryCPtr entry, QStringList &typeNames)
+{
+ if (entry->shouldGenerate()) {
+ typeNames[entry->sbkIndex()] = entry->qualifiedTargetLangName();
+ if (entry->isEnum()) {
+ auto ete = std::static_pointer_cast<const EnumTypeEntry>(entry);
+ if (ete->flags()) {
+ auto entry = ete->flags();
+ typeNames[entry->sbkIndex()] = entry->qualifiedTargetLangName();
+ }
+ }
+ }
+}
+
+void ShibokenGenerator::collectFullTypeNamesArray(QStringList &typeNames)
+{
+ for (const auto &metaClass : api().classes()) {
+ collectfromTypeEntry(metaClass->typeEntry(), typeNames);
+
+ for (const AbstractMetaEnum &metaEnum : metaClass->enums())
+ collectfromTypeEntry(metaEnum.typeEntry(), typeNames);
+
+ int smartPointerCountIndex = getMaxTypeIndex();
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ auto entry = smp.type.typeEntry();
+ typeNames[smartPointerCountIndex] =
+ smp.specialized->typeEntry()->qualifiedTargetLangName();
+ ++smartPointerCountIndex;
+ }
+ }
+ for (const AbstractMetaEnum &metaEnum : api().globalEnums())
+ collectfromTypeEntry(metaEnum.typeEntry(), typeNames);
+}
+
+bool ShibokenGenerator::verboseErrorMessagesDisabled()
+{
+ return m_options.verboseErrorMessagesDisabled;
+}
+
+bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const AbstractMetaFunctionCPtr &func) const
+{
+ const auto &groups = func->implementingClass()
+ ? getFunctionGroups(func->implementingClass())
+ : getGlobalFunctionGroups();
+ OverloadData od(groups.value(func->name()), api());
+ return od.pythonFunctionWrapperUsesListOfArguments();
+}
+
+QString ShibokenGenerator::minimalConstructorExpression(const ApiExtractorResult &api,
+ const AbstractMetaType &type)
+{
+ if (type.isExtendedCppPrimitive() || type.isSmartPointer())
+ return {};
+ QString errorMessage;
+ const auto ctor = minimalConstructor(api, type, &errorMessage);
+ if (ctor.has_value())
+ return ctor->initialization();
+
+ const QString message =
+ msgCouldNotFindMinimalConstructor(QLatin1StringView(__FUNCTION__),
+ type.cppSignature(), errorMessage);
+ qCWarning(lcShiboken()).noquote() << message;
+ return u";\n#error "_s + message + u'\n';
+}
+
+QString ShibokenGenerator::minimalConstructorExpression(const ApiExtractorResult &api,
+ const TypeEntryCPtr &type)
+{
+ if (isExtendedCppPrimitive(type))
+ return {};
+ const auto ctor = minimalConstructor(api, type);
+ if (ctor.has_value())
+ return ctor->initialization();
+
+ const QString message =
+ msgCouldNotFindMinimalConstructor(QLatin1StringView(__FUNCTION__),
+ type->qualifiedCppName());
+ qCWarning(lcShiboken()).noquote() << message;
+ return u";\n#error "_s + message + u'\n';
+}
+
+QString ShibokenGenerator::pythonArgsAt(int i)
+{
+ return PYTHON_ARGS + u'[' + QString::number(i) + u']';
+}
+
+void ShibokenGenerator::replaceTemplateVariables(QString &code,
+ const AbstractMetaFunctionCPtr &func) const
+{
+ const auto cpp_class = func->ownerClass();
+ if (cpp_class)
+ code.replace(u"%TYPE"_s, cpp_class->name());
+
+ const AbstractMetaArgumentList &argument = func->arguments();
+ for (const AbstractMetaArgument &arg : argument)
+ code.replace(u'%' + QString::number(arg.argumentIndex() + 1), arg.name());
+
+ //template values
+ code.replace(u"%RETURN_TYPE"_s, translateType(func->type(), cpp_class));
+ code.replace(u"%FUNCTION_NAME"_s, func->originalName());
+
+ if (code.contains(u"%ARGUMENT_NAMES")) {
+ StringStream aux_stream;
+ writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments);
+ code.replace(u"%ARGUMENT_NAMES"_s, aux_stream);
+ }
+
+ if (code.contains(u"%ARGUMENTS")) {
+ StringStream aux_stream;
+ writeFunctionArguments(aux_stream, func, Options(SkipDefaultValues) | SkipRemovedArguments);
+ code.replace(u"%ARGUMENTS"_s, aux_stream);
+ }
+}
+
+QString ShibokenGenerator::stdMove(const QString &c)
+{
+ return u"std::move("_s + c + u')';
+}
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.h b/sources/shiboken6/generator/shiboken/shibokengenerator.h
new file mode 100644
index 000000000..22ee73fa2
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.h
@@ -0,0 +1,491 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SHIBOKENGENERATOR_H
+#define SHIBOKENGENERATOR_H
+
+#include <generator.h>
+
+#include "customconversion_typedefs.h"
+#include "abstractmetalang_enums.h"
+#include "typesystem_typedefs.h"
+#include "typesystem_enums.h"
+
+#include <QtCore/QRegularExpression>
+
+#include <array>
+#include <optional>
+
+class EnumTypeEntry;
+class FlagsTypeEntry;
+class DocParser;
+class CodeSnip;
+class QPropertySpec;
+class OverloadData;
+class TargetToNativeConversion;
+struct GeneratorClassInfoCacheEntry;
+struct IncludeGroup;
+struct ShibokenGeneratorOptions;
+
+class TextStream;
+
+// Function to be used for implementing nb_bool
+struct BoolCastFunction
+{
+ AbstractMetaFunctionCPtr function;
+ bool invert = false; // Function is "isNull()", (invert result).
+};
+
+using BoolCastFunctionOptional = std::optional<BoolCastFunction>;
+
+/**
+ * Abstract generator that contains common methods used in CppGenerator and HeaderGenerator.
+ */
+class ShibokenGenerator : public Generator
+{
+public:
+ Q_DISABLE_COPY_MOVE(ShibokenGenerator)
+
+ /// Besides the actual bindings (see AbstractMetaFunction::generateBinding(),
+ /// some functions need to be generated into the wrapper class
+ /// (virtual method/avoid protected hack expose).
+ enum class FunctionGenerationFlag
+ {
+ None = 0x0,
+ /// Virtual method overridable in Python
+ VirtualMethod = 0x1,
+ /// Special QObject virtuals
+ QMetaObjectMethod = 0x2,
+ /// Needs a protected wrapper for avoidProtectedHack()
+ /// public "foo_protected()" calling "foo()"
+ ProtectedWrapper = 0x4, //
+ /// Pass through constructor
+ WrapperConstructor = 0x8,
+ /// Generate a special copy constructor
+ /// "FooBar_Wrapper(const Foo&)" for constructing a wrapper from a value
+ WrapperSpecialCopyConstructor = 0x10
+ };
+ Q_DECLARE_FLAGS(FunctionGeneration, FunctionGenerationFlag);
+
+ enum class AttroCheckFlag
+ {
+ None = 0x0,
+ GetattroOverloads = 0x01,
+ GetattroSmartPointer = 0x02,
+ GetattroUser = 0x04, // Injected code
+ GetattroMask = 0x0F,
+ SetattroQObject = 0x10,
+ SetattroSmartPointer = 0x20,
+ SetattroMethodOverride = 0x40,
+ SetattroUser = 0x80, // Injected code
+ SetattroMask = 0xF0,
+ };
+ Q_DECLARE_FLAGS(AttroCheck, AttroCheckFlag);
+
+ using FunctionGroups = QMap<QString, AbstractMetaFunctionCList>; // Sorted
+
+ ShibokenGenerator();
+ ~ShibokenGenerator() override;
+
+ const char *name() const override { return "Shiboken"; }
+
+ static QList<OptionDescription> options();
+ static std::shared_ptr<OptionsParser> createOptionsParser();
+
+ static QString minimalConstructorExpression(const ApiExtractorResult &api,
+ const AbstractMetaType &type);
+ static QString minimalConstructorExpression(const ApiExtractorResult &api,
+ const TypeEntryCPtr &type);
+
+protected:
+ bool doSetup() override;
+
+ GeneratorContext contextForClass(const AbstractMetaClassCPtr &c) const override;
+
+ /**
+ * Returns a map with all functions grouped, the function name is used as key.
+ * Example of return value: { "foo" -> ["foo(int)", "foo(int, long)], "bar" -> "bar(double)"}
+ * \param scope Where to search for functions, null means all global functions.
+ */
+ FunctionGroups getGlobalFunctionGroups() const;
+ static FunctionGroups getFunctionGroups(const AbstractMetaClassCPtr &scope);
+
+ static QList<AbstractMetaFunctionCList>
+ numberProtocolOperators(const AbstractMetaClassCPtr &scope);
+
+ static BoolCastFunctionOptional boolCast(const AbstractMetaClassCPtr &scope);
+
+ /**
+ * Returns all different inherited overloads of func, and includes func as well.
+ * The function can be called multiple times without duplication.
+ * \param func the metafunction to be searched in subclasses.
+ * \param seen the function's minimal signatures already seen.
+ */
+ static AbstractMetaFunctionCList getFunctionAndInheritedOverloads(const AbstractMetaFunctionCPtr &func,
+ QSet<QString> *seen);
+
+ /// Write user's custom code snippets at class or module level.
+ void writeClassCodeSnips(TextStream &s,
+ const QList<CodeSnip> &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const GeneratorContext &context) const;
+ void writeCodeSnips(TextStream &s,
+ const QList<CodeSnip> &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const;
+ /// Write user's custom code snippets at function level.
+ void writeCodeSnips(TextStream &s,
+ const QList<CodeSnip> &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaFunctionCPtr &func,
+ bool usePyArgs,
+ const AbstractMetaArgument *lastArg) const;
+
+ /// Replaces variables for the user's custom code at global or class level.
+ void processCodeSnip(QString &code) const;
+ void processCodeSnip(QString &code, const QString &context) const;
+ void processClassCodeSnip(QString &code, const GeneratorContext &context) const;
+
+ /**
+ * Verifies if any of the function's code injections makes a call
+ * to the C++ method. This is used by the generator to avoid writing calls
+ * to C++ when the user custom code already does this.
+ * \param func the function to check
+ * \return true if the function's code snippets call the wrapped C++ function
+ */
+ static bool injectedCodeCallsCppFunction(const GeneratorContext &context,
+ const AbstractMetaFunctionCPtr &func);
+
+ /**
+ * Function which parse the metafunction information
+ * \param func the function witch will be parserd
+ * \param option some extra options
+ * \param arg_count the number of function arguments
+ */
+ QString functionSignature(const AbstractMetaFunctionCPtr &func,
+ const QString &prepend = QString(),
+ const QString &append = QString(),
+ Options options = NoOption,
+ int arg_count = -1) const;
+
+ /// Returns the top-most class that has multiple inheritance in the ancestry.
+ static AbstractMetaClassCPtr
+ getMultipleInheritingClass(const AbstractMetaClassCPtr &metaClass);
+
+ static bool useOverrideCaching(const AbstractMetaClassCPtr &metaClass);
+ static AttroCheck checkAttroFunctionNeeds(const AbstractMetaClassCPtr &metaClass);
+
+ /// Returns a list of methods of the given class where each one is part of
+ /// a different overload with both static and non-static method.
+ static AbstractMetaFunctionCList
+ getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClassCPtr &metaClass);
+
+ static void writeToPythonConversion(TextStream &s,
+ const AbstractMetaType &type,
+ const AbstractMetaClassCPtr &context,
+ const QString &argumentName);
+ static void writeToCppConversion(TextStream &s,
+ const AbstractMetaType &type,
+ const QString &inArgName,
+ const QString &outArgName);
+ static void writeToCppConversion(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const QString &inArgName,
+ const QString &outArgName);
+
+ /// Returns true if the argument is a pointer that rejects nullptr values.
+ static bool shouldRejectNullPointerArgument(const AbstractMetaFunctionCPtr &func,
+ int argIndex);
+
+ /// Verifies if the class should have a C++ wrapper generated for it,
+ /// instead of only a Python wrapper.
+ static bool shouldGenerateCppWrapper(const AbstractMetaClassCPtr &metaClass);
+
+ static bool shouldGenerateMetaObjectFunctions(const AbstractMetaClassCPtr &metaClass);
+
+ /// Returns which functions need to be generated into the wrapper class
+ static FunctionGeneration functionGeneration(const AbstractMetaFunctionCPtr &func);
+
+ // Return a list of implicit conversions if generation is enabled.
+ AbstractMetaFunctionCList implicitConversions(const TypeEntryCPtr &t) const;
+
+ static QString wrapperName(const AbstractMetaClassCPtr &metaClass);
+
+ static QString fullPythonClassName(const AbstractMetaClassCPtr &metaClass);
+
+ static QString headerFileNameForContext(const GeneratorContext &context);
+ IncludeGroup baseWrapperIncludes(const GeneratorContext &classContext) const;
+
+ static QString fullPythonFunctionName(const AbstractMetaFunctionCPtr &func, bool forceFunc);
+
+ static bool wrapperDiagnostics();
+
+ static QString protectedEnumSurrogateName(const AbstractMetaEnum &metaEnum);
+
+ static QString pythonPrimitiveTypeName(const QString &cppTypeName);
+
+ static QString pythonOperatorFunctionName(const AbstractMetaFunctionCPtr &func);
+ static QList<AbstractMetaFunctionCList>
+ filterGroupedOperatorFunctions(const AbstractMetaClassCPtr &metaClass,
+ OperatorQueryOptions query);
+
+ static QString fixedCppTypeName(const TargetToNativeConversion &toNative);
+ static QString fixedCppTypeName(const AbstractMetaType &type);
+ static QString fixedCppTypeName(const TypeEntryCPtr &type, QString typeName = {});
+
+ static bool isNumber(const QString &cpythonApiName);
+ static bool isNumber(const TypeEntryCPtr &type);
+ static bool isNumber(const AbstractMetaType &type);
+ static bool isPyInt(const TypeEntryCPtr &type);
+ static bool isPyInt(const AbstractMetaType &type);
+
+ static bool isNullPtr(const QString &value);
+
+ static QString converterObject(const AbstractMetaType &type) ;
+ static QString converterObject(const TypeEntryCPtr &type);
+
+ static QString cpythonBaseName(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonBaseName(const TypeEntryCPtr &type);
+ static QString containerCpythonBaseName(const ContainerTypeEntryCPtr &ctype);
+ static QString cpythonBaseName(const AbstractMetaType &type);
+ static QString cpythonTypeName(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonTypeName(const TypeEntryCPtr &type);
+ static QString cpythonTypeNameExtSet(const TypeEntryCPtr &type);
+ static QString cpythonTypeNameExtSet(const AbstractMetaType &type);
+ static QString cpythonTypeNameExt(const TypeEntryCPtr &type);
+ static QString cpythonTypeNameExt(const AbstractMetaType &type);
+ static QString cpythonCheckFunction(TypeEntryCPtr type);
+ static QString cpythonCheckFunction(AbstractMetaType metaType);
+ static QString cpythonIsConvertibleFunction(const TypeEntryCPtr &type);
+ static QString cpythonIsConvertibleFunction(const AbstractMetaType &metaType);
+ static QString cpythonIsConvertibleFunction(const AbstractMetaArgument &metaArg);
+
+ static QString cpythonToCppConversionFunction(const AbstractMetaClassCPtr &metaClass) ;
+ static QString cpythonToCppConversionFunction(const AbstractMetaType &type);
+ static QString cpythonToPythonConversionFunction(const AbstractMetaType &type);
+ static QString cpythonToPythonConversionFunction(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonToPythonConversionFunction(const TypeEntryCPtr &type);
+
+ static QString cpythonFunctionName(const AbstractMetaFunctionCPtr &func) ;
+ static QString cpythonMethodDefinitionName(const AbstractMetaFunctionCPtr &func);
+ static QString cpythonGettersSettersDefinitionName(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonGetattroFunctionName(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonSetattroFunctionName(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonGetterFunctionName(const AbstractMetaField &metaField);
+ static QString cpythonSetterFunctionName(const AbstractMetaField &metaField);
+ static QString cpythonGetterFunctionName(const QPropertySpec &property,
+ const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonSetterFunctionName(const QPropertySpec &property,
+ const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonWrapperCPtr(const AbstractMetaClassCPtr &metaClass,
+ const QString &argName = QLatin1StringView("self"));
+ static QString cpythonWrapperCPtr(const AbstractMetaType &metaType,
+ const QString &argName);
+ static QString cpythonWrapperCPtr(const TypeEntryCPtr &type, const QString &argName);
+
+ static QString cpythonEnumName(const EnumTypeEntryCPtr &enumEntry);
+ static QString cpythonEnumName(const AbstractMetaEnum &metaEnum);
+
+ static QString cpythonFlagsName(const FlagsTypeEntryCPtr &flagsEntry);
+ static QString cpythonFlagsName(const AbstractMetaEnum *metaEnum);
+ /// Returns the special cast function name, the function used to proper cast
+ /// class with multiple inheritance.
+ static QString cpythonSpecialCastFunctionName(const AbstractMetaClassCPtr &metaClass);
+
+ /// Returns the file name for the module global header. If no module name
+ /// is provided the current will be used.
+ static QString getModuleHeaderFileName(const QString &moduleName = QString());
+ static QString getPrivateModuleHeaderFileName(const QString &moduleName = QString());
+
+ /// Includes for header (native wrapper class) or binding source
+ QList<IncludeGroup> classIncludes(const AbstractMetaClassCPtr &metaClass) const;
+
+ /// Returns true if the user enabled the so called "parent constructor heuristic".
+ static bool useCtorHeuristic();
+ /// Returns true if the user enabled the so called "return value heuristic".
+ static bool useReturnValueHeuristic();
+ /// Returns true if the generator should use the result of isNull()const to compute boolean casts.
+ static bool useIsNullAsNbBool();
+ /// Whether to generate lean module headers
+ static bool leanHeaders();
+ /// Returns true if the generator should use operator bool to compute boolean casts.
+ static bool useOperatorBoolAsNbBool();
+ /// Generate implicit conversions of function arguments
+ static bool generateImplicitConversions();
+ static QString cppApiVariableNameOld(const QString &moduleName = {});
+ static QString cppApiVariableName(const QString &moduleName = QString());
+ static QString pythonModuleObjectName(const QString &moduleName = QString());
+ static QString convertersVariableName(const QString &moduleName = QString());
+ /// Returns the type index variable name for a given class.
+ static QString getTypeIndexVariableName(const AbstractMetaClassCPtr &metaClass);
+ /// Returns the type index variable name for a given typedef for a template
+ /// class instantiation made of the template class and the instantiation values
+ static QString getTypeAlternateTemplateIndexVariableName(const AbstractMetaClassCPtr &metaClass);
+ static QString getTypeIndexVariableName(TypeEntryCPtr type);
+ static QString getTypeIndexVariableName(const AbstractMetaType &type) ;
+
+ /// Collect all type names as an array for initializing the type/name struct.
+ void collectFullTypeNamesArray(QStringList &typeNames);
+
+ /// Returns true if the user don't want verbose error messages on the generated bindings.
+ static bool verboseErrorMessagesDisabled();
+
+ void collectContainerTypesFromConverterMacros(const QString &code, bool toPythonMacro);
+
+ static void writeFunctionCall(TextStream &s,
+ const AbstractMetaFunctionCPtr &metaFunc,
+ Options options = NoOption);
+
+ // All data about extended converters: the type entries of the target type, and a
+ // list of AbstractMetaClasses accepted as argument for the conversion.
+ using ExtendedConverterData = QHash<TypeEntryCPtr, AbstractMetaClassCList>;
+ /// Returns all extended conversions for the current module.
+ ExtendedConverterData getExtendedConverters() const;
+
+ /// Returns a list of converters for the non wrapper types of the current module.
+ static QList<CustomConversionPtr> getPrimitiveCustomConversions();
+
+ /// Returns true if the Python wrapper for the received OverloadData must accept a list of arguments.
+ bool pythonFunctionWrapperUsesListOfArguments(const AbstractMetaFunctionCPtr &func) const;
+
+ static const QRegularExpression &convertToCppRegEx()
+ { return typeSystemConvRegExps()[TypeSystemToCppFunction]; }
+
+ static QString pythonArgsAt(int i);
+
+ /// Return the format character for C++->Python->C++ conversion (Py_BuildValue)
+ static const QHash<QString, QChar> &formatUnits();
+
+ static QString stdMove(const QString &c);
+
+private:
+ static QString getModuleHeaderFileBaseName(const QString &moduleName = QString());
+ static QString cpythonGetterFunctionName(const QString &name,
+ const AbstractMetaClassCPtr &enclosingClass);
+ static QString cpythonSetterFunctionName(const QString &name,
+ const AbstractMetaClassCPtr &enclosingClass);
+
+ static const GeneratorClassInfoCacheEntry &
+ getGeneratorClassInfo(const AbstractMetaClassCPtr &scope);
+ static FunctionGroups getFunctionGroupsImpl(const AbstractMetaClassCPtr &scope);
+ static QList<AbstractMetaFunctionCList>
+ getNumberProtocolOperators(const AbstractMetaClassCPtr &metaClass);
+ static BoolCastFunctionOptional getBoolCast(const AbstractMetaClassCPtr &metaClass);
+ static bool classNeedsGetattroFunctionImpl(const AbstractMetaClassCPtr &metaClass);
+
+ QString translateTypeForWrapperMethod(const AbstractMetaType &cType,
+ const AbstractMetaClassCPtr &context,
+ Options opt = NoOption) const;
+
+ /**
+ * Returns all different inherited overloads of func.
+ * The function can be called multiple times without duplication.
+ * \param func the metafunction to be searched in subclasses.
+ * \param seen the function's minimal signatures already seen.
+ */
+ static void getInheritedOverloads(const AbstractMetaClassCPtr &scope,
+ AbstractMetaFunctionCList *overloads);
+
+
+ /**
+ * Write a function argument in the C++ in the text stream \p s.
+ * This function just call \code s << argumentString(); \endcode
+ * \param s text stream used to write the output.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ void writeArgument(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &argument,
+ Options options = NoOption) const;
+ /**
+ * Create a QString in the C++ format to an function argument.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ QString argumentString(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &argument,
+ Options options = NoOption) const;
+
+ QString functionReturnType(const AbstractMetaFunctionCPtr &func, Options options = NoOption) const;
+
+ /// Utility function for writeCodeSnips.
+ using ArgumentVarReplacementPair = std::pair<AbstractMetaArgument, QString>;
+ using ArgumentVarReplacementList = QList<ArgumentVarReplacementPair>;
+ static ArgumentVarReplacementList
+ getArgumentReplacement(const AbstractMetaFunctionCPtr &func,
+ bool usePyArgs, TypeSystem::Language language,
+ const AbstractMetaArgument *lastArg);
+
+ /// Returns a string with the user's custom code snippets that comply with \p position and \p language.
+ static QString getCodeSnippets(const QList<CodeSnip> &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language);
+
+ enum TypeSystemConverterVariable {
+ TypeSystemCheckFunction = 0,
+ TypeSystemIsConvertibleFunction,
+ TypeSystemToCppFunction,
+ TypeSystemToPythonFunction,
+ TypeSystemConverterVariables
+ };
+ void replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable,
+ QString &code) const;
+
+ /// Replaces the %CONVERTTOPYTHON type system variable.
+ inline void replaceConvertToPythonTypeSystemVariable(QString &code) const
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToPythonFunction, code);
+ }
+ /// Replaces the %CONVERTTOCPP type system variable.
+ inline void replaceConvertToCppTypeSystemVariable(QString &code) const
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToCppFunction, code);
+ }
+ /// Replaces the %ISCONVERTIBLE type system variable.
+ inline void replaceIsConvertibleToCppTypeSystemVariable(QString &code) const
+ {
+ replaceConverterTypeSystemVariable(TypeSystemIsConvertibleFunction, code);
+ }
+ /// Replaces the %CHECKTYPE type system variable.
+ inline void replaceTypeCheckTypeSystemVariable(QString &code) const
+ {
+ replaceConverterTypeSystemVariable(TypeSystemCheckFunction, code);
+ }
+
+ /// Return a prefix with '_' suitable for names in C++
+ static QString moduleCppPrefix(const QString &moduleName = QString());
+
+ /// Functions used to write the function arguments on the class buffer.
+ /// \param s the class output buffer
+ /// \param func the pointer to metafunction information
+ /// \param count the number of function arguments
+ /// \param options some extra options used during the parser
+ static void writeArgumentNames(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ Options option);
+
+ void writeFunctionArguments(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ Options options = NoOption) const;
+
+ void replaceTemplateVariables(QString &code,
+ const AbstractMetaFunctionCPtr &func) const;
+
+ static ShibokenGeneratorOptions m_options;
+
+ /// Type system converter variable replacement names and regular expressions.
+ static const QHash<int, QString> &typeSystemConvName();
+
+ using TypeSystemConverterRegExps = std::array<QRegularExpression, TypeSystemConverterVariables>;
+ static const TypeSystemConverterRegExps &typeSystemConvRegExps();
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(ShibokenGenerator::FunctionGeneration);
+Q_DECLARE_OPERATORS_FOR_FLAGS(ShibokenGenerator::AttroCheck);
+
+#endif // SHIBOKENGENERATOR_H
diff --git a/sources/shiboken6/generator/shibokenconfig.h.in b/sources/shiboken6/generator/shibokenconfig.h.in
new file mode 100644
index 000000000..848bad372
--- /dev/null
+++ b/sources/shiboken6/generator/shibokenconfig.h.in
@@ -0,0 +1,6 @@
+#ifndef SHIBOKENCONFIG_H
+#define SHIBOKENCONFIG_H
+
+#define SHIBOKEN_VERSION "@shiboken6_VERSION@"
+
+#endif
diff --git a/sources/shiboken6/generatorrunnerconfig.h.in b/sources/shiboken6/generatorrunnerconfig.h.in
new file mode 100644
index 000000000..d291fcc53
--- /dev/null
+++ b/sources/shiboken6/generatorrunnerconfig.h.in
@@ -0,0 +1,13 @@
+#ifndef GENERATORRUNNERCONFIG_H
+#define GENERATORRUNNERCONFIG_H
+
+// generatorrunner version
+#define GENERATORRUNNER_VERSION "@generator_VERSION@"
+
+// generatorrunner plugin dir
+#define GENERATORRUNNER_PLUGIN_DIR "@generator_plugin_DIR@"
+
+// module extension
+#define MODULE_EXTENSION "@CMAKE_SHARED_LIBRARY_SUFFIX@"
+
+#endif
diff --git a/sources/shiboken6/generatorrunnermacros.h b/sources/shiboken6/generatorrunnermacros.h
new file mode 100644
index 000000000..1b204bf62
--- /dev/null
+++ b/sources/shiboken6/generatorrunnermacros.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef GENERATORRUNNERMACROS_H
+#define GENERATORRUNNERMACROS_H
+
+// GENRUNNER_API is used for the public API symbols.
+#if defined _WIN32
+ #define GENRUNNER_EXPORT __declspec(dllexport)
+ #if GENRUNNER_EXPORTS
+ #define GENRUNNER_API GENRUNNER_EXPORT
+ #endif
+#elif __GNUC__ >= 4
+ #define GENRUNNER_EXPORT __attribute__ ((visibility("default")))
+ #define GENRUNNER_API GENRUNNER_EXPORT
+#elif __GNUC__ < 4
+ #define GENRUNNER_EXPORT
+#endif
+
+#ifndef GENRUNNER_API
+ #define GENRUNNER_API
+#endif
+#endif
diff --git a/sources/shiboken6/icecc.cmake b/sources/shiboken6/icecc.cmake
new file mode 100644
index 000000000..fa8d3b7cf
--- /dev/null
+++ b/sources/shiboken6/icecc.cmake
@@ -0,0 +1,14 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include (CMakeForceCompiler)
+option(ENABLE_ICECC "Enable icecc checking, for distributed compilation")
+if (ENABLE_ICECC)
+ find_program(ICECC icecc)
+ if (ICECC)
+ message(STATUS "icecc found! Distributed compilation for all!! huhuhu.")
+ cmake_force_cxx_compiler(${ICECC} icecc)
+ else(ICECC)
+ message(FATAL_ERROR "icecc NOT found! re-run cmake without -DENABLE_ICECC")
+ endif(ICECC)
+endif(ENABLE_ICECC)
diff --git a/sources/shiboken6/libshiboken/CMakeLists.txt b/sources/shiboken6/libshiboken/CMakeLists.txt
new file mode 100644
index 000000000..b5bbb498a
--- /dev/null
+++ b/sources/shiboken6/libshiboken/CMakeLists.txt
@@ -0,0 +1,199 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(libshiboken)
+
+option(ENABLE_VERSION_SUFFIX "Used to use current version in suffix to generated files. This is used to allow multiples versions installed simultaneous." FALSE)
+if(ENABLE_VERSION_SUFFIX)
+ set(shiboken6_SUFFIX "-${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}")
+else()
+ set(shiboken6_SUFFIX "")
+endif()
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sbkversion.h.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h" @ONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.py" @ONLY)
+
+# Variable from enclosing scope.
+list(TRANSFORM shiboken_python_files
+ PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../shibokenmodule/files.dir/shibokensupport/"
+ OUTPUT_VARIABLE embedded_shiboken_files)
+
+if (QUIET_BUILD)
+ set(embedding_option "--quiet")
+else()
+ set(embedding_option "")
+endif()
+
+if(SHIBOKEN_IS_CROSS_BUILD)
+ set(host_python_path "${QFP_PYTHON_HOST_PATH}")
+ set(use_pyc_in_embedding FALSE)
+else()
+ set(host_python_path "${Python_EXECUTABLE}")
+ if(PYTHON_LIMITED_API)
+ set(use_pyc_in_embedding FALSE)
+ else()
+ set(use_pyc_in_embedding TRUE)
+ endif()
+endif()
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap_inc.h"
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_inc.h"
+ COMMAND ${host_python_path} -E
+ "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py"
+ --cmake-dir "${CMAKE_CURRENT_BINARY_DIR}/embed"
+ --use-pyc ${use_pyc_in_embedding}
+ ${embedding_option}
+ DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py"
+ "${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py"
+ ${embedded_shiboken_files}
+ )
+
+set(libshiboken_MAJOR_VERSION ${shiboken_MAJOR_VERSION})
+set(libshiboken_MINOR_VERSION ${shiboken_MINOR_VERSION})
+set(libshiboken_MICRO_VERSION ${shiboken_MICRO_VERSION})
+set(libshiboken_VERSION "${libshiboken_MAJOR_VERSION}.${libshiboken_MINOR_VERSION}.${libshiboken_MICRO_VERSION}")
+set(libshiboken_SOVERSION "${shiboken6_library_so_version}")
+
+set(libshiboken_SRC
+autodecref.h
+basewrapper.cpp basewrapper.h basewrapper_p.h
+bindingmanager.cpp bindingmanager.h
+bufferprocs_py37.cpp bufferprocs_py37.h
+debugfreehook.cpp debugfreehook.h
+gilstate.cpp gilstate.h
+helper.cpp helper.h
+pep384impl.cpp pep384impl.h
+pyobjectholder.h
+sbkarrayconverter.cpp sbkarrayconverter.h sbkarrayconverter_p.h
+sbkcontainer.cpp sbkcontainer.h
+sbkconverter.cpp sbkconverter.h sbkconverter_p.h
+sbkcppstring.cpp sbkcppstring.h sbkcpptonumpy.h
+sbkenum.cpp sbkenum.h
+sbkerrors.cpp sbkerrors.h
+sbkfeature_base.cpp sbkfeature_base.h
+sbkmodule.cpp sbkmodule.h
+sbknumpy.cpp sbknumpycheck.h
+sbknumpyview.h
+sbkpython.h
+sbksmartpointer.cpp sbksmartpointer.h
+sbkstaticstrings.cpp sbkstaticstrings.h sbkstaticstrings_p.h
+sbkstring.cpp sbkstring.h
+sbktypefactory.cpp sbktypefactory.h
+sbkwindows.h
+shiboken.h
+shibokenbuffer.cpp shibokenbuffer.h
+shibokenmacros.h
+threadstatesaver.cpp threadstatesaver.h
+voidptr.cpp voidptr.h
+
+embed/signature_bootstrap_inc.h
+embed/signature_inc.h
+
+signature/signature.cpp signature.h signature_p.h
+signature/signature_globals.cpp
+signature/signature_extend.cpp
+signature/signature_helper.cpp
+)
+
+# This is needed to let the header obey a variable in "pep384impl.h".
+# Note: This must be set on the cpp file!
+set_property(SOURCE "pep384impl.cpp" PROPERTY SKIP_UNITY_BUILD_INCLUSION ON)
+
+add_library(libshiboken SHARED ${libshiboken_SRC})
+add_library(Shiboken6::libshiboken ALIAS libshiboken)
+
+target_include_directories(libshiboken PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
+ $<INSTALL_INTERFACE:include/shiboken6>
+)
+
+if (NOT "${NUMPY_INCLUDE_DIR}" STREQUAL "")
+ message(STATUS "NUMPY_INCLUDE_DIR: " ${NUMPY_INCLUDE_DIR})
+ target_include_directories(libshiboken PRIVATE ${NUMPY_INCLUDE_DIR})
+ target_compile_definitions(libshiboken PRIVATE -DHAVE_NUMPY
+ PRIVATE -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION)
+else()
+ message(STATUS "NUMPY not found")
+endif()
+
+if(SHIBOKEN_IS_CROSS_BUILD)
+ target_compile_definitions(libshiboken PRIVATE -DSHIBOKEN_NO_EMBEDDING_PYC=1)
+endif()
+
+shiboken_compute_python_includes()
+# On Windows we need to link against the python.lib import library.
+# On macOS and Linux we don't link against the python shared / static library,
+# the dynamic linker will pick up the python symbols at runtime automatically.
+shiboken_compute_python_libraries()
+
+if(PYTHON_LIMITED_API)
+ target_compile_definitions(libshiboken PUBLIC "-DPy_LIMITED_API=0x03060000")
+endif()
+
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ if(PYTHON_WITH_DEBUG)
+ target_compile_definitions(libshiboken PUBLIC "-DPy_DEBUG")
+ endif()
+ if (PYTHON_WITH_COUNT_ALLOCS)
+ target_compile_definitions(libshiboken PUBLIC "-DCOUNT_ALLOCS")
+ endif()
+elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
+ target_compile_definitions(libshiboken PUBLIC "-DNDEBUG")
+endif()
+
+set_target_properties(libshiboken PROPERTIES OUTPUT_NAME "shiboken6${shiboken6_SUFFIX}${PYTHON_SHARED_LIBRARY_SUFFIX}"
+ VERSION ${libshiboken_VERSION}
+ SOVERSION ${libshiboken_SOVERSION}
+ DEFINE_SYMBOL BUILD_LIBSHIBOKEN)
+
+qfp_strip_library("libshiboken")
+
+install(FILES
+ autodecref.h
+ basewrapper.h
+ basewrapper_p.h
+ bindingmanager.h
+ gilstate.h
+ helper.h
+ pyobjectholder.h
+ sbkarrayconverter.h
+ sbkcontainer.h
+ sbkconverter.h
+ sbkcpptonumpy.h
+ sbkenum.h
+ sbkerrors.h
+ sbkfeature_base.h
+ sbkmodule.h
+ sbknumpycheck.h
+ sbknumpyview.h
+ sbkstring.h
+ sbkcppstring.h
+ sbksmartpointer.h
+ sbkstaticstrings.h
+ sbktypefactory.h
+ shiboken.h
+ shibokenmacros.h
+ threadstatesaver.h
+ shibokenbuffer.h
+ sbkpython.h
+ sbkwindows.h
+ pep384impl.h
+ pep384ext.h
+ voidptr.h
+ bufferprocs_py37.h
+ "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h"
+
+ signature.h
+ signature_p.h
+
+ DESTINATION include/shiboken6${shiboken6_SUFFIX})
+install(TARGETS libshiboken EXPORT Shiboken6Targets
+ LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
+ ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
+ RUNTIME DESTINATION bin)
+install(EXPORT Shiboken6Targets NAMESPACE Shiboken6::
+ DESTINATION ${LIB_INSTALL_DIR}/cmake/Shiboken6)
diff --git a/sources/shiboken6/libshiboken/autodecref.h b/sources/shiboken6/libshiboken/autodecref.h
new file mode 100644
index 000000000..62a8584e1
--- /dev/null
+++ b/sources/shiboken6/libshiboken/autodecref.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef AUTODECREF_H
+#define AUTODECREF_H
+
+#include "sbkpython.h"
+
+#include <utility>
+
+struct SbkObject;
+namespace Shiboken
+{
+
+/**
+ * AutoDecRef holds a PyObject pointer and decrement its reference counter when destroyed.
+ */
+struct AutoDecRef
+{
+public:
+ AutoDecRef(const AutoDecRef &) = delete;
+ AutoDecRef(AutoDecRef &&o) noexcept : m_pyObj{std::exchange(o.m_pyObj, nullptr)} {}
+ AutoDecRef &operator=(const AutoDecRef &) = delete;
+ AutoDecRef &operator=(AutoDecRef &&o) noexcept
+ {
+ m_pyObj = std::exchange(o.m_pyObj, nullptr);
+ return *this;
+ }
+
+ /// AutoDecRef constructor.
+ /// \param pyobj A borrowed reference to a Python object
+ explicit AutoDecRef(PyObject *pyObj) noexcept : m_pyObj(pyObj) {}
+ /// AutoDecRef constructor.
+ /// \param pyobj A borrowed reference to a wrapped Python object
+ explicit AutoDecRef(SbkObject *pyObj) noexcept : m_pyObj(reinterpret_cast<PyObject *>(pyObj)) {}
+ /// AutoDecref default constructor.
+ /// To be used later with reset():
+ AutoDecRef() noexcept = default;
+
+ /// Decref the borrowed python reference
+ ~AutoDecRef()
+ {
+ Py_XDECREF(m_pyObj);
+ }
+
+ [[nodiscard]] bool isNull() const { return m_pyObj == nullptr; }
+ /// Returns the pointer of the Python object being held.
+ [[nodiscard]] PyObject *object() const { return m_pyObj; }
+ [[nodiscard]] operator PyObject *() const { return m_pyObj; }
+#ifndef Py_LIMITED_API
+ [[deprecated]] inline operator PyTupleObject *()
+ { return reinterpret_cast<PyTupleObject *>(m_pyObj); }
+#endif
+ inline operator bool() const { return m_pyObj != nullptr; }
+ inline PyObject *operator->() { return m_pyObj; }
+
+ template<typename T>
+ [[deprecated]] T cast()
+ {
+ return reinterpret_cast<T>(m_pyObj);
+ }
+
+ /**
+ * Decref the current borrowed python reference and borrow \p other.
+ */
+ void reset(PyObject *other)
+ {
+ // Safely decref m_pyObj. See Py_XSETREF in object.h .
+ PyObject *_py_tmp = m_pyObj;
+ m_pyObj = other;
+ Py_XDECREF(_py_tmp);
+ }
+
+ PyObject *release()
+ {
+ PyObject *result = m_pyObj;
+ m_pyObj = nullptr;
+ return result;
+ }
+
+private:
+ PyObject *m_pyObj = nullptr;
+};
+
+} // namespace Shiboken
+
+#endif // AUTODECREF_H
diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp
new file mode 100644
index 000000000..0ce80d0c6
--- /dev/null
+++ b/sources/shiboken6/libshiboken/basewrapper.cpp
@@ -0,0 +1,1924 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+#include "bindingmanager.h"
+#include "helper.h"
+#include "pep384ext.h"
+#include "sbkconverter.h"
+#include "sbkenum.h"
+#include "sbkerrors.h"
+#include "sbkfeature_base.h"
+#include "sbkmodule.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "autodecref.h"
+#include "gilstate.h"
+#include <string>
+#include <cstring>
+#include <cstddef>
+#include <set>
+#include <sstream>
+#include <algorithm>
+#include "threadstatesaver.h"
+#include "signature.h"
+#include "signature_p.h"
+#include "voidptr.h"
+
+#include <string>
+#include <iostream>
+#include <sstream>
+
+#if defined(__APPLE__)
+#include <dlfcn.h>
+#endif
+
+namespace {
+ void _destroyParentInfo(SbkObject *obj, bool keepReference);
+}
+
+namespace Shiboken
+{
+// Walk through the first level of non-user-type Sbk base classes relevant for
+// C++ object allocation. Return true from the predicate to terminate.
+template <class Predicate>
+bool walkThroughBases(PyTypeObject *currentType, Predicate predicate)
+{
+ PyObject *bases = currentType->tp_bases;
+ const Py_ssize_t numBases = PyTuple_Size(bases);
+ bool result = false;
+ for (Py_ssize_t i = 0; !result && i < numBases; ++i) {
+ auto type = reinterpret_cast<PyTypeObject *>(PyTuple_GetItem(bases, i));
+ if (PyType_IsSubtype(type, SbkObject_TypeF()) != 0) {
+ result = PepType_SOTP(type)->is_user_type
+ ? walkThroughBases(type, predicate) : predicate(type);
+ }
+ }
+ return result;
+}
+
+int getTypeIndexOnHierarchy(PyTypeObject *baseType, PyTypeObject *desiredType)
+{
+ int index = -1;
+ walkThroughBases(baseType, [&index, desiredType](PyTypeObject *node) {
+ ++index;
+ return PyType_IsSubtype(node, desiredType) != 0;
+ });
+ return index;
+}
+
+int getNumberOfCppBaseClasses(PyTypeObject *baseType)
+{
+ int count = 0;
+ walkThroughBases(baseType, [&count](PyTypeObject *) {
+ ++count;
+ return false;
+ });
+ return count;
+}
+
+std::vector<PyTypeObject *> getCppBaseClasses(PyTypeObject *baseType)
+{
+ std::vector<PyTypeObject *> cppBaseClasses;
+ walkThroughBases(baseType, [&cppBaseClasses](PyTypeObject *node) {
+ cppBaseClasses.push_back(node);
+ return false;
+ });
+ return cppBaseClasses;
+}
+
+using DestructorEntries = std::vector<DestructorEntry>;
+
+DestructorEntries getDestructorEntries(SbkObject *o)
+{
+ DestructorEntries result;
+ void **cptrs = o->d->cptr;
+ walkThroughBases(Py_TYPE(o), [&result, cptrs](PyTypeObject *node) {
+ auto *sotp = PepType_SOTP(node);
+ auto index = result.size();
+ result.push_back(DestructorEntry{sotp->cpp_dtor,
+ cptrs[index]});
+ return false;
+ });
+ return result;
+}
+
+static void callDestructor(const DestructorEntries &dts)
+{
+ for (const auto &e : dts) {
+ Shiboken::ThreadStateSaver threadSaver;
+ threadSaver.save();
+ e.destructor(e.cppInstance);
+ }
+}
+
+} // namespace Shiboken
+
+extern "C"
+{
+
+// PYSIDE-939: A general replacement for object_dealloc.
+void Sbk_object_dealloc(PyObject *self)
+{
+ if (PepRuntime_38_flag) {
+ // PYSIDE-939: Handling references correctly.
+ // This was not needed before Python 3.8 (Python issue 35810)
+ Py_DECREF(Py_TYPE(self));
+ }
+ PepExt_TypeCallFree(self);
+}
+
+static void SbkObjectType_tp_dealloc(PyTypeObject *pyType);
+static PyTypeObject *SbkObjectType_tp_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds);
+
+static DestroyQAppHook DestroyQApplication = nullptr;
+
+// PYSIDE-1470: Provide a hook to kill an Application from Shiboken.
+void setDestroyQApplication(DestroyQAppHook func)
+{
+ DestroyQApplication = func;
+}
+
+// PYSIDE-535: Use the C API in PyPy instead of `op->ob_dict`, directly
+LIBSHIBOKEN_API PyObject *SbkObject_GetDict_NoRef(PyObject *op)
+{
+ assert(Shiboken::Object::checkType(op));
+#ifdef PYPY_VERSION
+ Shiboken::GilState state;
+ auto *ret = PyObject_GenericGetDict(op, nullptr);
+ Py_DECREF(ret);
+ return ret;
+#else
+ auto *sbkObj = reinterpret_cast<SbkObject *>(op);
+ if (!sbkObj->ob_dict) {
+ Shiboken::GilState state;
+ sbkObj->ob_dict = PyDict_New();
+ }
+ return sbkObj->ob_dict;
+#endif
+}
+
+static int
+check_set_special_type_attr(PyTypeObject *type, PyObject *value, const char *name)
+{
+ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ PyErr_Format(PyExc_TypeError,
+ "can't set %s.%s", type->tp_name, name);
+ return 0;
+ }
+ if (!value) {
+ PyErr_Format(PyExc_TypeError,
+ "can't delete %s.%s", type->tp_name, name);
+ return 0;
+ }
+ return 1;
+}
+
+// PYSIDE-1177: Add a setter to allow setting type doc.
+static int
+type_set_doc(PyTypeObject *type, PyObject *value, void * /* context */)
+{
+ if (!check_set_special_type_attr(type, value, "__doc__"))
+ return -1;
+ PyType_Modified(type);
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(type));
+ return PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::doc(), value);
+}
+
+// PYSIDE-908: The function PyType_Modified does not work in PySide, so we need to
+// explicitly pass __doc__.
+static PyGetSetDef SbkObjectType_tp_getset[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(Sbk_TypeGet___doc__),
+ reinterpret_cast<setter>(type_set_doc), nullptr, nullptr},
+ {const_cast<char *>("__dict__"), reinterpret_cast<getter>(Sbk_TypeGet___dict__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr} // Sentinel
+};
+
+static PyTypeObject *createObjectTypeType()
+{
+ PyType_Slot SbkObjectType_Type_slots[] = {
+ {Py_tp_dealloc, reinterpret_cast<void *>(SbkObjectType_tp_dealloc)},
+ {Py_tp_getattro, reinterpret_cast<void *>(mangled_type_getattro)},
+ {Py_tp_base, static_cast<void *>(&PyType_Type)},
+ {Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)},
+ {Py_tp_new, reinterpret_cast<void *>(SbkObjectType_tp_new)},
+ {Py_tp_free, reinterpret_cast<void *>(PyObject_GC_Del)},
+ {Py_tp_getset, reinterpret_cast<void *>(SbkObjectType_tp_getset)},
+ {0, nullptr}
+ };
+
+ // PYSIDE-535: The tp_itemsize field is inherited and does not need to be set.
+ // In PyPy, it _must_ not be set, because it would have the meanin
+ // that a `__len__` field must be defined. Not doing so creates
+ // a hard-to-find crash.
+ //
+ // PYSIDE-2230: In Python < 3.12, the decision which base class should create
+ // the instance is arbitrarily drawn by the size of the type.
+ // Ignoring this creates a bug in the new version of bug_825 that
+ // selects the wrong metatype.
+ //
+ PyType_Spec SbkObjectType_Type_spec = {
+ "1:Shiboken.ObjectType",
+ static_cast<int>(PyType_Type.tp_basicsize) + 1, // see above
+ 0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_TYPE_SUBCLASS,
+ SbkObjectType_Type_slots,
+ };
+
+ PyType_Spec SbkObjectType_Type_spec_312 = {
+ "1:Shiboken.ObjectType",
+ -long(sizeof(SbkObjectTypePrivate)),
+ 0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_TYPE_SUBCLASS,
+ SbkObjectType_Type_slots,
+ };
+
+ return SbkType_FromSpec(_PepRuntimeVersion() >= 0x030C00 ?
+ &SbkObjectType_Type_spec_312 :
+ &SbkObjectType_Type_spec);
+}
+
+PyTypeObject *SbkObjectType_TypeF(void)
+{
+ static auto *type = createObjectTypeType();
+ return type;
+}
+
+static PyObject *SbkObjectGetDict(PyObject *pObj, void *)
+{
+ auto ret = SbkObject_GetDict_NoRef(pObj);
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyGetSetDef SbkObject_tp_getset[] = {
+ {const_cast<char *>("__dict__"), SbkObjectGetDict, nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr} // Sentinel
+};
+
+static int SbkObject_tp_traverse(PyObject *self, visitproc visit, void *arg)
+{
+ auto *sbkSelf = reinterpret_cast<SbkObject *>(self);
+
+ //Visit children
+ Shiboken::ParentInfo *pInfo = sbkSelf->d->parentInfo;
+ if (pInfo) {
+ for (SbkObject *c : pInfo->children)
+ Py_VISIT(c);
+ }
+
+ //Visit refs
+ Shiboken::RefCountMap *rInfo = sbkSelf->d->referredObjects;
+ if (rInfo) {
+ for (auto it = rInfo->begin(), end = rInfo->end(); it != end; ++it)
+ Py_VISIT(it->second);
+ }
+
+ if (sbkSelf->ob_dict)
+ Py_VISIT(sbkSelf->ob_dict);
+
+ // This was not needed before Python 3.9 (Python issue 35810 and 40217)
+ Py_VISIT(Py_TYPE(self));
+ return 0;
+}
+
+static int SbkObject_tp_clear(PyObject *self)
+{
+ auto *sbkSelf = reinterpret_cast<SbkObject *>(self);
+
+ Shiboken::Object::removeParent(sbkSelf);
+
+ if (sbkSelf->d->parentInfo)
+ _destroyParentInfo(sbkSelf, true);
+
+ Shiboken::Object::clearReferences(sbkSelf);
+
+ if (sbkSelf->ob_dict)
+ Py_CLEAR(sbkSelf->ob_dict);
+ return 0;
+}
+
+static PyTypeObject *createObjectType()
+{
+ PyType_Slot SbkObject_Type_slots[] = {
+ {Py_tp_getattro, reinterpret_cast<void *>(SbkObject_GenericGetAttr)},
+ {Py_tp_setattro, reinterpret_cast<void *>(SbkObject_GenericSetAttr)},
+ {Py_tp_dealloc, reinterpret_cast<void *>(SbkDeallocWrapperWithPrivateDtor)},
+ {Py_tp_traverse, reinterpret_cast<void *>(SbkObject_tp_traverse)},
+ {Py_tp_clear, reinterpret_cast<void *>(SbkObject_tp_clear)},
+ // unsupported: {Py_tp_weaklistoffset, (void *)offsetof(SbkObject, weakreflist)},
+ {Py_tp_getset, reinterpret_cast<void *>(SbkObject_tp_getset)},
+ // unsupported: {Py_tp_dictoffset, (void *)offsetof(SbkObject, ob_dict)},
+ {0, nullptr}
+ };
+
+ PyType_Spec SbkObject_Type_spec = {
+ "1:Shiboken.Object",
+ sizeof(SbkObject),
+ 0,
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
+ SbkObject_Type_slots,
+ };
+
+ // PYSIDE-2230: When creating this type, we cannot easily handle the metaclass.
+ // In versions < Python 3.12, the metaclass can only be set
+ // indirectly by a base which has that metaclass.
+ // But before 3.12 is the minimum version, we cannot use the new
+ // function, although we would need this for 3.12 :-D
+ // We do a special patching here that is triggered through Py_None.
+ auto *type = SbkType_FromSpec_BMDWB(&SbkObject_Type_spec,
+ Py_None, // bases, spectial flag!
+ SbkObjectType_TypeF(),
+ offsetof(SbkObject, ob_dict),
+ offsetof(SbkObject, weakreflist),
+ nullptr); // bufferprocs
+ return type;
+}
+
+PyTypeObject *SbkObject_TypeF(void)
+{
+ static auto *type = createObjectType(); // bufferprocs
+ return type;
+}
+
+static const char *SbkObject_SignatureStrings[] = {
+ "Shiboken.Object(self)",
+ nullptr}; // Sentinel
+
+static int mainThreadDeletionHandler(void *)
+{
+ if (Py_IsInitialized())
+ Shiboken::BindingManager::instance().runDeletionInMainThread();
+ return 0;
+}
+
+static void SbkDeallocWrapperCommon(PyObject *pyObj, bool canDelete)
+{
+ auto *sbkObj = reinterpret_cast<SbkObject *>(pyObj);
+ PyTypeObject *pyType = Py_TYPE(pyObj);
+
+ // Need to decref the type if this is the dealloc func; if type
+ // is subclassed, that dealloc func will decref (see subtype_dealloc
+ // in typeobject.c in the python sources)
+ auto dealloc = PyType_GetSlot(pyType, Py_tp_dealloc);
+ bool needTypeDecref = dealloc == SbkDeallocWrapper
+ || dealloc == SbkDeallocWrapperWithPrivateDtor;
+ if (PepRuntime_38_flag) {
+ // PYSIDE-939: Additional rule: Also when a subtype is heap allocated,
+ // then the subtype_dealloc deref will be suppressed, and we need again
+ // to supply a decref.
+ needTypeDecref |= (pyType->tp_base->tp_flags & Py_TPFLAGS_HEAPTYPE) != 0;
+ }
+
+#if defined(__APPLE__)
+ // Just checking once that our assumptions are right.
+ if (false) {
+ void *p = PyType_GetSlot(pyType, Py_tp_dealloc);
+ Dl_info dl_info;
+ dladdr(p, &dl_info);
+ fprintf(stderr, "tp_dealloc is %s\n", dl_info.dli_sname);
+ }
+ // Gives one of our functions
+ // "Sbk_object_dealloc"
+ // "SbkDeallocWrapperWithPrivateDtor"
+ // "SbkDeallocQAppWrapper"
+ // "SbkDeallocWrapper"
+ // but for typedealloc_test.py we get
+ // "subtype_dealloc"
+#endif
+
+ // Ensure that the GC is no longer tracking this object to avoid a
+ // possible reentrancy problem. Since there are multiple steps involved
+ // in deallocating a SbkObject it is possible for the garbage collector to
+ // be invoked and it trying to delete this object while it is still in
+ // progress from the first time around, resulting in a double delete and a
+ // crash.
+ PyObject_GC_UnTrack(pyObj);
+
+ // Check that Python is still initialized as sometimes this is called by a static destructor
+ // after Python interpeter is shutdown.
+ if (sbkObj->weakreflist && Py_IsInitialized())
+ PyObject_ClearWeakRefs(pyObj);
+
+ // If I have ownership and is valid delete C++ pointer
+ auto *sotp = PepType_SOTP(pyType);
+ canDelete &= sbkObj->d->hasOwnership && sbkObj->d->validCppObject;
+ if (canDelete) {
+ if (sotp->delete_in_main_thread && Shiboken::currentThreadId() != Shiboken::mainThreadId()) {
+ auto &bindingManager = Shiboken::BindingManager::instance();
+ if (sotp->is_multicpp) {
+ const auto entries = Shiboken::getDestructorEntries(sbkObj);
+ for (const auto &e : entries)
+ bindingManager.addToDeletionInMainThread(e);
+ } else {
+ Shiboken::DestructorEntry e{sotp->cpp_dtor, sbkObj->d->cptr[0]};
+ bindingManager.addToDeletionInMainThread(e);
+ }
+ Py_AddPendingCall(mainThreadDeletionHandler, nullptr);
+ canDelete = false;
+ }
+ }
+
+ PyObject *error_type, *error_value, *error_traceback;
+
+ /* Save the current exception, if any. */
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
+ if (canDelete) {
+ if (sotp->is_multicpp) {
+ const auto entries = Shiboken::getDestructorEntries(sbkObj);
+ Shiboken::Object::deallocData(sbkObj, true);
+ callDestructor(entries);
+ } else {
+ void *cptr = sbkObj->d->cptr[0];
+ Shiboken::Object::deallocData(sbkObj, true);
+
+ Shiboken::ThreadStateSaver threadSaver;
+ if (Py_IsInitialized())
+ threadSaver.save();
+ sotp->cpp_dtor(cptr);
+ }
+ } else {
+ Shiboken::Object::deallocData(sbkObj, true);
+ }
+
+ /* Restore the saved exception. */
+ PyErr_Restore(error_type, error_value, error_traceback);
+
+ if (needTypeDecref)
+ Py_DECREF(pyType);
+ if (PepRuntime_38_flag) {
+ // PYSIDE-939: Handling references correctly.
+ // This was not needed before Python 3.8 (Python issue 35810)
+ Py_DECREF(pyType);
+ }
+}
+
+static inline PyObject *_Sbk_NewVarObject(PyTypeObject *type)
+{
+ // PYSIDE-1970: Support __slots__, implemented by PyVarObject
+ auto const baseSize = sizeof(SbkObject);
+ auto varCount = Py_SIZE(type);
+ auto *self = PyObject_GC_NewVar(PyObject, type, varCount);
+ if (varCount)
+ std::memset(reinterpret_cast<char *>(self) + baseSize, 0, varCount * sizeof(void *));
+ return self;
+}
+
+void SbkDeallocWrapper(PyObject *pyObj)
+{
+ SbkDeallocWrapperCommon(pyObj, true);
+}
+
+void SbkDeallocQAppWrapper(PyObject *pyObj)
+{
+ SbkDeallocWrapper(pyObj);
+ // PYSIDE-571: make sure to create a singleton deleted qApp.
+ Py_DECREF(MakeQAppWrapper(nullptr));
+}
+
+void SbkDeallocWrapperWithPrivateDtor(PyObject *self)
+{
+ SbkDeallocWrapperCommon(self, false);
+}
+
+void SbkObjectType_tp_dealloc(PyTypeObject *sbkType)
+{
+ SbkObjectTypePrivate *sotp = PepType_SOTP(sbkType);
+ auto pyObj = reinterpret_cast<PyObject *>(sbkType);
+
+ PyObject_GC_UnTrack(pyObj);
+#if !defined(Py_LIMITED_API) && !defined(PYPY_VERSION)
+# if PY_VERSION_HEX >= 0x030A0000
+ Py_TRASHCAN_BEGIN(pyObj, 1);
+# else
+ Py_TRASHCAN_SAFE_BEGIN(pyObj);
+# endif
+#endif
+ if (sotp) {
+ if (sotp->user_data && sotp->d_func) {
+ sotp->d_func(sotp->user_data);
+ sotp->user_data = nullptr;
+ }
+ free(sotp->original_name);
+ sotp->original_name = nullptr;
+ if (!Shiboken::ObjectType::isUserType(sbkType))
+ Shiboken::Conversions::deleteConverter(sotp->converter);
+ PepType_SOTP_delete(sbkType);
+ }
+#if !defined(Py_LIMITED_API) && !defined(PYPY_VERSION)
+# if PY_VERSION_HEX >= 0x030A0000
+ Py_TRASHCAN_END;
+# else
+ Py_TRASHCAN_SAFE_END(pyObj);
+# endif
+#endif
+ if (PepRuntime_38_flag) {
+ // PYSIDE-939: Handling references correctly.
+ // This was not needed before Python 3.8 (Python issue 35810)
+ Py_DECREF(Py_TYPE(pyObj));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Support for the qApp macro.
+//
+// qApp is a macro in Qt5. In Python, we simulate that a little by a
+// variable that monitors Q*Application.instance().
+// This variable is also able to destroy the app by qApp.shutdown().
+//
+
+PyObject *MakeQAppWrapper(PyTypeObject *type)
+{
+ static PyObject *qApp_last = nullptr;
+
+ // protecting from multiple application instances
+ if (!(type == nullptr || qApp_last == Py_None)) {
+ const char *res_name = qApp_last != nullptr
+ ? PepType_GetNameStr(Py_TYPE(qApp_last)) : "<Unknown>";
+ const char *type_name = PepType_GetNameStr(type);
+ PyErr_Format(PyExc_RuntimeError, "Please destroy the %s singleton before"
+ " creating a new %s instance.", res_name, type_name);
+ return nullptr;
+ }
+
+ // monitoring the last application state
+ PyObject *qApp_curr = type != nullptr ? _Sbk_NewVarObject(type) : Py_None;
+ static PyObject *builtins = PyEval_GetBuiltins();
+ if (PyDict_SetItem(builtins, Shiboken::PyName::qApp(), qApp_curr) < 0)
+ return nullptr;
+ qApp_last = qApp_curr;
+ // Note: This Py_INCREF would normally be wrong because the qApp
+ // object already has a reference from PyObject_GC_New. But this is
+ // exactly the needed reference that keeps qApp alive from alone!
+ Py_INCREF(qApp_curr);
+ // PYSIDE-1470: As a side effect, the interactive "_" variable tends to
+ // create reference cycles. This is disturbing when trying
+ // to remove qApp with del.
+ // PYSIDE-1758: Since we moved to an explicit qApp.shutdown() call, we
+ // no longer initialize "_" with Py_None.
+ return qApp_curr;
+}
+
+static PyTypeObject *SbkObjectType_tp_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
+{
+ // Check if all bases are new style before calling type.tp_new
+ // Was causing gc assert errors in test_bug704.py when
+ // this check happened after creating the type object.
+ // Argument parsing take from type.tp_new code.
+
+ // PYSIDE-595: Also check if all bases allow inheritance.
+ // Before we changed to heap types, it was sufficient to remove the
+ // Py_TPFLAGS_BASETYPE flag. That does not work, because PySide does
+ // not respect this flag itself!
+ PyObject *name;
+ PyObject *pyBases;
+ PyObject *dict;
+ static const char *kwlist[] = { "name", "bases", "dict", nullptr};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO!O!:sbktype", const_cast<char **>(kwlist),
+ &name,
+ &PyTuple_Type, &pyBases,
+ &PyDict_Type, &dict))
+ return nullptr;
+
+ for (int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) {
+ PyObject *baseType = PyTuple_GET_ITEM(pyBases, i);
+ if (PepExt_Type_GetNewSlot(reinterpret_cast<PyTypeObject *>(baseType)) == SbkDummyNew) {
+ // PYSIDE-595: A base class does not allow inheritance.
+ return reinterpret_cast<PyTypeObject *>(SbkDummyNew(metatype, args, kwds));
+ }
+ }
+
+ // PYSIDE-939: This is still a temporary patch that circumvents the problem
+ // with Py_TPFLAGS_METHOD_DESCRIPTOR. The problem exists in Python 3.8
+ // until 3.9.12, only. We check the runtime and hope for this version valishing.
+ // https://github.com/python/cpython/issues/92112 will not be fixed for 3.8 :/
+ PyTypeObject *newType{};
+ static auto triplet = _PepRuntimeVersion();
+ if (triplet >= (3 << 16 | 8 << 8 | 0) && triplet < (3 << 16 | 9 << 8 | 13)) {
+ auto hold = PyMethodDescr_Type.tp_flags;
+ PyMethodDescr_Type.tp_flags &= ~Py_TPFLAGS_METHOD_DESCRIPTOR;
+ newType = PepType_Type_tp_new(metatype, args, kwds);
+ PyMethodDescr_Type.tp_flags = hold;
+ } else {
+ newType = PepType_Type_tp_new(metatype, args, kwds);
+ }
+
+ if (!newType)
+ return nullptr;
+
+ SbkObjectTypePrivate *sotp = PepType_SOTP(newType);
+
+ const auto bases = Shiboken::getCppBaseClasses(newType);
+ if (bases.size() == 1) {
+ SbkObjectTypePrivate *parentType = PepType_SOTP(bases.front());
+ sotp->mi_offsets = parentType->mi_offsets;
+ sotp->mi_init = parentType->mi_init;
+ sotp->mi_specialcast = parentType->mi_specialcast;
+ sotp->type_discovery = parentType->type_discovery;
+ sotp->cpp_dtor = parentType->cpp_dtor;
+ sotp->is_multicpp = 0;
+ sotp->converter = parentType->converter;
+ } else {
+ sotp->mi_offsets = nullptr;
+ sotp->mi_init = nullptr;
+ sotp->mi_specialcast = nullptr;
+ sotp->type_discovery = nullptr;
+ sotp->cpp_dtor = nullptr;
+ sotp->is_multicpp = 1;
+ sotp->converter = nullptr;
+ }
+ if (bases.size() == 1) {
+ const char *original_name = PepType_SOTP(bases.front())->original_name;
+ if (original_name == nullptr)
+ original_name = "object";
+ sotp->original_name = strdup(original_name);
+ }
+ else
+ sotp->original_name = strdup("object");
+ sotp->user_data = nullptr;
+ sotp->d_func = nullptr;
+ sotp->is_user_type = 1;
+
+ // PYSIDE-1463: Prevent feature switching while in the creation process
+ auto saveFeature = initSelectableFeature(nullptr);
+ for (PyTypeObject *base : bases) {
+ sotp = PepType_SOTP(base);
+ if (sotp->subtype_init)
+ sotp->subtype_init(newType, args, kwds);
+ }
+ initSelectableFeature(saveFeature);
+ return newType;
+}
+
+static PyObject *_setupNew(PyObject *obSelf, PyTypeObject *subtype)
+{
+ auto *obSubtype = reinterpret_cast<PyObject *>(subtype);
+ auto *sbkSubtype = subtype;
+ auto *self = reinterpret_cast<SbkObject *>(obSelf);
+
+ Py_INCREF(obSubtype);
+ auto d = new SbkObjectPrivate;
+
+ auto *sotp = PepType_SOTP(sbkSubtype);
+ int numBases = ((sotp && sotp->is_multicpp) ?
+ Shiboken::getNumberOfCppBaseClasses(subtype) : 1);
+ d->cptr = new void *[numBases];
+ std::memset(d->cptr, 0, sizeof(void *) *size_t(numBases));
+ d->hasOwnership = 1;
+ d->containsCppWrapper = 0;
+ d->validCppObject = 0;
+ d->parentInfo = nullptr;
+ d->referredObjects = nullptr;
+ d->cppObjectCreated = 0;
+ d->isQAppSingleton = 0;
+ self->ob_dict = nullptr;
+ self->weakreflist = nullptr;
+ self->d = d;
+ PyObject_GC_Track(obSelf);
+ return obSelf;
+}
+
+PyObject *SbkObject_tp_new(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
+{
+ PyObject *self = _Sbk_NewVarObject(subtype);
+ return _setupNew(self, subtype);
+}
+
+PyObject *SbkQApp_tp_new(PyTypeObject *subtype, PyObject *, PyObject *)
+{
+ auto *obSelf = MakeQAppWrapper(subtype);
+ auto *self = reinterpret_cast<SbkObject *>(obSelf);
+ if (self == nullptr)
+ return nullptr;
+ auto ret = _setupNew(obSelf, subtype);
+ auto priv = self->d;
+ priv->isQAppSingleton = 1;
+ return ret;
+}
+
+PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *)
+{
+ // PYSIDE-595: Give the same error as type_call does when tp_new is NULL.
+ const char regret[] = "¯\\_(ツ)_/¯";
+ PyErr_Format(PyExc_TypeError,
+ "cannot create '%.100s' instances %s", type->tp_name, regret);
+ return nullptr;
+}
+
+// PYSIDE-74: Fallback used in all types now.
+PyObject *FallbackRichCompare(PyObject *self, PyObject *other, int op)
+{
+ // This is a very simple implementation that supplies a simple identity.
+ static const char * const opstrings[] = {"<", "<=", "==", "!=", ">", ">="};
+ PyObject *res;
+
+ switch (op) {
+
+ case Py_EQ:
+ res = (self == other) ? Py_True : Py_False;
+ break;
+ case Py_NE:
+ res = (self != other) ? Py_True : Py_False;
+ break;
+ default:
+ PyErr_Format(PyExc_TypeError,
+ "'%s' not supported between instances of '%.100s' and '%.100s'",
+ opstrings[op],
+ self->ob_type->tp_name,
+ other->ob_type->tp_name);
+ return nullptr;
+ }
+ Py_INCREF(res);
+ return res;
+}
+
+bool SbkObjectType_Check(PyTypeObject *type)
+{
+ static auto *meta = SbkObjectType_TypeF();
+ return Py_TYPE(type) == meta || PyType_IsSubtype(Py_TYPE(type), meta);
+}
+
+} //extern "C"
+
+
+namespace
+{
+
+void _destroyParentInfo(SbkObject *obj, bool keepReference)
+{
+ Shiboken::ParentInfo *pInfo = obj->d->parentInfo;
+ if (pInfo) {
+ while(!pInfo->children.empty()) {
+ SbkObject *first = *pInfo->children.begin();
+ // Mark child as invalid
+ Shiboken::Object::invalidate(first);
+ Shiboken::Object::removeParent(first, false, keepReference);
+ }
+ Shiboken::Object::removeParent(obj, false);
+ }
+}
+
+}
+
+namespace Shiboken
+{
+
+// Wrapper metatype and base type ----------------------------------------------------------
+
+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()
+{
+ static bool shibokenAlreadInitialised = false;
+ if (shibokenAlreadInitialised)
+ return;
+
+ _initMainThreadId();
+
+ Conversions::init();
+
+ //Init private data
+ Pep384_Init();
+
+ auto *type = SbkObjectType_TypeF();
+ if (type == nullptr || PyType_Ready(type) < 0)
+ Py_FatalError(msgFailedToInitializeType("Shiboken.BaseWrapperType metatype").c_str());
+
+ type = SbkObject_TypeF();
+ if (type == nullptr || PyType_Ready(type) < 0)
+ Py_FatalError(msgFailedToInitializeType("Shiboken.BaseWrapper type").c_str());
+
+ VoidPtr::init();
+
+ shibokenAlreadInitialised = true;
+}
+
+// PYSIDE-1415: Publish Shiboken objects.
+// PYSIDE-1735: Initialize the whole Shiboken startup.
+void initShibokenSupport(PyObject *module)
+{
+ Py_INCREF(SbkObject_TypeF());
+ PyModule_AddObject(module, "Object", reinterpret_cast<PyObject *>(SbkObject_TypeF()));
+
+ // PYSIDE-1735: When the initialization was moved into Shiboken import, this
+ // Py_INCREF became necessary. No idea why.
+ Py_INCREF(module);
+ init_shibokensupport_module();
+
+ auto *type = SbkObject_TypeF();
+ if (InitSignatureStrings(type, SbkObject_SignatureStrings) < 0)
+ Py_FatalError("Error in initShibokenSupport");
+}
+
+// setErrorAboutWrongArguments now gets overload info from the signature module.
+// Info can be nullptr and contains extra info.
+void setErrorAboutWrongArguments(PyObject *args, const char *funcName, PyObject *info)
+{
+ SetError_Argument(args, funcName, info);
+}
+
+PyObject *returnWrongArguments(PyObject *args, const char *funcName, PyObject *info)
+{
+ setErrorAboutWrongArguments(args, funcName, info);
+ return {};
+}
+
+int returnWrongArguments_Zero(PyObject *args, const char *funcName, PyObject *info)
+{
+ setErrorAboutWrongArguments(args, funcName, info);
+ return 0;
+}
+
+int returnWrongArguments_MinusOne(PyObject *args, const char *funcName, PyObject *info)
+{
+ setErrorAboutWrongArguments(args, funcName, info);
+ return -1;
+}
+
+PyObject *returnFromRichCompare(PyObject *result)
+{
+ if (result && !PyErr_Occurred())
+ return result;
+ Shiboken::Errors::setOperatorNotImplemented();
+ return {};
+}
+
+PyObject *checkInvalidArgumentCount(Py_ssize_t numArgs, Py_ssize_t minArgs, Py_ssize_t maxArgs)
+{
+ PyObject *result = nullptr;
+ // for seterror_argument(), signature/errorhandler.py
+ if (numArgs > maxArgs) {
+ static PyObject *const tooMany = Shiboken::String::createStaticString(">");
+ result = tooMany;
+ Py_INCREF(result);
+ } else if (numArgs < minArgs) {
+ static PyObject *const tooFew = Shiboken::String::createStaticString("<");
+ static PyObject *const noArgs = Shiboken::String::createStaticString("0");
+ result = numArgs > 0 ? tooFew : noArgs;
+ Py_INCREF(result);
+ }
+ return result;
+}
+
+std::vector<SbkObject *> splitPyObject(PyObject *pyObj)
+{
+ std::vector<SbkObject *> result;
+ if (PySequence_Check(pyObj)) {
+ AutoDecRef lst(PySequence_Fast(pyObj, "Invalid keep reference object."));
+ if (!lst.isNull()) {
+ for (Py_ssize_t i = 0, i_max = PySequence_Fast_GET_SIZE(lst.object()); i < i_max; ++i) {
+ PyObject *item = PySequence_Fast_GET_ITEM(lst.object(), i);
+ if (Object::checkType(item))
+ result.push_back(reinterpret_cast<SbkObject *>(item));
+ }
+ }
+ } else {
+ result.push_back(reinterpret_cast<SbkObject *>(pyObj));
+ }
+ return result;
+}
+
+template <class Iterator>
+inline void decRefPyObjectList(Iterator i1, Iterator i2)
+{
+ for (; i1 != i2; ++i1)
+ Py_DECREF(i1->second);
+}
+
+namespace ObjectType
+{
+
+bool checkType(PyTypeObject *type)
+{
+ return PyType_IsSubtype(type, SbkObject_TypeF()) != 0;
+}
+
+bool isUserType(PyTypeObject *type)
+{
+ return checkType(type) && PepType_SOTP(type)->is_user_type;
+}
+
+bool canCallConstructor(PyTypeObject *myType, PyTypeObject *ctorType)
+{
+ auto findBasePred = [ctorType](PyTypeObject *type) { return type == ctorType; };
+ if (!walkThroughBases(myType, findBasePred)) {
+ PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", ctorType->tp_name, myType->tp_name);
+ return false;
+ }
+ return true;
+}
+
+bool hasCast(PyTypeObject *type)
+{
+ return PepType_SOTP(type)->mi_specialcast != nullptr;
+}
+
+void *cast(PyTypeObject *sourceType, SbkObject *obj, PyTypeObject *pyTargetType)
+{
+ auto *sotp = PepType_SOTP(sourceType);
+ return sotp->mi_specialcast(Object::cppPointer(obj, pyTargetType), pyTargetType);
+}
+
+void setCastFunction(PyTypeObject *type, SpecialCastFunction func)
+{
+ auto *sotp = PepType_SOTP(type);
+ sotp->mi_specialcast = func;
+}
+
+void setOriginalName(PyTypeObject *type, const char *name)
+{
+ auto *sotp = PepType_SOTP(type);
+ if (sotp->original_name)
+ free(sotp->original_name);
+ sotp->original_name = strdup(name);
+}
+
+const char *getOriginalName(PyTypeObject *type)
+{
+ return PepType_SOTP(type)->original_name;
+}
+
+void setTypeDiscoveryFunctionV2(PyTypeObject *type, TypeDiscoveryFuncV2 func)
+{
+ PepType_SOTP(type)->type_discovery = func;
+}
+
+void copyMultipleInheritance(PyTypeObject *type, PyTypeObject *other)
+{
+ auto *sotp_type = PepType_SOTP(type);
+ auto *sotp_other = PepType_SOTP(other);
+ sotp_type->mi_init = sotp_other->mi_init;
+ sotp_type->mi_offsets = sotp_other->mi_offsets;
+ sotp_type->mi_specialcast = sotp_other->mi_specialcast;
+}
+
+void setMultipleInheritanceFunction(PyTypeObject *type, MultipleInheritanceInitFunction function)
+{
+ PepType_SOTP(type)->mi_init = function;
+}
+
+MultipleInheritanceInitFunction getMultipleInheritanceFunction(PyTypeObject *type)
+{
+ return PepType_SOTP(type)->mi_init;
+}
+
+void setDestructorFunction(PyTypeObject *type, ObjectDestructor func)
+{
+ PepType_SOTP(type)->cpp_dtor = func;
+}
+
+PyTypeObject *
+introduceWrapperType(PyObject *enclosingObject,
+ const char *typeName,
+ const char *originalName,
+ PyType_Spec *typeSpec,
+ ObjectDestructor cppObjDtor,
+ PyObject *bases,
+ unsigned wrapperFlags)
+{
+ 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());
+
+ auto sotp = PepType_SOTP(type);
+ if (wrapperFlags & DeleteInMainThread)
+ sotp->delete_in_main_thread = 1;
+ sotp->type_behaviour = (wrapperFlags & Value) != 0
+ ? BEHAVIOUR_VALUETYPE : BEHAVIOUR_OBJECTTYPE;
+
+ setOriginalName(type, originalName);
+ setDestructorFunction(type, cppObjDtor);
+ auto *ob_type = reinterpret_cast<PyObject *>(type);
+
+ if (wrapperFlags & InnerClass) {
+ // PYSIDE-2230: Instead of tp_dict, use the enclosing type.
+ // This stays interface compatible.
+ if (PyType_Check(enclosingObject)) {
+ AutoDecRef tpDict(PepType_GetDict(reinterpret_cast<PyTypeObject *>(enclosingObject)));
+ return PyDict_SetItemString(tpDict, typeName, ob_type) == 0 ? type : nullptr;
+ }
+ assert(PyDict_Check(enclosingObject));
+ return PyDict_SetItemString(enclosingObject, typeName, ob_type) == 0 ? type : nullptr;
+ }
+
+ // PyModule_AddObject steals type's reference.
+ Py_INCREF(ob_type);
+ if (PyModule_AddObject(enclosingObject, typeName, ob_type) != 0) {
+ std::cerr << "Warning: " << __FUNCTION__ << " returns nullptr for "
+ << typeName << '/' << originalName << " due to PyModule_AddObject(enclosingObject="
+ << enclosingObject << ", ob_type=" << ob_type << ") failing\n";
+ return nullptr;
+ }
+ return type;
+}
+
+void setSubTypeInitHook(PyTypeObject *type, SubTypeInitHook func)
+{
+ assert(SbkObjectType_Check(type));
+ PepType_SOTP(type)->subtype_init = func;
+}
+
+void *getTypeUserData(PyTypeObject *type)
+{
+ assert(SbkObjectType_Check(type));
+ return PepType_SOTP(type)->user_data;
+}
+
+void setTypeUserData(PyTypeObject *type, void *userData, DeleteUserDataFunc d_func)
+{
+ assert(SbkObjectType_Check(type));
+ auto *sotp = PepType_SOTP(type);
+ sotp->user_data = userData;
+ sotp->d_func = d_func;
+}
+
+// Try to find the exact type of cptr.
+PyTypeObject *typeForTypeName(const char *typeName)
+{
+ PyTypeObject *result{};
+ if (typeName) {
+ if (PyTypeObject *pyType = Shiboken::Conversions::getPythonTypeObject(typeName))
+ result = pyType;
+ }
+ return result;
+}
+
+bool hasSpecialCastFunction(PyTypeObject *sbkType)
+{
+ const auto *d = PepType_SOTP(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
+
+
+namespace Object
+{
+
+static void recursive_invalidate(SbkObject *self, std::set<SbkObject *>& seen);
+
+bool checkType(PyObject *pyObj)
+{
+ return ObjectType::checkType(Py_TYPE(pyObj));
+}
+
+bool isUserType(PyObject *pyObj)
+{
+ return ObjectType::isUserType(Py_TYPE(pyObj));
+}
+
+Py_hash_t hash(PyObject *pyObj)
+{
+ assert(Shiboken::Object::checkType(pyObj));
+ return reinterpret_cast<Py_hash_t>(pyObj);
+}
+
+static void setSequenceOwnership(PyObject *pyObj, bool owner)
+{
+
+ bool has_length = true;
+
+ if (!pyObj)
+ return;
+
+ if (PySequence_Size(pyObj) < 0) {
+ PyErr_Clear();
+ has_length = false;
+ }
+
+ if (PySequence_Check(pyObj) && has_length) {
+ Py_ssize_t size = PySequence_Size(pyObj);
+ if (size > 0) {
+ const auto objs = splitPyObject(pyObj);
+ if (owner) {
+ for (SbkObject *o : objs)
+ getOwnership(o);
+ } else {
+ for (SbkObject *o : objs)
+ releaseOwnership(o);
+ }
+ }
+ } else if (Object::checkType(pyObj)) {
+ if (owner)
+ getOwnership(reinterpret_cast<SbkObject *>(pyObj));
+ else
+ releaseOwnership(reinterpret_cast<SbkObject *>(pyObj));
+ }
+}
+
+void setValidCpp(SbkObject *pyObj, bool value)
+{
+ pyObj->d->validCppObject = value;
+}
+
+void setHasCppWrapper(SbkObject *pyObj, bool value)
+{
+ pyObj->d->containsCppWrapper = value;
+}
+
+bool hasCppWrapper(SbkObject *pyObj)
+{
+ return pyObj->d->containsCppWrapper;
+}
+
+bool wasCreatedByPython(SbkObject *pyObj)
+{
+ return pyObj->d->cppObjectCreated;
+}
+
+void callCppDestructors(SbkObject *pyObj)
+{
+ auto priv = pyObj->d;
+ if (priv->isQAppSingleton && DestroyQApplication) {
+ // PYSIDE-1470: Allow to destroy the application from Shiboken.
+ DestroyQApplication();
+ return;
+ }
+ PyTypeObject *type = Py_TYPE(pyObj);
+ auto *sotp = PepType_SOTP(type);
+ if (sotp->is_multicpp) {
+ callDestructor(getDestructorEntries(pyObj));
+ } else {
+ Shiboken::ThreadStateSaver threadSaver;
+ threadSaver.save();
+ sotp->cpp_dtor(pyObj->d->cptr[0]);
+ }
+
+ if (priv->validCppObject && priv->containsCppWrapper) {
+ BindingManager::instance().releaseWrapper(pyObj);
+ }
+
+ /* invalidate needs to be called before deleting pointer array because
+ it needs to delete entries for them from the BindingManager hash table;
+ also release wrapper explicitly if object contains C++ wrapper because
+ invalidate doesn't */
+ invalidate(pyObj);
+
+ delete[] priv->cptr;
+ priv->cptr = nullptr;
+ priv->validCppObject = false;
+}
+
+bool hasOwnership(SbkObject *pyObj)
+{
+ return pyObj->d->hasOwnership;
+}
+
+void getOwnership(SbkObject *self)
+{
+ // skip if already have the ownership
+ if (self->d->hasOwnership)
+ return;
+
+ // skip if this object has parent
+ if (self->d->parentInfo && self->d->parentInfo->parent)
+ return;
+
+ // Get back the ownership
+ self->d->hasOwnership = true;
+
+ if (self->d->containsCppWrapper)
+ Py_DECREF(reinterpret_cast<PyObject *>(self)); // Remove extra ref
+ else
+ makeValid(self); // Make the object valid again
+}
+
+void getOwnership(PyObject *pyObj)
+{
+ if (pyObj)
+ setSequenceOwnership(pyObj, true);
+}
+
+void releaseOwnership(SbkObject *self)
+{
+ // skip if the ownership have already moved to c++
+ auto *selfType = Py_TYPE(self);
+ if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(PepType_SOTP(selfType)->converter))
+ return;
+
+ // remove object ownership
+ self->d->hasOwnership = false;
+
+ // If We have control over object life
+ if (self->d->containsCppWrapper)
+ Py_INCREF(reinterpret_cast<PyObject *>(self)); // keep the python object alive until the wrapper destructor call
+ else
+ invalidate(self); // If I do not know when this object will die We need to invalidate this to avoid use after
+}
+
+void releaseOwnership(PyObject *self)
+{
+ setSequenceOwnership(self, false);
+}
+
+/* Needed forward declarations */
+static void recursive_invalidate(PyObject *pyobj, std::set<SbkObject *>& seen);
+static void recursive_invalidate(SbkObject *self, std::set<SbkObject *> &seen);
+
+void invalidate(PyObject *pyobj)
+{
+ std::set<SbkObject *> seen;
+ recursive_invalidate(pyobj, seen);
+}
+
+void invalidate(SbkObject *self)
+{
+ std::set<SbkObject *> seen;
+ recursive_invalidate(self, seen);
+}
+
+static void recursive_invalidate(PyObject *pyobj, std::set<SbkObject *> &seen)
+{
+ const auto objs = splitPyObject(pyobj);
+ for (SbkObject *o : objs)
+ recursive_invalidate(o, seen);
+}
+
+static void recursive_invalidate(SbkObject *self, std::set<SbkObject *> &seen)
+{
+ // Skip if this object not is a valid object or if it's already been seen
+ if (!self || reinterpret_cast<PyObject *>(self) == Py_None || seen.find(self) != seen.end())
+ return;
+ seen.insert(self);
+
+ if (!self->d->containsCppWrapper) {
+ self->d->validCppObject = false; // Mark object as invalid only if this is not a wrapper class
+ BindingManager::instance().releaseWrapper(self);
+ }
+
+ // If it is a parent invalidate all children.
+ if (self->d->parentInfo) {
+ // Create a copy because this list can be changed during the process
+ ChildrenList copy = self->d->parentInfo->children;
+
+ for (SbkObject *child : copy) {
+ // invalidate the child
+ recursive_invalidate(child, seen);
+
+ // if the parent not is a wrapper class, then remove children from him, because We do not know when this object will be destroyed
+ if (!self->d->validCppObject)
+ removeParent(child, true, true);
+ }
+ }
+
+ // If has ref to other objects invalidate all
+ if (self->d->referredObjects) {
+ RefCountMap &refCountMap = *(self->d->referredObjects);
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it)
+ recursive_invalidate(it->second, seen);
+ }
+}
+
+void makeValid(SbkObject *self)
+{
+ // Skip if this object not is a valid object
+ if (!self || reinterpret_cast<PyObject *>(self) == Py_None || self->d->validCppObject)
+ return;
+
+ // Mark object as invalid only if this is not a wrapper class
+ self->d->validCppObject = true;
+
+ // If it is a parent make all children valid
+ if (self->d->parentInfo) {
+ for (SbkObject *child : self->d->parentInfo->children)
+ makeValid(child);
+ }
+
+ // If has ref to other objects make all valid again
+ if (self->d->referredObjects) {
+ const RefCountMap &refCountMap = *(self->d->referredObjects);
+ for (const auto &p : refCountMap) {
+ if (Shiboken::Object::checkType(p.second))
+ makeValid(reinterpret_cast<SbkObject *>(p.second));
+ }
+ }
+}
+
+void *cppPointer(SbkObject *pyObj, PyTypeObject *desiredType)
+{
+ PyTypeObject *pyType = Py_TYPE(pyObj);
+ auto *sotp = PepType_SOTP(pyType);
+ int idx = 0;
+ if (sotp->is_multicpp)
+ idx = getTypeIndexOnHierarchy(pyType, desiredType);
+ if (pyObj->d->cptr)
+ return pyObj->d->cptr[idx];
+ return nullptr;
+}
+
+std::vector<void *> cppPointers(SbkObject *pyObj)
+{
+ int n = getNumberOfCppBaseClasses(Py_TYPE(pyObj));
+ std::vector<void *> ptrs(n);
+ for (int i = 0; i < n; ++i)
+ ptrs[i] = pyObj->d->cptr[i];
+ return ptrs;
+}
+
+
+bool setCppPointer(SbkObject *sbkObj, PyTypeObject *desiredType, void *cptr)
+{
+ PyTypeObject *type = Py_TYPE(sbkObj);
+ int idx = 0;
+ if (PepType_SOTP(type)->is_multicpp)
+ idx = getTypeIndexOnHierarchy(type, desiredType);
+
+ const bool alreadyInitialized = sbkObj->d->cptr[idx] != nullptr;
+ if (alreadyInitialized)
+ PyErr_Format(PyExc_RuntimeError, "You can't initialize an %s object in class %s twice!",
+ desiredType->tp_name, type->tp_name);
+ else
+ sbkObj->d->cptr[idx] = cptr;
+
+ sbkObj->d->cppObjectCreated = true;
+ return !alreadyInitialized;
+}
+
+bool isValid(PyObject *pyObj)
+{
+ if (!pyObj || pyObj == Py_None
+ || PyType_Check(pyObj) != 0
+ || Py_TYPE(Py_TYPE(pyObj)) != SbkObjectType_TypeF()) {
+ return true;
+ }
+
+ auto priv = reinterpret_cast<SbkObject *>(pyObj)->d;
+
+ if (!priv->cppObjectCreated && isUserType(pyObj)) {
+ PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.",
+ Py_TYPE(pyObj)->tp_name);
+ return false;
+ }
+
+ if (!priv->validCppObject) {
+ PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.",
+ Py_TYPE(pyObj)->tp_name);
+ return false;
+ }
+
+ return true;
+}
+
+bool isValid(SbkObject *pyObj, bool throwPyError)
+{
+ if (!pyObj)
+ return false;
+
+ SbkObjectPrivate *priv = pyObj->d;
+ if (!priv->cppObjectCreated && isUserType(reinterpret_cast<PyObject *>(pyObj))) {
+ if (throwPyError)
+ PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.",
+ Py_TYPE(pyObj)->tp_name);
+ return false;
+ }
+
+ if (!priv->validCppObject) {
+ if (throwPyError)
+ PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.",
+ (Py_TYPE(pyObj))->tp_name);
+ return false;
+ }
+
+ return true;
+}
+
+bool isValid(PyObject *pyObj, bool throwPyError)
+{
+ if (!pyObj || pyObj == Py_None ||
+ !PyType_IsSubtype(Py_TYPE(pyObj), SbkObject_TypeF())) {
+ return true;
+ }
+ return isValid(reinterpret_cast<SbkObject *>(pyObj), throwPyError);
+}
+
+SbkObject *findColocatedChild(SbkObject *wrapper,
+ const PyTypeObject *instanceType)
+{
+ // Degenerate case, wrapper is the correct wrapper.
+ if (reinterpret_cast<const void *>(Py_TYPE(wrapper)) == reinterpret_cast<const void *>(instanceType))
+ return wrapper;
+
+ if (!(wrapper->d && wrapper->d->cptr))
+ return nullptr;
+
+ ParentInfo *pInfo = wrapper->d->parentInfo;
+ if (!pInfo)
+ return nullptr;
+
+ ChildrenList &children = pInfo->children;
+
+ for (SbkObject *child : children) {
+ if (!(child->d && child->d->cptr))
+ continue;
+ if (child->d->cptr[0] == wrapper->d->cptr[0]) {
+ return reinterpret_cast<const void *>(Py_TYPE(child)) == reinterpret_cast<const void *>(instanceType)
+ ? child : findColocatedChild(child, instanceType);
+ }
+ }
+ return nullptr;
+}
+
+// Legacy, for compatibility only.
+PyObject *newObject(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership,
+ bool isExactType,
+ const char *typeName)
+{
+ 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;
+
+ // Some logic to ensure that colocated child field does not overwrite the parent
+ if (BindingManager::instance().hasWrapper(cptr)) {
+ SbkObject *existingWrapper = BindingManager::instance().retrieveWrapper(cptr);
+
+ self = findColocatedChild(existingWrapper, instanceType);
+ if (self) {
+ // Wrapper already registered for cptr.
+ // This should not ideally happen, binding code should know when a wrapper
+ // already exists and retrieve it instead.
+ shouldRegister = shouldCreate = false;
+ } else if (hasOwnership &&
+ (!(Shiboken::Object::hasCppWrapper(existingWrapper) ||
+ Shiboken::Object::hasOwnership(existingWrapper)))) {
+ // Old wrapper is likely junk, since we have ownership and it doesn't.
+ BindingManager::instance().releaseWrapper(existingWrapper);
+ } else {
+ // Old wrapper may be junk caused by some bug in identifying object deletion
+ // but it may not be junk when a colocated field is accessed for an
+ // object which was not created by python (returned from c++ factory function).
+ // Hence we cannot release the wrapper confidently so we do not register.
+ shouldRegister = false;
+ }
+ }
+
+ if (shouldCreate) {
+ self = reinterpret_cast<SbkObject *>(SbkObject_tp_new(instanceType, nullptr, nullptr));
+ self->d->cptr[0] = cptr;
+ self->d->hasOwnership = hasOwnership;
+ self->d->validCppObject = 1;
+ if (shouldRegister) {
+ BindingManager::instance().registerWrapper(self, cptr);
+ }
+ } else {
+ Py_IncRef(reinterpret_cast<PyObject *>(self));
+ }
+ return reinterpret_cast<PyObject *>(self);
+}
+
+void destroy(SbkObject *self, void *cppData)
+{
+ // Skip if this is called with NULL pointer this can happen in derived classes
+ if (!self)
+ return;
+
+ // This can be called in c++ side
+ Shiboken::GilState gil;
+
+ // Remove all references attached to this object
+ clearReferences(self);
+
+ // Remove the object from parent control
+
+ // Verify if this object has parent
+ bool hasParent = (self->d->parentInfo && self->d->parentInfo->parent);
+
+ if (self->d->parentInfo) {
+ // Check for children information and make all invalid if they exists
+ _destroyParentInfo(self, true);
+ // If this object has parent then the pyobject can be invalid now, because we remove the last ref after remove from parent
+ }
+
+ //if !hasParent this object could still alive
+ if (!hasParent && self->d->containsCppWrapper && !self->d->hasOwnership) {
+ // Remove extra ref used by c++ object this will case the pyobject destruction
+ // This can cause the object death
+ Py_DECREF(reinterpret_cast<PyObject *>(self));
+ }
+
+ //Python Object is not destroyed yet
+ if (cppData && Shiboken::BindingManager::instance().hasWrapper(cppData)) {
+ // Remove from BindingManager
+ Shiboken::BindingManager::instance().releaseWrapper(self);
+ self->d->hasOwnership = false;
+
+ // the cpp object instance was deleted
+ delete[] self->d->cptr;
+ self->d->cptr = nullptr;
+ }
+
+ // After this point the object can be death do not use the self pointer bellow
+}
+
+void removeParent(SbkObject *child, bool giveOwnershipBack, bool keepReference)
+{
+ ParentInfo *pInfo = child->d->parentInfo;
+ if (!pInfo || !pInfo->parent) {
+ if (pInfo && pInfo->hasWrapperRef) {
+ pInfo->hasWrapperRef = false;
+ }
+ return;
+ }
+
+ ChildrenList &oldBrothers = pInfo->parent->d->parentInfo->children;
+ // Verify if this child is part of parent list
+ auto iChild = oldBrothers.find(child);
+ if (iChild == oldBrothers.end())
+ return;
+
+ oldBrothers.erase(iChild);
+
+ pInfo->parent = nullptr;
+
+ // This will keep the wrapper reference, will wait for wrapper destruction to remove that
+ if (keepReference &&
+ child->d->containsCppWrapper) {
+ //If have already a extra ref remove this one
+ if (pInfo->hasWrapperRef)
+ Py_DECREF(child);
+ else
+ pInfo->hasWrapperRef = true;
+ return;
+ }
+
+ // Transfer ownership back to Python
+ child->d->hasOwnership = giveOwnershipBack;
+
+ // Remove parent ref
+ Py_DECREF(child);
+}
+
+void setParent(PyObject *parent, PyObject *child)
+{
+ if (!child || child == Py_None || child == parent)
+ return;
+
+ /*
+ * setParent is recursive when the child is a native Python sequence, i.e. objects not binded by Shiboken
+ * like tuple and list.
+ *
+ * This "limitation" exists to fix the following problem: A class multiple inherits QObject and QString,
+ * so if you pass this class to someone that takes the ownership, we CAN'T enter in this if, but hey! QString
+ * follows the sequence protocol.
+ */
+ if (PySequence_Check(child) && !Object::checkType(child)) {
+ Shiboken::AutoDecRef seq(PySequence_Fast(child, nullptr));
+ for (Py_ssize_t i = 0, max = PySequence_Size(seq); i < max; ++i)
+ setParent(parent, PySequence_Fast_GET_ITEM(seq.object(), i));
+ return;
+ }
+
+ bool parentIsNull = !parent || parent == Py_None;
+ auto parent_ = reinterpret_cast<SbkObject *>(parent);
+ auto child_ = reinterpret_cast<SbkObject *>(child);
+
+ if (!parentIsNull) {
+ if (!parent_->d->parentInfo)
+ parent_->d->parentInfo = new ParentInfo;
+
+ // do not re-add a child
+ if (child_->d->parentInfo && (child_->d->parentInfo->parent == parent_))
+ return;
+ }
+
+ ParentInfo *pInfo = child_->d->parentInfo;
+ bool hasAnotherParent = pInfo && pInfo->parent && pInfo->parent != parent_;
+
+ //Avoid destroy child during reparent operation
+ Py_INCREF(child);
+
+ // check if we need to remove this child from the old parent
+ if (parentIsNull || hasAnotherParent)
+ removeParent(child_);
+
+ // Add the child to the new parent
+ pInfo = child_->d->parentInfo;
+ if (!parentIsNull) {
+ if (!pInfo)
+ pInfo = child_->d->parentInfo = new ParentInfo;
+
+ pInfo->parent = parent_;
+ parent_->d->parentInfo->children.insert(child_);
+
+ // Add Parent ref
+ Py_INCREF(child_);
+
+ // Remove ownership
+ child_->d->hasOwnership = false;
+ }
+
+ // Remove previous safe ref
+ Py_DECREF(child);
+}
+
+void deallocData(SbkObject *self, bool cleanup)
+{
+ // Make cleanup if this is not a wrapper otherwise this will be done on wrapper destructor
+ if(cleanup) {
+ removeParent(self);
+
+ if (self->d->parentInfo)
+ _destroyParentInfo(self, true);
+
+ clearReferences(self);
+ }
+
+ if (self->d->cptr) {
+ // Remove from BindingManager
+ Shiboken::BindingManager::instance().releaseWrapper(self);
+ delete[] self->d->cptr;
+ self->d->cptr = nullptr;
+ // delete self->d; PYSIDE-205: wrong!
+ }
+ delete self->d; // PYSIDE-205: always delete d.
+ Py_XDECREF(self->ob_dict);
+ PepExt_TypeCallFree(reinterpret_cast<PyObject *>(self));
+}
+
+void setTypeUserData(SbkObject *wrapper, void *userData, DeleteUserDataFunc d_func)
+{
+ auto *type = Py_TYPE(wrapper);
+ auto *sotp = PepType_SOTP(type);
+ if (sotp->user_data)
+ sotp->d_func(sotp->user_data);
+
+ sotp->d_func = d_func;
+ sotp->user_data = userData;
+}
+
+void *getTypeUserData(SbkObject *wrapper)
+{
+ auto *type = Py_TYPE(wrapper);
+ return PepType_SOTP(type)->user_data;
+}
+
+static inline bool isNone(const PyObject *o)
+{
+ return o == nullptr || o == Py_None;
+}
+
+static void removeRefCountKey(SbkObject *self, const char *key)
+{
+ if (self->d->referredObjects) {
+ const auto iterPair = self->d->referredObjects->equal_range(key);
+ if (iterPair.first != iterPair.second) {
+ decRefPyObjectList(iterPair.first, iterPair.second);
+ self->d->referredObjects->erase(iterPair.first, iterPair.second);
+ }
+ }
+}
+
+void keepReference(SbkObject *self, const char *key, PyObject *referredObject, bool append)
+{
+ if (isNone(referredObject)) {
+ removeRefCountKey(self, key);
+ return;
+ }
+
+ if (!self->d->referredObjects) {
+ self->d->referredObjects =
+ new Shiboken::RefCountMap{RefCountMap::value_type{key, referredObject}};
+ Py_INCREF(referredObject);
+ return;
+ }
+
+ RefCountMap &refCountMap = *(self->d->referredObjects);
+ const auto iterPair = refCountMap.equal_range(key);
+ if (std::any_of(iterPair.first, iterPair.second,
+ [referredObject](const RefCountMap::value_type &v) { return v.second == referredObject; })) {
+ return;
+ }
+
+ if (!append && iterPair.first != iterPair.second) {
+ decRefPyObjectList(iterPair.first, iterPair.second);
+ refCountMap.erase(iterPair.first, iterPair.second);
+ }
+
+ refCountMap.insert(RefCountMap::value_type{key, referredObject});
+ Py_INCREF(referredObject);
+}
+
+void removeReference(SbkObject *self, const char *key, PyObject *referredObject)
+{
+ if (!isNone(referredObject))
+ removeRefCountKey(self, key);
+}
+
+void clearReferences(SbkObject *self)
+{
+ if (!self->d->referredObjects)
+ return;
+
+ RefCountMap &refCountMap = *(self->d->referredObjects);
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it)
+ Py_DECREF(it->second);
+ self->d->referredObjects->clear();
+}
+
+// Helpers for debug / info formatting
+
+static std::vector<PyTypeObject *> getBases(SbkObject *self)
+{
+ return ObjectType::isUserType(Py_TYPE(self))
+ ? getCppBaseClasses(Py_TYPE(self))
+ : std::vector<PyTypeObject *>(1, Py_TYPE(self));
+}
+
+static bool isValueType(SbkObject *self)
+{
+ return PepType_SOTP(Py_TYPE(self))->type_behaviour == BEHAVIOUR_VALUETYPE;
+}
+
+void _debugFormat(std::ostream &s, SbkObject *self)
+{
+ assert(self);
+ auto *d = self->d;
+ if (!d) {
+ s << "[Invalid]";
+ return;
+ }
+ if (d->cptr) {
+ const std::vector<PyTypeObject *> bases = getBases(self);
+ for (size_t i = 0, size = bases.size(); i < size; ++i)
+ s << ", C++: " << bases[i]->tp_name << '/' << self->d->cptr[i];
+ } else {
+ s << " [Deleted]";
+ }
+ if (d->hasOwnership)
+ s << " [hasOwnership]";
+ if (d->containsCppWrapper)
+ s << " [containsCppWrapper]";
+ if (d->validCppObject)
+ s << " [validCppObject]";
+ if (d->cppObjectCreated)
+ s << " [wasCreatedByPython]";
+ s << (isValueType(self) ? " [value]" : " [object]");
+
+ if (d->parentInfo) {
+ if (auto *parent = d->parentInfo->parent)
+ s << ", parent=" << reinterpret_cast<PyObject *>(parent)->ob_type->tp_name
+ << '/' << parent;
+ if (!d->parentInfo->children.empty())
+ s << ", " << d->parentInfo->children.size() << " child(ren)";
+ }
+ if (d->referredObjects && !d->referredObjects->empty())
+ s << ", " << d->referredObjects->size() << " referred object(s)";
+}
+
+std::string info(SbkObject *self)
+{
+ std::ostringstream s;
+
+ if (self->d && self->d->cptr) {
+ const std::vector<PyTypeObject *> bases = getBases(self);
+
+ s << "C++ address....... ";
+ for (size_t i = 0, size = bases.size(); i < size; ++i)
+ s << bases[i]->tp_name << '/' << self->d->cptr[i] << ' ';
+ s << "\n";
+ }
+ else {
+ s << "C++ address....... <<Deleted>>\n";
+ }
+
+ s << "hasOwnership...... " << bool(self->d->hasOwnership) << "\n"
+ "containsCppWrapper " << self->d->containsCppWrapper << "\n"
+ "validCppObject.... " << self->d->validCppObject << "\n"
+ "wasCreatedByPython " << self->d->cppObjectCreated << "\n"
+ "value...... " << isValueType(self) << "\n"
+ "reference count... " << reinterpret_cast<PyObject *>(self)->ob_refcnt << '\n';
+
+ if (self->d->parentInfo && self->d->parentInfo->parent) {
+ s << "parent............ ";
+ Shiboken::AutoDecRef parent(PyObject_Str(reinterpret_cast<PyObject *>(self->d->parentInfo->parent)));
+ s << String::toCString(parent) << "\n";
+ }
+
+ if (self->d->parentInfo && !self->d->parentInfo->children.empty()) {
+ s << "children.......... ";
+ for (SbkObject *sbkChild : self->d->parentInfo->children) {
+ Shiboken::AutoDecRef child(PyObject_Str(reinterpret_cast<PyObject *>(sbkChild)));
+ s << String::toCString(child) << ' ';
+ }
+ s << '\n';
+ }
+
+ if (self->d->referredObjects && !self->d->referredObjects->empty()) {
+ const Shiboken::RefCountMap &map = *self->d->referredObjects;
+ s << "referred objects.. ";
+ std::string lastKey;
+ for (const auto &p : map) {
+ if (p.first != lastKey) {
+ if (!lastKey.empty())
+ s << " ";
+ s << '"' << p.first << "\" => ";
+ lastKey = p.first;
+ }
+ Shiboken::AutoDecRef obj(PyObject_Str(p.second));
+ s << String::toCString(obj) << ' ';
+ }
+ s << '\n';
+ }
+ return s.str();
+}
+
+} // namespace Object
+
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/basewrapper.h b/sources/shiboken6/libshiboken/basewrapper.h
new file mode 100644
index 000000000..ec5545aea
--- /dev/null
+++ b/sources/shiboken6/libshiboken/basewrapper.h
@@ -0,0 +1,519 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef BASEWRAPPER_H
+#define BASEWRAPPER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+#include "sbktypefactory.h"
+
+#include <vector>
+#include <string>
+
+extern "C"
+{
+
+struct SbkConverter;
+struct SbkObjectPrivate;
+
+/// Base Python object for all the wrapped C++ classes.
+struct LIBSHIBOKEN_API SbkObject
+{
+ PyObject_HEAD
+ /// Instance dictionary.
+ PyObject *ob_dict;
+ /// List of weak references
+ PyObject *weakreflist;
+ SbkObjectPrivate *d;
+};
+
+
+/// PYSIDE-939: A general replacement for object_dealloc.
+LIBSHIBOKEN_API void Sbk_object_dealloc(PyObject *self);
+
+/// Dealloc the python object \p pyObj and the C++ object represented by it.
+LIBSHIBOKEN_API void SbkDeallocWrapper(PyObject *pyObj);
+LIBSHIBOKEN_API void SbkDeallocQAppWrapper(PyObject *pyObj);
+LIBSHIBOKEN_API void SbkDeallocWrapperWithPrivateDtor(PyObject *self);
+
+/// Function signature for the multiple inheritance information initializers that should be provided by classes with multiple inheritance.
+using MultipleInheritanceInitFunction = int *(*)(const void *);
+
+/**
+ * Special cast function is used to correctly cast an object when it's
+ * part of a multiple inheritance hierarchy.
+ * The implementation of this function is auto generated by the generator and you don't need to care about it.
+ */
+using SpecialCastFunction = void *(*)(void *, PyTypeObject *);
+using TypeDiscoveryFunc = PyTypeObject *(*)(void *, PyTypeObject *);
+using TypeDiscoveryFuncV2 = void *(*)(void *, PyTypeObject *);
+
+// Used in userdata dealloc function
+using DeleteUserDataFunc = void (*)(void *);
+
+using ObjectDestructor = void (*)(void *);
+
+using SubTypeInitHook = void (*)(PyTypeObject *, PyObject *, PyObject *);
+
+/// PYSIDE-1019: Set the function to select the current feature.
+/// Return value is the previous content.
+using SelectableFeatureHook = void (*)(PyTypeObject *);
+using SelectableFeatureCallback = void (*)(bool);
+LIBSHIBOKEN_API SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func);
+LIBSHIBOKEN_API void setSelectableFeatureCallback(SelectableFeatureCallback func);
+
+/// PYSIDE-1626: Enforcing a context switch without further action.
+LIBSHIBOKEN_API void SbkObjectType_UpdateFeature(PyTypeObject *type);
+
+/// PYSIDE-1019: Get access to PySide property strings.
+LIBSHIBOKEN_API const char **SbkObjectType_GetPropertyStrings(PyTypeObject *type);
+LIBSHIBOKEN_API void SbkObjectType_SetPropertyStrings(PyTypeObject *type, const char **strings);
+
+/// PYSIDE-1735: Store the enumFlagInfo.
+LIBSHIBOKEN_API void SbkObjectType_SetEnumFlagInfo(PyTypeObject *type, const char **strings);
+
+/// PYSIDE-1470: Set the function to kill a Q*Application.
+using DestroyQAppHook = void(*)();
+LIBSHIBOKEN_API void setDestroyQApplication(DestroyQAppHook func);
+
+/// PYSIDE-535: Use the C API in PyPy instead of `op->ob_dict`, directly (borrowed ref)
+LIBSHIBOKEN_API PyObject *SbkObject_GetDict_NoRef(PyObject *op);
+
+extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void);
+extern LIBSHIBOKEN_API PyTypeObject *SbkObject_TypeF(void);
+
+
+struct SbkObjectTypePrivate;
+/// PyTypeObject extended with C++ multiple inheritance information.
+
+LIBSHIBOKEN_API PyObject *SbkObject_tp_new(PyTypeObject *subtype, PyObject *, PyObject *);
+
+/// The special case of a switchable singleton Q*Application.
+LIBSHIBOKEN_API PyObject *SbkQApp_tp_new(PyTypeObject *subtype, PyObject *, PyObject *);
+
+/// Create a new Q*Application wrapper and monitor it.
+LIBSHIBOKEN_API PyObject *MakeQAppWrapper(PyTypeObject *type);
+
+/**
+ * PYSIDE-832: Use object_dealloc instead of nullptr.
+ *
+ * When moving to heaptypes, we were struck by a special default behavior of
+ * PyType_FromSpec that inserts subtype_dealloc when tp_dealloc is
+ * nullptr. But the default before conversion to heaptypes was to assign
+ * object_dealloc. This seems to be a bug in the Limited API.
+ */
+/// PYSIDE-939: Replaced by Sbk_object_dealloc.
+LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *);
+
+/// PYSIDE-74: Fallback used in all types now.
+LIBSHIBOKEN_API PyObject *FallbackRichCompare(PyObject *self, PyObject *other, int op);
+
+/// PYSIDE-1970: Be easily able to see what is happening in the running code.
+LIBSHIBOKEN_API void disassembleFrame(const char *marker);
+
+/// PYSIDE-2230: Check if an object is an SbkObject.
+LIBSHIBOKEN_API bool SbkObjectType_Check(PyTypeObject *type);
+
+} // extern "C"
+
+namespace Shiboken
+{
+
+/**
+* Init shiboken library.
+*/
+LIBSHIBOKEN_API void init();
+
+/// PYSIDE-1415: Publish Shiboken objects.
+LIBSHIBOKEN_API void initShibokenSupport(PyObject *module);
+
+/// Delete the class T allocated on \p cptr.
+template<typename T>
+void callCppDestructor(void *cptr)
+{
+ delete reinterpret_cast<T *>(cptr);
+}
+
+/// setErrorAboutWrongArguments now gets overload information from the signature module.
+/// The extra info argument can contain additional data about the error.
+LIBSHIBOKEN_API void setErrorAboutWrongArguments(PyObject *args, const char *funcName,
+ PyObject *info);
+
+/// Return values for the different retun variants.
+/// This is used instead of goto.
+LIBSHIBOKEN_API PyObject *returnWrongArguments(PyObject *args, const char *funcName,
+ PyObject *info);
+
+LIBSHIBOKEN_API int returnWrongArguments_Zero(PyObject *args, const char *funcName,
+ PyObject *info);
+
+LIBSHIBOKEN_API int returnWrongArguments_MinusOne(PyObject *args, const char *funcName,
+ PyObject *info);
+
+/// A simple special version for the end of rich comparison.
+LIBSHIBOKEN_API PyObject *returnFromRichCompare(PyObject *result);
+
+// Return error information object if the argument count is wrong
+LIBSHIBOKEN_API PyObject *checkInvalidArgumentCount(Py_ssize_t numArgs,
+ Py_ssize_t minArgs,
+ Py_ssize_t maxArgs);
+
+namespace ObjectType {
+
+/**
+* Returns true if the object is an instance of a type created by the Shiboken generator.
+*/
+LIBSHIBOKEN_API bool checkType(PyTypeObject *pyObj);
+
+/**
+* Returns true if this object is an instance of an user defined type derived from an Shiboken type.
+*/
+LIBSHIBOKEN_API bool isUserType(PyTypeObject *pyObj);
+
+/**
+* Returns true if the constructor of \p ctorType can be called for a instance of type \p myType.
+* \note This function set a python error when returning false.
+*/
+LIBSHIBOKEN_API bool canCallConstructor(PyTypeObject *myType, PyTypeObject *ctorType);
+
+/**
+ * Tells if the \p type represents an object of a class with multiple inheritance in C++.
+ * When this occurs, the C++ pointer held by the Python wrapper will need to be cast when
+ * passed as a parameter that expects a type of its ancestry.
+ * \returns true if a call to ObjectType::cast() is needed to obtain the correct
+ * C++ pointer for Python objects of type \p type.
+ */
+LIBSHIBOKEN_API bool hasCast(PyTypeObject *type);
+/**
+ * Cast the C++ pointer held by a Python object \p obj of type \p sourceType,
+ * to a C++ pointer of a C++ class indicated by type \p targetType.
+ * \returns The cast C++ pointer.
+ */
+LIBSHIBOKEN_API void *cast(PyTypeObject *sourceType, SbkObject *obj, PyTypeObject *targetType);
+/// Set the C++ cast function for \p type.
+LIBSHIBOKEN_API void setCastFunction(PyTypeObject *type, SpecialCastFunction func);
+
+LIBSHIBOKEN_API void setOriginalName(PyTypeObject *self, const char *name);
+LIBSHIBOKEN_API const char *getOriginalName(PyTypeObject *self);
+
+LIBSHIBOKEN_API void setTypeDiscoveryFunctionV2(PyTypeObject *self, TypeDiscoveryFuncV2 func);
+LIBSHIBOKEN_API void copyMultipleInheritance(PyTypeObject *self, PyTypeObject *other);
+LIBSHIBOKEN_API void setMultipleInheritanceFunction(PyTypeObject *self, MultipleInheritanceInitFunction func);
+LIBSHIBOKEN_API MultipleInheritanceInitFunction getMultipleInheritanceFunction(PyTypeObject *type);
+
+LIBSHIBOKEN_API void setDestructorFunction(PyTypeObject *self, ObjectDestructor func);
+
+enum WrapperFlags
+{
+ InnerClass = 0x1,
+ DeleteInMainThread = 0x2,
+ Value = 0x4
+};
+
+/**
+ * Initializes a Shiboken wrapper type and adds it to the module,
+ * or to the enclosing class if the type is an inner class.
+ * This function also calls setDestructorFunction.
+ * \param enclosingObject The module or enclosing class to where the new \p type will be added.
+ * \param typeName Name by which the type will be known in Python.
+ * \param originalName Original C++ name of the type.
+ * \param type The new type to be initialized and added to the module.
+ * \param cppObjDtor Memory deallocation function for the C++ object held by \p type.
+ * Should not be used if the underlying C++ class has a private destructor.
+ * \param baseType Base type from whom the new \p type inherits.
+ * \param baseTypes Other base types from whom the new \p type inherits.
+ * \param isInnerClass Tells if the new \p type is an inner class (the default is that it isn't).
+ * If false then the \p enclosingObject is a module, otherwise it is another
+ * wrapper type.
+ * \returns true if the initialization went fine, false otherwise.
+ */
+LIBSHIBOKEN_API PyTypeObject *introduceWrapperType(PyObject *enclosingObject,
+ const char *typeName,
+ const char *originalName,
+ PyType_Spec *typeSpec,
+ ObjectDestructor cppObjDtor,
+ PyObject *bases,
+ unsigned wrapperFlags = 0);
+
+/**
+ * Set the subtype init hook for a type.
+ *
+ * This hook will be invoked every time the user creates a sub-type inherited from a Shiboken based type.
+ * The hook gets 3 params, they are: The new type being created, args and kwds. The last two are the very
+ * same got from tp_new.
+ */
+LIBSHIBOKEN_API void setSubTypeInitHook(PyTypeObject *self, SubTypeInitHook func);
+
+/**
+ * Get the user data previously set by Shiboken::Object::setTypeUserData
+ */
+LIBSHIBOKEN_API void *getTypeUserData(PyTypeObject *self);
+LIBSHIBOKEN_API void setTypeUserData(PyTypeObject *self, void *userData, DeleteUserDataFunc d_func);
+
+/**
+ * Return an instance of PyTypeObject for a C++ type name as determined by
+ * typeinfo().name().
+ * \param typeName Type name
+ * \since 5.12
+ */
+LIBSHIBOKEN_API PyTypeObject *typeForTypeName(const char *typeName);
+
+/**
+ * Returns whether PyTypeObject has a special cast function (multiple inheritance)
+ * \param sbkType Sbk type
+ * \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 {
+
+/**
+ * Returns a string with information about the internal state of the instance object, useful for debug purposes.
+ */
+LIBSHIBOKEN_API std::string info(SbkObject *self);
+
+/**
+* Returns true if the object is an instance of a type created by the Shiboken generator.
+*/
+LIBSHIBOKEN_API bool checkType(PyObject *pyObj);
+
+/**
+ * Returns true if this object type is an instance of an user defined type derived from an Shiboken type.
+ * \see Shiboken::ObjectType::isUserType
+ */
+LIBSHIBOKEN_API bool isUserType(PyObject *pyObj);
+
+/**
+ * Generic function used to make ObjectType hashable, the C++ pointer is used as hash value.
+ */
+LIBSHIBOKEN_API Py_hash_t hash(PyObject *pyObj);
+
+/**
+ * Find a child of given wrapper having same address having the specified type.
+ */
+LIBSHIBOKEN_API SbkObject *findColocatedChild(SbkObject *wrapper,
+ const PyTypeObject *instanceType);
+
+/**
+ * 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++
+ * object, in any case you must provide \p instanceType, it'll be used as search starting point
+ * and as fallback.
+ * \param typeName If non-null, this will be used as helper to find the correct Python type for this object.
+ */
+LIBSHIBOKEN_API PyObject *newObject(PyTypeObject *instanceType,
+ void *cptr,
+ bool hasOwnership = true,
+ 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.
+ */
+LIBSHIBOKEN_API void setValidCpp(SbkObject *pyObj, bool value);
+/**
+ * Tells shiboken the Python object \p pyObj has a C++ wrapper used to intercept virtual method calls.
+ */
+LIBSHIBOKEN_API void setHasCppWrapper(SbkObject *pyObj, bool value);
+/**
+ * Return true if the Python object \p pyObj has a C++ wrapper used to intercept virtual method calls.
+ */
+LIBSHIBOKEN_API bool hasCppWrapper(SbkObject *pyObj);
+
+/**
+ * Return true if the Python object was created by Python, false otherwise.
+ * \note This function was added to libshiboken only to be used by shiboken.wasCreatedByPython()
+ */
+LIBSHIBOKEN_API bool wasCreatedByPython(SbkObject *pyObj);
+
+/**
+ * Call the C++ object destructor and invalidates the Python object.
+ * \note This function was added to libshiboken only to be used by shiboken.delete()
+ */
+LIBSHIBOKEN_API void callCppDestructors(SbkObject *pyObj);
+
+/**
+ * Return true if the Python is responsible for deleting the underlying C++ object.
+ */
+LIBSHIBOKEN_API bool hasOwnership(SbkObject *pyObj);
+
+/**
+ * Sets python as responsible to delete the underlying C++ object.
+ * \note You this overload only when the PyObject can be a sequence and you want to
+ * call this function for every item in the sequence.
+ * \see getOwnership(SbkObject *)
+ */
+LIBSHIBOKEN_API void getOwnership(PyObject *pyObj);
+
+/**
+ * Sets python as responsible to delete the underlying C++ object.
+ */
+LIBSHIBOKEN_API void getOwnership(SbkObject *pyObj);
+
+/**
+ * Release the ownership, so Python will not delete the underlying C++ object.
+ * \note You this overload only when the PyObject can be a sequence and you want to
+ * call this function for every item in the sequence.
+ * \see releaseOwnership(SbkObject *)
+ */
+LIBSHIBOKEN_API void releaseOwnership(PyObject *pyObj);
+/**
+ * Release the ownership, so Python will not delete the underlying C++ object.
+ */
+LIBSHIBOKEN_API void releaseOwnership(SbkObject *pyObj);
+
+/**
+ * Get the C++ pointer of type \p desiredType from a Python object.
+ */
+LIBSHIBOKEN_API void *cppPointer(SbkObject *pyObj, PyTypeObject *desiredType);
+
+/**
+ * Return a list with all C++ pointers held from a Python object.
+ * \note This function was added to libshiboken only to be used by shiboken.getCppPointer()
+ */
+LIBSHIBOKEN_API std::vector<void *>cppPointers(SbkObject *pyObj);
+
+/**
+ * Set the C++ pointer of type \p desiredType of a Python object.
+ */
+LIBSHIBOKEN_API bool setCppPointer(SbkObject *sbkObj, PyTypeObject *desiredType, void *cptr);
+
+/**
+ * Returns false and sets a Python RuntimeError if the Python wrapper is not marked as valid.
+ */
+LIBSHIBOKEN_API bool isValid(PyObject *pyObj);
+
+/**
+ * Returns false if the Python wrapper is not marked as valid.
+ * \param pyObj the object.
+ * \param throwPyError sets a Python RuntimeError when the object isn't valid.
+ */
+LIBSHIBOKEN_API bool isValid(SbkObject *pyObj, bool throwPyError = true);
+
+/**
+ * Returns false if the Python wrapper is not marked as valid.
+ * \param pyObj the object.
+ * \param throwPyError sets a Python RuntimeError when the object isn't valid.
+ */
+LIBSHIBOKEN_API bool isValid(PyObject *pyObj, bool throwPyError);
+
+/**
+* Set the parent of \p child to \p parent.
+* When an object dies, all their children, grandchildren, etc, are tagged as invalid.
+* \param parent the parent object, if null, the child will have no parents.
+* \param child the child.
+*/
+LIBSHIBOKEN_API void setParent(PyObject *parent, PyObject *child);
+
+/**
+* Remove this child from their parent, if any.
+* \param child the child.
+*/
+LIBSHIBOKEN_API void removeParent(SbkObject *child, bool giveOwnershipBack = true, bool keepReferenc = false);
+
+/**
+ * Mark the object as invalid
+ */
+LIBSHIBOKEN_API void invalidate(SbkObject *self);
+
+/**
+ * Help function can be used to invalidate a sequence of object
+ **/
+LIBSHIBOKEN_API void invalidate(PyObject *pyobj);
+
+/**
+ * Make the object valid again
+ */
+LIBSHIBOKEN_API void makeValid(SbkObject *self);
+
+/**
+ * Destroy any data in Shiboken structure and c++ pointer if the pyboject has the ownership
+ */
+LIBSHIBOKEN_API void destroy(SbkObject *self, void *cppData);
+
+/**
+ * Set user data on type of \p wrapper.
+ * \param wrapper instance object, the user data will be set on his type
+ * \param userData the user data
+ * \param d_func a function used to delete the user data
+ */
+LIBSHIBOKEN_API void setTypeUserData(SbkObject *wrapper, void *userData, DeleteUserDataFunc d_func);
+/**
+ * Get the user data previously set by Shiboken::Object::setTypeUserData
+ */
+LIBSHIBOKEN_API void *getTypeUserData(SbkObject *wrapper);
+
+/**
+ * Increments the reference count of the referred Python object.
+ * A previous Python object in the same position identified by the 'key' parameter
+ * will have its reference counter decremented automatically when replaced.
+ * All the kept references should be decremented when the Python wrapper indicated by
+ * 'self' dies.
+ * No checking is done for any of the passed arguments, since it is meant to be used
+ * by generated code it is supposed that the generator is correct.
+ * \param self the wrapper instance that keeps references to other objects.
+ * \param key a key that identifies the C++ method signature and argument where the referred Object came from.
+ * \param referredObject the object whose reference is used by the self object.
+ */
+LIBSHIBOKEN_API void keepReference(SbkObject *self, const char *key, PyObject *referredObject, bool append = false);
+
+/**
+ * Removes any reference previously added by keepReference function
+ * \param self the wrapper instance that keeps references to other objects.
+ * \param key a key that identifies the C++ method signature and argument from where the referred Object came.
+ * \param referredObject the object whose reference is used by the self object.
+ */
+LIBSHIBOKEN_API void removeReference(SbkObject *self, const char *key, PyObject *referredObject);
+
+} // namespace Object
+
+} // namespace Shiboken
+
+#endif // BASEWRAPPER_H
diff --git a/sources/shiboken6/libshiboken/basewrapper_p.h b/sources/shiboken6/libshiboken/basewrapper_p.h
new file mode 100644
index 000000000..fb9140793
--- /dev/null
+++ b/sources/shiboken6/libshiboken/basewrapper_p.h
@@ -0,0 +1,167 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef BASEWRAPPER_P_H
+#define BASEWRAPPER_P_H
+
+#include "sbkpython.h"
+#include "basewrapper.h"
+
+#include <unordered_map>
+#include <set>
+#include <string>
+#include <vector>
+#include <iosfwd>
+
+struct SbkObject;
+struct SbkConverter;
+
+namespace Shiboken
+{
+/**
+ * This mapping associates a method and argument of an wrapper object with the wrapper of
+ * said argument when it needs the binding to help manage its reference count.
+ */
+using RefCountMap = std::unordered_multimap<std::string, PyObject *> ;
+
+/// Linked list of SbkBaseWrapper pointers
+using ChildrenList = std::set<SbkObject *>;
+
+/// Structure used to store information about object parent and children.
+struct ParentInfo
+{
+ /// Pointer to parent object.
+ SbkObject *parent = nullptr;
+ /// List of object children.
+ ChildrenList children;
+ /// has internal ref
+ bool hasWrapperRef = false;
+};
+
+} // namespace Shiboken
+
+extern "C"
+{
+
+/**
+ * \internal
+ * Private data for SbkBaseWrapper
+ */
+struct SbkObjectPrivate
+{
+ SbkObjectPrivate() noexcept = default;
+ SbkObjectPrivate(const SbkObjectPrivate &) = delete;
+ SbkObjectPrivate(SbkObjectPrivate &&o) = delete;
+ SbkObjectPrivate &operator=(const SbkObjectPrivate &) = delete;
+ SbkObjectPrivate &operator=(SbkObjectPrivate &&o) = delete;
+
+ /// Pointer to the C++ class.
+ void ** cptr;
+ /// True when Python is responsible for freeing the used memory.
+ unsigned int hasOwnership : 1;
+ /// This is true when the C++ class of the wrapped object has a virtual destructor AND was created by Python.
+ unsigned int containsCppWrapper : 1;
+ /// Marked as false when the object is lost to C++ and the binding can not know if it was deleted or not.
+ unsigned int validCppObject : 1;
+ /// Marked as true when the object constructor was called
+ unsigned int cppObjectCreated : 1;
+ /// PYSIDE-1470: Marked as true if this is the Q*Application singleton.
+ /// This bit allows app deletion from shiboken?.delete() .
+ unsigned int isQAppSingleton : 1;
+ /// Information about the object parents and children, may be null.
+ Shiboken::ParentInfo *parentInfo;
+ /// Manage reference count of objects that are referred to but not owned from.
+ Shiboken::RefCountMap *referredObjects;
+
+ ~SbkObjectPrivate()
+ {
+ delete parentInfo;
+ parentInfo = nullptr;
+ delete referredObjects;
+ referredObjects = nullptr;
+ }
+};
+
+// TODO-CONVERTERS: to be deprecated/removed
+/// The type behaviour was not defined yet
+#define BEHAVIOUR_UNDEFINED 0
+/// The type is a value type
+#define BEHAVIOUR_VALUETYPE 1
+/// The type is an object type
+#define BEHAVIOUR_OBJECTTYPE 2
+
+struct SbkObjectTypePrivate
+{
+ SbkConverter *converter;
+ int *mi_offsets;
+ MultipleInheritanceInitFunction mi_init;
+
+ /// Special cast function, null if this class doesn't have multiple inheritance.
+ SpecialCastFunction mi_specialcast;
+ TypeDiscoveryFuncV2 type_discovery;
+ /// Pointer to a function responsible for deletion of the C++ instance calling the proper destructor.
+ ObjectDestructor cpp_dtor;
+ /// C++ name
+ char *original_name;
+ /// Type user data
+ void *user_data;
+ DeleteUserDataFunc d_func;
+ void (*subtype_init)(PyTypeObject *, PyObject *, PyObject *);
+ const char **propertyStrings;
+ const char **enumFlagInfo;
+ PyObject *enumFlagsDict;
+ PyObject *enumTypeDict;
+
+ /// True if this type holds two or more C++ instances, e.g.: a Python class which inherits from two C++ classes.
+ unsigned int is_multicpp : 1;
+ /// True if this type was defined by the user (a class written in Python inheriting
+ /// a class provided by a Shiboken binding).
+ unsigned int is_user_type : 1;
+ /// Tells is the type is a value type or an object-type, see BEHAVIOUR_ *constants.
+ unsigned int type_behaviour : 2;
+ unsigned int delete_in_main_thread : 1;
+};
+
+
+} // extern "C"
+
+namespace Shiboken
+{
+
+/**
+ * \internal
+ * Data required to invoke a C++ destructor
+ */
+struct DestructorEntry
+{
+ ObjectDestructor destructor;
+ void *cppInstance;
+};
+
+/**
+ * Utility function used to transform a PyObject that implements sequence protocol into a std::list.
+ **/
+std::vector<SbkObject *> splitPyObject(PyObject *pyObj);
+
+int getNumberOfCppBaseClasses(PyTypeObject *baseType);
+
+namespace Object
+{
+/**
+* Decrements the reference counters of every object referred by self.
+* \param self the wrapper instance that keeps references to other objects.
+*/
+void clearReferences(SbkObject *self);
+
+/**
+ * Destroy internal data
+ **/
+void deallocData(SbkObject *self, bool doCleanup);
+
+
+void _debugFormat(std::ostream &str, SbkObject *self);
+} // namespace Object
+
+} // namespace Shiboken
+
+#endif
diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp
new file mode 100644
index 000000000..83c927ae5
--- /dev/null
+++ b/sources/shiboken6/libshiboken/bindingmanager.cpp
@@ -0,0 +1,549 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "autodecref.h"
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+#include "bindingmanager.h"
+#include "gilstate.h"
+#include "helper.h"
+#include "sbkmodule.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkfeature_base.h"
+#include "debugfreehook.h"
+
+#include <cstddef>
+#include <cstring>
+#include <fstream>
+#include <iostream>
+#include <mutex>
+#include <string_view>
+#include <unordered_map>
+#include <unordered_set>
+
+// GraphNode for the dependency graph. It keeps a pointer to
+// the TypeInitStruct to be able to lazily create the type and hashes
+// by the full type name.
+struct GraphNode
+{
+ explicit GraphNode(Shiboken::Module::TypeInitStruct *i) : name(i->fullName), initStruct(i) {}
+ explicit GraphNode(const char *n) : name(n), initStruct(nullptr) {} // Only for searching
+
+ std::string_view name;
+ Shiboken::Module::TypeInitStruct *initStruct;
+
+ friend bool operator==(const GraphNode &n1, const GraphNode &n2) { return n1.name == n2.name; }
+ friend bool operator!=(const GraphNode &n1, const GraphNode &n2) { return n1.name != n2.name; }
+};
+
+template <>
+struct std::hash<GraphNode> {
+ size_t operator()(const GraphNode &n) const noexcept
+ {
+ return std::hash<std::string_view>{}(n.name);
+ }
+};
+
+namespace Shiboken
+{
+
+using WrapperMap = std::unordered_map<const void *, SbkObject *>;
+
+template <class NodeType>
+class BaseGraph
+{
+public:
+ using NodeList = std::vector<NodeType>;
+ using NodeSet = std::unordered_set<NodeType>;
+
+ using Edges = std::unordered_map<NodeType, NodeList>;
+
+ Edges m_edges;
+
+ BaseGraph() = default;
+
+ void addEdge(NodeType from, NodeType to)
+ {
+ m_edges[from].push_back(to);
+ }
+
+ NodeSet nodeSet() const
+ {
+ NodeSet result;
+ for (const auto &p : m_edges) {
+ result.insert(p.first);
+ for (const auto node2 : p.second)
+ result.insert(node2);
+ }
+ return result;
+ }
+};
+
+class Graph : public BaseGraph<GraphNode>
+{
+public:
+ using TypeCptrPair = BindingManager::TypeCptrPair;
+
+ TypeCptrPair identifyType(void *cptr, PyTypeObject *type, PyTypeObject *baseType) const
+ {
+ return identifyType(cptr, GraphNode(type->tp_name), type, baseType);
+ }
+
+ bool dumpTypeGraph(const char *fileName) const;
+
+private:
+ TypeCptrPair identifyType(void *cptr, const GraphNode &typeNode, PyTypeObject *type,
+ PyTypeObject *baseType) const;
+};
+
+Graph::TypeCptrPair Graph::identifyType(void *cptr,
+ const GraphNode &typeNode, PyTypeObject *type,
+ PyTypeObject *baseType) const
+{
+ assert(typeNode.initStruct != nullptr || type != nullptr);
+ auto edgesIt = m_edges.find(typeNode);
+ if (edgesIt != m_edges.end()) {
+ const NodeList &adjNodes = edgesIt->second;
+ for (const auto &node : adjNodes) {
+ auto newType = identifyType(cptr, node, nullptr, baseType);
+ if (newType.first != nullptr)
+ return newType;
+ }
+ }
+
+ if (type == nullptr) {
+ if (typeNode.initStruct->type == nullptr) // Layzily create type
+ type = Shiboken::Module::get(*typeNode.initStruct);
+ else
+ type = typeNode.initStruct->type;
+ }
+
+ auto *sotp = PepType_SOTP(type);
+ if (sotp->type_discovery != nullptr) {
+ if (void *derivedCPtr = sotp->type_discovery(cptr, baseType))
+ return {type, derivedCPtr};
+ }
+ return {nullptr, nullptr};
+}
+
+static void formatDotNode(std::string_view name, std::ostream &file)
+{
+ auto lastDot = name.rfind('.');
+ file << " \"" << name << "\" [ label=";
+ if (lastDot != std::string::npos) {
+ file << '"' << name.substr(lastDot + 1) << "\" tooltip=\""
+ << name.substr(0, lastDot) << '"';
+ } else {
+ file << '"' << name << '"';
+ }
+ file << " ]\n";
+}
+
+bool Graph::dumpTypeGraph(const char *fileName) const
+{
+ std::ofstream file(fileName);
+ if (!file.good())
+ return false;
+
+ file << "digraph D {\n";
+
+ // Define nodes with short names
+ for (const auto &node : nodeSet())
+ formatDotNode(node.name, file);
+
+ // Write edges
+ for (const auto &p : m_edges) {
+ const auto &node1 = p.first;
+ const NodeList &nodeList = p.second;
+ for (const auto &node2 : nodeList)
+ file << " \"" << node2.name << "\" -> \"" << node1.name << "\"\n";
+ }
+ file << "}\n";
+ return true;
+}
+
+struct BindingManager::BindingManagerPrivate {
+ using DestructorEntries = std::vector<DestructorEntry>;
+
+ WrapperMap wrapperMapper;
+ // Guard wrapperMapper mainly for QML which calls into the generated
+ // QObject::metaObject() and elsewhere from threads without GIL, causing
+ // crashes for example in retrieveWrapper(). std::shared_mutex was rejected due to:
+ // https://stackoverflow.com/questions/50972345/when-is-stdshared-timed-mutex-slower-than-stdmutex-and-when-not-to-use-it
+ std::recursive_mutex wrapperMapLock;
+ Graph classHierarchy;
+ DestructorEntries deleteInMainThread;
+
+ bool releaseWrapper(void *cptr, SbkObject *wrapper, const int *bases = nullptr);
+ bool releaseWrapperHelper(void *cptr, SbkObject *wrapper);
+
+ void assignWrapper(SbkObject *wrapper, const void *cptr, const int *bases = nullptr);
+ void assignWrapperHelper(SbkObject *wrapper, const void *cptr);
+};
+
+inline bool BindingManager::BindingManagerPrivate::releaseWrapperHelper(void *cptr, SbkObject *wrapper)
+{
+ // The wrapper argument is checked to ensure that the correct wrapper is released.
+ // Returns true if the correct wrapper is found and released.
+ // If wrapper argument is NULL, no such check is performed.
+ auto iter = wrapperMapper.find(cptr);
+ if (iter != wrapperMapper.end() && (wrapper == nullptr || iter->second == wrapper)) {
+ wrapperMapper.erase(iter);
+ return true;
+ }
+ return false;
+}
+
+bool BindingManager::BindingManagerPrivate::releaseWrapper(void *cptr, SbkObject *wrapper,
+ const int *bases)
+{
+ assert(cptr);
+ std::lock_guard<std::recursive_mutex> guard(wrapperMapLock);
+ const bool result = releaseWrapperHelper(cptr, wrapper);
+ if (bases != nullptr) {
+ auto *base = static_cast<uint8_t *>(cptr);
+ for (const auto *offset = bases; *offset != -1; ++offset)
+ releaseWrapperHelper(base + *offset, wrapper);
+ }
+ return result;
+}
+
+inline void BindingManager::BindingManagerPrivate::assignWrapperHelper(SbkObject *wrapper,
+ const void *cptr)
+{
+ auto iter = wrapperMapper.find(cptr);
+ if (iter == wrapperMapper.end())
+ wrapperMapper.insert(std::make_pair(cptr, wrapper));
+}
+
+void BindingManager::BindingManagerPrivate::assignWrapper(SbkObject *wrapper, const void *cptr,
+ const int *bases)
+{
+ assert(cptr);
+ std::lock_guard<std::recursive_mutex> guard(wrapperMapLock);
+ assignWrapperHelper(wrapper, cptr);
+ if (bases != nullptr) {
+ const auto *base = static_cast<const uint8_t *>(cptr);
+ for (const auto *offset = bases; *offset != -1; ++offset)
+ assignWrapperHelper(wrapper, base + *offset);
+ }
+}
+
+BindingManager::BindingManager()
+{
+ m_d = new BindingManager::BindingManagerPrivate;
+
+#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+ debugInstallFreeHook();
+#endif
+}
+
+BindingManager::~BindingManager()
+{
+#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+ debugRemoveFreeHook();
+#endif
+#ifndef NDEBUG
+ if (Shiboken::pyVerbose() > 0)
+ dumpWrapperMap();
+#endif
+ /* Cleanup hanging references. We just invalidate them as when
+ * the BindingManager is being destroyed the interpreter is alredy
+ * shutting down. */
+ if (Py_IsInitialized()) { // ensure the interpreter is still valid
+ std::lock_guard<std::recursive_mutex> guard(m_d->wrapperMapLock);
+ while (!m_d->wrapperMapper.empty()) {
+ Object::destroy(m_d->wrapperMapper.begin()->second, const_cast<void *>(m_d->wrapperMapper.begin()->first));
+ }
+ assert(m_d->wrapperMapper.empty());
+ }
+ delete m_d;
+}
+
+BindingManager &BindingManager::instance() {
+ static BindingManager singleton;
+ return singleton;
+}
+
+bool BindingManager::hasWrapper(const void *cptr)
+{
+ std::lock_guard<std::recursive_mutex> guard(m_d->wrapperMapLock);
+ return m_d->wrapperMapper.find(cptr) != m_d->wrapperMapper.end();
+}
+
+void BindingManager::registerWrapper(SbkObject *pyObj, void *cptr)
+{
+ auto *instanceType = Py_TYPE(pyObj);
+ auto *d = PepType_SOTP(instanceType);
+
+ if (!d)
+ return;
+
+ if (d->mi_init && !d->mi_offsets)
+ d->mi_offsets = d->mi_init(cptr);
+ m_d->assignWrapper(pyObj, cptr, d->mi_offsets);
+}
+
+void BindingManager::releaseWrapper(SbkObject *sbkObj)
+{
+ auto *sbkType = Py_TYPE(sbkObj);
+ auto *d = PepType_SOTP(sbkType);
+ int numBases = ((d && d->is_multicpp) ? getNumberOfCppBaseClasses(Py_TYPE(sbkObj)) : 1);
+
+ void ** cptrs = reinterpret_cast<SbkObject *>(sbkObj)->d->cptr;
+ const int *mi_offsets = d != nullptr ? d->mi_offsets : nullptr;
+ for (int i = 0; i < numBases; ++i) {
+ if (cptrs[i] != nullptr)
+ m_d->releaseWrapper(cptrs[i], sbkObj, mi_offsets);
+ }
+ sbkObj->d->validCppObject = false;
+}
+
+void BindingManager::runDeletionInMainThread()
+{
+ for (const DestructorEntry &e : m_d->deleteInMainThread)
+ e.destructor(e.cppInstance);
+ m_d->deleteInMainThread.clear();
+}
+
+void BindingManager::addToDeletionInMainThread(const DestructorEntry &e)
+{
+ m_d->deleteInMainThread.push_back(e);
+}
+
+SbkObject *BindingManager::retrieveWrapper(const void *cptr)
+{
+ std::lock_guard<std::recursive_mutex> guard(m_d->wrapperMapLock);
+ auto iter = m_d->wrapperMapper.find(cptr);
+ if (iter == m_d->wrapperMapper.end())
+ return nullptr;
+ return iter->second;
+}
+
+PyObject *BindingManager::getOverride(const void *cptr,
+ PyObject *nameCache[],
+ const char *methodName)
+{
+ SbkObject *wrapper = retrieveWrapper(cptr);
+ // The refcount can be 0 if the object is dieing and someone called
+ // a virtual method from the destructor
+ if (!wrapper || Py_REFCNT(reinterpret_cast<const PyObject *>(wrapper)) == 0)
+ return nullptr;
+
+ // PYSIDE-1626: Touch the type to initiate switching early.
+ SbkObjectType_UpdateFeature(Py_TYPE(wrapper));
+
+ int flag = currentSelectId(Py_TYPE(wrapper));
+ int propFlag = isdigit(methodName[0]) ? methodName[0] - '0' : 0;
+ bool is_snake = flag & 0x01;
+ PyObject *pyMethodName = nameCache[is_snake]; // borrowed
+ if (pyMethodName == nullptr) {
+ if (propFlag)
+ methodName += 2; // skip the propFlag and ':'
+ pyMethodName = Shiboken::String::getSnakeCaseName(methodName, is_snake);
+ nameCache[is_snake] = pyMethodName;
+ }
+
+ auto *obWrapper = reinterpret_cast<PyObject *>(wrapper);
+ auto *wrapper_dict = SbkObject_GetDict_NoRef(obWrapper);
+ if (PyObject *method = PyDict_GetItem(wrapper_dict, pyMethodName)) {
+ // Note: This special case was implemented for duck-punching, which happens
+ // in the instance dict. It does not work with properties.
+ Py_INCREF(method);
+ return method;
+ }
+
+ PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), pyMethodName);
+
+ PyObject *function = nullptr;
+
+ // PYSIDE-1523: PyMethod_Check is not accepting compiled methods, we do this rather
+ // crude check for them.
+ if (method) {
+ // PYSIDE-535: This macro is redefined in a compatible way in pep384
+ if (PyMethod_Check(method)) {
+ if (PyMethod_GET_SELF(method) == reinterpret_cast<PyObject *>(wrapper)) {
+ function = PyMethod_GET_FUNCTION(method);
+ } else {
+ Py_DECREF(method);
+ method = nullptr;
+ }
+ } else if (PyObject_HasAttr(method, PyName::im_self())
+ && PyObject_HasAttr(method, PyName::im_func())
+ && PyObject_HasAttr(method, Shiboken::PyMagicName::code())) {
+ PyObject *im_self = PyObject_GetAttr(method, PyName::im_self());
+ // Not retaining a reference inline with what PyMethod_GET_SELF does.
+ Py_DECREF(im_self);
+
+ if (im_self == reinterpret_cast<PyObject *>(wrapper)) {
+ function = PyObject_GetAttr(method, PyName::im_func());
+ // Not retaining a reference inline with what PyMethod_GET_FUNCTION does.
+ Py_DECREF(function);
+ } else {
+ Py_DECREF(method);
+ method = nullptr;
+ }
+ } else {
+ Py_DECREF(method);
+ method = nullptr;
+ }
+ }
+
+ if (method != nullptr) {
+ PyObject *defaultMethod{};
+ PyObject *mro = Py_TYPE(wrapper)->tp_mro;
+
+ int size = PyTuple_GET_SIZE(mro);
+ bool defaultFound = false;
+ // The first class in the mro (index 0) is the class being checked and it should not be tested.
+ // The last class in the mro (size - 1) is the base Python object class which should not be tested also.
+ for (int idx = 1; idx < size - 1; ++idx) {
+ auto *parent = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ AutoDecRef tpDict(PepType_GetDict(parent));
+ auto *parentDict = tpDict.object();
+ if (parentDict) {
+ defaultMethod = PyDict_GetItem(parentDict, pyMethodName);
+ if (defaultMethod) {
+ defaultFound = true;
+ if (function != defaultMethod)
+ return method;
+ }
+ }
+ }
+ // PYSIDE-2255: If no default method was found, use the method.
+ if (!defaultFound)
+ return method;
+ Py_DECREF(method);
+ }
+
+ return nullptr;
+}
+
+void BindingManager::addClassInheritance(Module::TypeInitStruct *parent,
+ Module::TypeInitStruct *child)
+{
+ m_d->classHierarchy.addEdge(GraphNode(parent), GraphNode(child));
+}
+
+BindingManager::TypeCptrPair BindingManager::findDerivedType(void *cptr, PyTypeObject *type) const
+{
+ return m_d->classHierarchy.identifyType(cptr, type, type);
+}
+
+// FIXME PYSIDE7: remove, just for compatibility
+PyTypeObject *BindingManager::resolveType(void **cptr, PyTypeObject *type)
+{
+ auto result = findDerivedType(*cptr, type);
+ if (result.second != nullptr)
+ *cptr = result.second;
+ return result.first != nullptr ? result.first : type;
+}
+
+std::set<PyObject *> BindingManager::getAllPyObjects()
+{
+ std::set<PyObject *> pyObjects;
+ std::lock_guard<std::recursive_mutex> guard(m_d->wrapperMapLock);
+ const WrapperMap &wrappersMap = m_d->wrapperMapper;
+ auto it = wrappersMap.begin();
+ for (; it != wrappersMap.end(); ++it)
+ pyObjects.insert(reinterpret_cast<PyObject *>(it->second));
+
+ return pyObjects;
+}
+
+void BindingManager::visitAllPyObjects(ObjectVisitor visitor, void *data)
+{
+ WrapperMap copy = m_d->wrapperMapper;
+ for (const auto &p : copy) {
+ if (hasWrapper(p.first))
+ visitor(p.second, data);
+ }
+}
+
+bool BindingManager::dumpTypeGraph(const char *fileName) const
+{
+ return m_d->classHierarchy.dumpTypeGraph(fileName);
+}
+
+void BindingManager::dumpWrapperMap()
+{
+ const auto &wrapperMap = m_d->wrapperMapper;
+ std::cerr << "-------------------------------\n"
+ << "WrapperMap size: " << wrapperMap.size() << " Types: "
+ << m_d->classHierarchy.nodeSet().size() << '\n';
+ for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) {
+ const SbkObject *sbkObj = it->second;
+ std::cerr << "key: " << it->first << ", value: "
+ << static_cast<const void *>(sbkObj) << " ("
+ << (Py_TYPE(sbkObj))->tp_name << ", refcnt: "
+ << Py_REFCNT(reinterpret_cast<const PyObject *>(sbkObj)) << ")\n";
+ }
+ std::cerr << "-------------------------------\n";
+}
+
+static bool isPythonType(PyTypeObject *type)
+{
+ // This is a type which should be called by multiple inheritance.
+ // It is either a pure Python type or a derived PySide type.
+ return !ObjectType::checkType(type) || ObjectType::isUserType(type);
+}
+
+bool callInheritedInit(PyObject *self, PyObject *args, PyObject *kwds,
+ const char *fullName)
+{
+ using Shiboken::AutoDecRef;
+
+ static PyObject *const _init = String::createStaticString("__init__");
+ static PyObject *objectInit =
+ PyObject_GetAttr(reinterpret_cast<PyObject *>(&PyBaseObject_Type), _init);
+
+ // A native C++ self cannot have multiple inheritance.
+ if (!Object::isUserType(self))
+ return false;
+
+ auto *startType = Py_TYPE(self);
+ auto *mro = startType->tp_mro;
+ Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
+ auto classNameLen = std::strrchr(fullName, '.') - fullName;
+ /* No need to check the last one: it's gonna be skipped anyway. */
+ for (idx = 0; idx + 1 < n; ++idx) {
+ auto *lookType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ const char *lookName = lookType->tp_name;
+ auto lookLen = long(std::strlen(lookName));
+ if (std::strncmp(lookName, fullName, classNameLen) == 0 && lookLen == classNameLen)
+ break;
+ }
+ // We are now at the first non-Python class `QObject`.
+ // mro: ('C', 'A', 'QObject', 'Object', 'B', 'object')
+ // We want to catch class `B` and call its `__init__`.
+ for (idx += 1; idx + 1 < n; ++idx) {
+ auto *t = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ if (isPythonType(t))
+ break;
+ }
+ if (idx >= n)
+ return false;
+
+ auto *obSubType = PyTuple_GET_ITEM(mro, idx);
+ auto *subType = reinterpret_cast<PyTypeObject *>(obSubType);
+ if (subType == &PyBaseObject_Type)
+ return false;
+ AutoDecRef func(PyObject_GetAttr(obSubType, _init));
+ // PYSIDE-2654: If this has no implementation then we get object.__init__
+ // but that is the same case like above.
+ if (func == objectInit)
+ return false;
+ // PYSIDE-2294: We need to explicitly ignore positional args in a mixin class.
+ SBK_UNUSED(args);
+ AutoDecRef newArgs(PyTuple_New(1));
+ auto *newArgsOb = newArgs.object();
+ Py_INCREF(self);
+ PyTuple_SET_ITEM(newArgsOb, 0, self);
+ // Note: This can fail, so please always check the error status.
+ AutoDecRef result(PyObject_Call(func, newArgs, kwds));
+ return true;
+}
+
+} // namespace Shiboken
+
diff --git a/sources/shiboken6/libshiboken/bindingmanager.h b/sources/shiboken6/libshiboken/bindingmanager.h
new file mode 100644
index 000000000..54c4e486a
--- /dev/null
+++ b/sources/shiboken6/libshiboken/bindingmanager.h
@@ -0,0 +1,93 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef BINDINGMANAGER_H
+#define BINDINGMANAGER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+#include <set>
+#include <utility>
+
+struct SbkObject;
+
+namespace Shiboken
+{
+
+namespace Module {
+struct TypeInitStruct;
+}
+
+struct DestructorEntry;
+
+using ObjectVisitor = void (*)(SbkObject *, void *);
+
+class LIBSHIBOKEN_API BindingManager
+{
+public:
+ BindingManager(const BindingManager &) = delete;
+ BindingManager(BindingManager &&) = delete;
+ BindingManager &operator=(const BindingManager &) = delete;
+ BindingManager &operator=(BindingManager &&) = delete;
+
+ static BindingManager &instance();
+
+ bool hasWrapper(const void *cptr);
+
+ void registerWrapper(SbkObject *pyObj, void *cptr);
+ void releaseWrapper(SbkObject *wrapper);
+
+ void runDeletionInMainThread();
+ void addToDeletionInMainThread(const DestructorEntry &);
+
+ SbkObject *retrieveWrapper(const void *cptr);
+ PyObject *getOverride(const void *cptr, PyObject *nameCache[], const char *methodName);
+
+ void addClassInheritance(Module::TypeInitStruct *parent, Module::TypeInitStruct *child);
+ /// Try to find the correct type of cptr via type discovery knowing that it's at least
+ /// of type \p type. If a derived class is found, it returns a cptr cast to the type
+ /// (which may be different in case of multiple inheritance.
+ /// \param cptr a pointer to the instance of type \p type
+ /// \param type type of cptr
+ using TypeCptrPair = std::pair<PyTypeObject *, void *>;
+ TypeCptrPair findDerivedType(void *cptr, PyTypeObject *type) const;
+
+ /**
+ * Try to find the correct type of *cptr knowing that it's at least of type \p type.
+ * In case of multiple inheritance this function may change the contents of cptr.
+ * \param cptr a pointer to a pointer to the instance of type \p type
+ * \param type type of *cptr
+ * \warning This function is slow, use it only as last resort.
+ */
+ [[deprecated]] PyTypeObject *resolveType(void **cptr, PyTypeObject *type);
+
+ std::set<PyObject *> getAllPyObjects();
+
+ /**
+ * Calls the function \p visitor for each object registered on binding manager.
+ * \note As various C++ pointers can point to the same PyObject due to multiple inheritance
+ * a PyObject can be called more than one time for each PyObject.
+ * \param visitor function called for each object.
+ * \param data user data passed as second argument to the visitor function.
+ */
+ void visitAllPyObjects(ObjectVisitor visitor, void *data);
+
+ bool dumpTypeGraph(const char *fileName) const;
+ void dumpWrapperMap();
+
+private:
+ ~BindingManager();
+ BindingManager();
+
+ struct BindingManagerPrivate;
+ BindingManagerPrivate *m_d;
+};
+
+LIBSHIBOKEN_API bool callInheritedInit(PyObject *self, PyObject *args, PyObject *kwds,
+ const char *fullName);
+
+} // namespace Shiboken
+
+#endif // BINDINGMANAGER_H
+
diff --git a/sources/shiboken6/libshiboken/bufferprocs_py37.cpp b/sources/shiboken6/libshiboken/bufferprocs_py37.cpp
new file mode 100644
index 000000000..4ccf970e5
--- /dev/null
+++ b/sources/shiboken6/libshiboken/bufferprocs_py37.cpp
@@ -0,0 +1,360 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*****************************************************************************
+ *
+ * Copied from abstract.c
+ *
+ * Py_buffer has been replaced by Pep_buffer
+ *
+ */
+
+#ifdef Py_LIMITED_API
+
+#include "sbkpython.h"
+/* Buffer C-API for Python 3.0 */
+
+int
+PyObject_GetBuffer(PyObject *obj, Pep_buffer *view, int flags)
+{
+ PyBufferProcs *pb = PepType_AS_BUFFER(Py_TYPE(obj));
+
+ if (pb == NULL || pb->bf_getbuffer == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "a bytes-like object is required, not '%.100s'",
+ Py_TYPE(obj)->tp_name);
+ return -1;
+ }
+ return (*pb->bf_getbuffer)(obj, view, flags);
+}
+
+static int
+_IsFortranContiguous(const Pep_buffer *view)
+{
+ Py_ssize_t sd, dim;
+ int i;
+
+ /* 1) len = product(shape) * itemsize
+ 2) itemsize > 0
+ 3) len = 0 <==> exists i: shape[i] = 0 */
+ if (view->len == 0) return 1;
+ if (view->strides == NULL) { /* C-contiguous by definition */
+ /* Trivially F-contiguous */
+ if (view->ndim <= 1) return 1;
+
+ /* ndim > 1 implies shape != NULL */
+ assert(view->shape != NULL);
+
+ /* Effectively 1-d */
+ sd = 0;
+ for (i=0; i<view->ndim; i++) {
+ if (view->shape[i] > 1) sd += 1;
+ }
+ return sd <= 1;
+ }
+
+ /* strides != NULL implies both of these */
+ assert(view->ndim > 0);
+ assert(view->shape != NULL);
+
+ sd = view->itemsize;
+ for (i=0; i<view->ndim; i++) {
+ dim = view->shape[i];
+ if (dim > 1 && view->strides[i] != sd) {
+ return 0;
+ }
+ sd *= dim;
+ }
+ return 1;
+}
+
+static int
+_IsCContiguous(const Pep_buffer *view)
+{
+ Py_ssize_t sd, dim;
+ int i;
+
+ /* 1) len = product(shape) * itemsize
+ 2) itemsize > 0
+ 3) len = 0 <==> exists i: shape[i] = 0 */
+ if (view->len == 0) return 1;
+ if (view->strides == NULL) return 1; /* C-contiguous by definition */
+
+ /* strides != NULL implies both of these */
+ assert(view->ndim > 0);
+ assert(view->shape != NULL);
+
+ sd = view->itemsize;
+ for (i=view->ndim-1; i>=0; i--) {
+ dim = view->shape[i];
+ if (dim > 1 && view->strides[i] != sd) {
+ return 0;
+ }
+ sd *= dim;
+ }
+ return 1;
+}
+
+int
+PyBuffer_IsContiguous(const Pep_buffer *view, char order)
+{
+
+ if (view->suboffsets != NULL) return 0;
+
+ if (order == 'C')
+ return _IsCContiguous(view);
+ else if (order == 'F')
+ return _IsFortranContiguous(view);
+ else if (order == 'A')
+ return (_IsCContiguous(view) || _IsFortranContiguous(view));
+ return 0;
+}
+
+
+void *
+PyBuffer_GetPointer(Pep_buffer *view, Py_ssize_t *indices)
+{
+ int i;
+ auto pointer = reinterpret_cast<char *>(view->buf);
+ for (i = 0; i < view->ndim; i++) {
+ pointer += view->strides[i]*indices[i];
+ if ((view->suboffsets != NULL) && (view->suboffsets[i] >= 0)) {
+ pointer = *reinterpret_cast<char **>(pointer) + view->suboffsets[i];
+ }
+ }
+ return pointer;
+}
+
+
+void
+_Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape)
+{
+ int k;
+
+ for (k=0; k<nd; k++) {
+ if (index[k] < shape[k]-1) {
+ index[k]++;
+ break;
+ }
+ else {
+ index[k] = 0;
+ }
+ }
+}
+
+void
+_Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape)
+{
+ int k;
+
+ for (k=nd-1; k>=0; k--) {
+ if (index[k] < shape[k]-1) {
+ index[k]++;
+ break;
+ }
+ else {
+ index[k] = 0;
+ }
+ }
+}
+
+int
+PyBuffer_FromContiguous(Pep_buffer *view, void *buf, Py_ssize_t len, char fort)
+{
+ int k;
+ void (*addone)(int, Py_ssize_t *, const Py_ssize_t *);
+ Py_ssize_t *indices, elements;
+ char *src, *ptr;
+
+ if (len > view->len) {
+ len = view->len;
+ }
+
+ if (PyBuffer_IsContiguous(view, fort)) {
+ /* simplest copy is all that is needed */
+ memcpy(view->buf, buf, len);
+ return 0;
+ }
+
+ /* Otherwise a more elaborate scheme is needed */
+
+ /* view->ndim <= 64 */
+ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim));
+ if (indices == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ for (k=0; k<view->ndim; k++) {
+ indices[k] = 0;
+ }
+
+ if (fort == 'F') {
+ addone = _Py_add_one_to_index_F;
+ }
+ else {
+ addone = _Py_add_one_to_index_C;
+ }
+ src = (char *)buf; // patched by CT
+ /* XXX : This is not going to be the fastest code in the world
+ several optimizations are possible.
+ */
+ elements = len / view->itemsize;
+ while (elements--) {
+ ptr = (char *)PyBuffer_GetPointer(view, indices); // patched by CT
+ memcpy(ptr, src, view->itemsize);
+ src += view->itemsize;
+ addone(view->ndim, indices, view->shape);
+ }
+
+ PyMem_Free(indices);
+ return 0;
+}
+
+int PyObject_CopyData(PyObject *dest, PyObject *src)
+{
+ Pep_buffer view_dest, view_src;
+ int k;
+ Py_ssize_t *indices, elements;
+ char *dptr, *sptr;
+
+ if (!PyObject_CheckBuffer(dest) ||
+ !PyObject_CheckBuffer(src)) {
+ PyErr_SetString(PyExc_TypeError,
+ "both destination and source must be "\
+ "bytes-like objects");
+ return -1;
+ }
+
+ if (PyObject_GetBuffer(dest, &view_dest, PyBUF_FULL) != 0) return -1;
+ if (PyObject_GetBuffer(src, &view_src, PyBUF_FULL_RO) != 0) {
+ PyBuffer_Release(&view_dest);
+ return -1;
+ }
+
+ if (view_dest.len < view_src.len) {
+ PyErr_SetString(PyExc_BufferError,
+ "destination is too small to receive data from source");
+ PyBuffer_Release(&view_dest);
+ PyBuffer_Release(&view_src);
+ return -1;
+ }
+
+ if ((PyBuffer_IsContiguous(&view_dest, 'C') &&
+ PyBuffer_IsContiguous(&view_src, 'C')) ||
+ (PyBuffer_IsContiguous(&view_dest, 'F') &&
+ PyBuffer_IsContiguous(&view_src, 'F'))) {
+ /* simplest copy is all that is needed */
+ memcpy(view_dest.buf, view_src.buf, view_src.len);
+ PyBuffer_Release(&view_dest);
+ PyBuffer_Release(&view_src);
+ return 0;
+ }
+
+ /* Otherwise a more elaborate copy scheme is needed */
+
+ /* XXX(nnorwitz): need to check for overflow! */
+ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view_src.ndim);
+ if (indices == NULL) {
+ PyErr_NoMemory();
+ PyBuffer_Release(&view_dest);
+ PyBuffer_Release(&view_src);
+ return -1;
+ }
+ for (k=0; k<view_src.ndim;k++) {
+ indices[k] = 0;
+ }
+ elements = 1;
+ for (k=0; k<view_src.ndim; k++) {
+ /* XXX(nnorwitz): can this overflow? */
+ elements *= view_src.shape[k];
+ }
+ while (elements--) {
+ _Py_add_one_to_index_C(view_src.ndim, indices, view_src.shape);
+ dptr = (char *)PyBuffer_GetPointer(&view_dest, indices); // patched by CT
+ sptr = (char *)PyBuffer_GetPointer(&view_src, indices); // patched by CT
+ memcpy(dptr, sptr, view_src.itemsize);
+ }
+ PyMem_Free(indices);
+ PyBuffer_Release(&view_dest);
+ PyBuffer_Release(&view_src);
+ return 0;
+}
+
+void
+PyBuffer_FillContiguousStrides(int nd, Py_ssize_t *shape,
+ Py_ssize_t *strides, int itemsize,
+ char fort)
+{
+ int k;
+ Py_ssize_t sd;
+
+ sd = itemsize;
+ if (fort == 'F') {
+ for (k=0; k<nd; k++) {
+ strides[k] = sd;
+ sd *= shape[k];
+ }
+ }
+ else {
+ for (k=nd-1; k>=0; k--) {
+ strides[k] = sd;
+ sd *= shape[k];
+ }
+ }
+ return;
+}
+
+int
+PyBuffer_FillInfo(Pep_buffer *view, PyObject *obj, void *buf, Py_ssize_t len,
+ int readonly, int flags)
+{
+ if (view == NULL) {
+ PyErr_SetString(PyExc_BufferError,
+ "PyBuffer_FillInfo: view==NULL argument is obsolete");
+ return -1;
+ }
+
+ if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) &&
+ (readonly == 1)) {
+ PyErr_SetString(PyExc_BufferError,
+ "Object is not writable.");
+ return -1;
+ }
+
+ view->obj = obj;
+ if (obj)
+ Py_INCREF(obj);
+ view->buf = buf;
+ view->len = len;
+ view->readonly = readonly;
+ view->itemsize = 1;
+ view->format = NULL;
+ if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
+ view->format = (char *)"B"; // patched by CT
+ view->ndim = 1;
+ view->shape = NULL;
+ if ((flags & PyBUF_ND) == PyBUF_ND)
+ view->shape = &(view->len);
+ view->strides = NULL;
+ if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
+ view->strides = &(view->itemsize);
+ view->suboffsets = NULL;
+ view->internal = NULL;
+ return 0;
+}
+
+void
+PyBuffer_Release(Pep_buffer *view)
+{
+ PyObject *obj = view->obj;
+ PyBufferProcs *pb;
+ if (obj == NULL)
+ return;
+ pb = PepType_AS_BUFFER(Py_TYPE(obj));
+ if (pb && pb->bf_releasebuffer)
+ pb->bf_releasebuffer(obj, view);
+ view->obj = NULL;
+ Py_DECREF(obj);
+}
+
+#endif // Py_LIMITED_API
diff --git a/sources/shiboken6/libshiboken/bufferprocs_py37.h b/sources/shiboken6/libshiboken/bufferprocs_py37.h
new file mode 100644
index 000000000..e16194e50
--- /dev/null
+++ b/sources/shiboken6/libshiboken/bufferprocs_py37.h
@@ -0,0 +1,109 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*
+PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+ the Individual or Organization ("Licensee") accessing and otherwise using Python
+ 3.7.0 software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python 3.7.0 alone or in any derivative
+ version, provided, however, that PSF's License Agreement and PSF's notice of
+ copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+ Reserved" are retained in Python 3.7.0 alone or in any derivative version
+ prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates Python 3.7.0 or any part thereof, and wants to make the
+ derivative work available to others as provided herein, then Licensee hereby
+ agrees to include in any such work a brief summary of the changes made to Python
+ 3.7.0.
+
+4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+ PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+ EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+ USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+ its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between PSF and Licensee. This License
+ Agreement does not grant permission to use PSF trademarks or trade name in a
+ trademark sense to endorse or promote products or services of Licensee, or any
+ third party.
+
+8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+ to be bound by the terms and conditions of this License Agreement.
+*/
+
+#ifndef BUFFER_REENABLE_H
+#define BUFFER_REENABLE_H
+
+/* buffer interface */
+// This has been renamed to Pep_buffer and will be used.
+typedef struct bufferinfo {
+ void *buf;
+ PyObject *obj; /* owned reference */
+ Py_ssize_t len;
+ Py_ssize_t itemsize; /* This is Py_ssize_t so it can be
+ pointed to by strides in simple case.*/
+ int readonly;
+ int ndim;
+ char *format;
+ Py_ssize_t *shape;
+ Py_ssize_t *strides;
+ Py_ssize_t *suboffsets;
+ void *internal;
+} Pep_buffer;
+
+using getbufferproc =int (*)(PyObject *, Pep_buffer *, int);
+using releasebufferproc = void (*)(PyObject *, Pep_buffer *);
+
+/* Maximum number of dimensions */
+#define PyBUF_MAX_NDIM 64
+
+/* Flags for getting buffers */
+#define PyBUF_SIMPLE 0
+#define PyBUF_WRITABLE 0x0001
+/* we used to include an E, backwards compatible alias */
+#define PyBUF_WRITEABLE PyBUF_WRITABLE
+#define PyBUF_FORMAT 0x0004
+#define PyBUF_ND 0x0008
+#define PyBUF_STRIDES (0x0010 | PyBUF_ND)
+#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES)
+#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES)
+#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES)
+#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
+
+#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE)
+#define PyBUF_CONTIG_RO (PyBUF_ND)
+
+#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE)
+#define PyBUF_STRIDED_RO (PyBUF_STRIDES)
+
+#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT)
+#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT)
+
+#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT)
+#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT)
+
+
+#define PyBUF_READ 0x100
+#define PyBUF_WRITE 0x200
+
+/* End buffer interface */
+LIBSHIBOKEN_API PyObject *PyMemoryView_FromBuffer(Pep_buffer *info);
+#define Py_buffer Pep_buffer
+
+#endif // BUFFER_REENABLE_H
diff --git a/sources/shiboken6/libshiboken/debugfreehook.cpp b/sources/shiboken6/libshiboken/debugfreehook.cpp
new file mode 100644
index 000000000..13df6bd6c
--- /dev/null
+++ b/sources/shiboken6/libshiboken/debugfreehook.cpp
@@ -0,0 +1,158 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "debugfreehook.h"
+#include "bindingmanager.h"
+#include "gilstate.h"
+
+#if defined(_WIN32) && defined(_DEBUG)
+# include <sbkwindows.h>
+# include <crtdbg.h>
+#endif
+
+#ifdef __GLIBC__
+#include <malloc.h>
+#endif
+
+#ifdef __APPLE__
+#include <malloc/malloc.h>
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#endif
+
+#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+extern "C" {
+
+static int testPointerBeingFreed(void *ptr)
+{
+ // It is an error for a deleted pointer address to still be registered
+ // in the BindingManager
+ if (Shiboken::BindingManager::instance().hasWrapper(ptr)) {
+ Shiboken::GilState state;
+
+ SbkObject *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(ptr);
+
+ fprintf(stderr, "SbkObject still in binding map when deleted: ");
+ PyObject_Print(reinterpret_cast<PyObject *>(wrapper), stderr, 0);
+ fprintf(stderr, "\n");
+
+#ifdef _WIN32
+ DebugBreak();
+#else
+ assert(0);
+#endif
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#if defined(_WIN32) && defined(_DEBUG)
+static _CRT_ALLOC_HOOK lastCrtAllocHook;
+static int DebugAllocHook(int nAllocType, void *pvData,
+ size_t nSize, int nBlockUse, long lRequest,
+ const unsigned char * szFileName, int nLine)
+{
+ // It is an error for a deleted pointer address to still be registered
+ // in the BindingManager
+ if ( nAllocType == _HOOK_FREE) {
+ if ( !testPointerBeingFreed(pvData) ) {
+ return 0;
+ }
+ }
+
+ if ( lastCrtAllocHook != NULL ) {
+ return lastCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest,
+ szFileName, nLine);
+ }
+
+ return 1;
+}
+#endif // _WIN32 && _DEBUG
+
+#ifdef __GLIBC__
+static void (*lastFreeHook)(void *ptr, const void *caller);
+static void DebugFreeHook(void *ptr, const void *caller)
+{
+ testPointerBeingFreed(ptr);
+
+ if ( lastFreeHook != NULL )
+ lastFreeHook(ptr, caller);
+}
+#endif // __GLIBC__
+
+#ifdef __APPLE__
+static malloc_zone_t lastMallocZone;
+static void DebugFreeHook(malloc_zone_t *zone, void *ptr)
+{
+ testPointerBeingFreed(ptr);
+
+ if ( lastMallocZone.free != NULL )
+ lastMallocZone.free(zone, ptr);
+}
+static void DebugFreeDefiniteSizeHook(malloc_zone_t *zone, void *ptr, size_t size)
+{
+ testPointerBeingFreed(ptr);
+
+ if ( lastMallocZone.free_definite_size != NULL )
+ lastMallocZone.free_definite_size(zone, ptr, size);
+}
+#endif __APPLE__
+
+void debugInstallFreeHook(void)
+{
+#if defined(_WIN32) && defined(_DEBUG)
+ lastCrtAllocHook = _CrtSetAllocHook(DebugAllocHook);
+#endif
+
+#ifdef __GLIBC__
+ // __free_hook is not thread safe so it marked as deprecated. Use here
+ // is hopefully safe and should catch errors in a single threaded program
+ // and only miss some in a multithreaded program
+ lastFreeHook = __free_hook;
+ __free_hook = DebugFreeHook;
+#endif
+
+#ifdef __APPLE__
+ malloc_zone_t *zone = malloc_default_zone();
+ assert(zone != NULL);
+ //remove the write protection from the zone struct
+ if (zone->version >= 8) {
+ vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ | VM_PROT_WRITE);
+ }
+ lastMallocZone = *zone;
+ zone->free = DebugFreeHook;
+ zone->free_definite_size = DebugFreeDefiniteSizeHook;
+ if (zone->version >= 8) {
+ vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ);
+ }
+#endif
+}
+
+void debugRemoveFreeHook(void)
+{
+#if defined(_WIN32) && defined(_DEBUG)
+ _CrtSetAllocHook(lastCrtAllocHook);
+#endif
+
+#ifdef __GLIBC__
+ __free_hook = lastFreeHook;
+#endif
+
+#ifdef __APPLE__
+ malloc_zone_t *zone = malloc_default_zone();
+ assert(zone != NULL);
+ //remove the write protection from the zone struct
+ if (zone->version >= 8) {
+ vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ | VM_PROT_WRITE);
+ }
+ zone->free = lastMallocZone.free;
+ zone->free_definite_size = lastMallocZone.free_definite_size;
+ if (zone->version >= 8) {
+ vm_protect(mach_task_self(), (uintptr_t)zone, sizeof(*zone), 0, VM_PROT_READ);
+ }
+#endif
+}
+
+} // extern "C"
+#endif // SHIBOKEN_INSTALL_DEBUG_FREE_HOOK
diff --git a/sources/shiboken6/libshiboken/debugfreehook.h b/sources/shiboken6/libshiboken/debugfreehook.h
new file mode 100644
index 000000000..c19e36ab2
--- /dev/null
+++ b/sources/shiboken6/libshiboken/debugfreehook.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef DEBUGFREEHOOK_H
+#define DEBUGFREEHOOK_H
+
+// These functions enable C library runtime hooks to try to catch cases where
+// C++ object addresses remain in hash table of valid wrappers when the address
+// is passed to free. The hooks are probably not thread safe and thus
+// should only be enabled in single threaded environments
+
+// To enable the hook, uncomment the following define.
+//#define SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+
+#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+extern "C" {
+
+void debugInstallFreeHook(void);
+void debugRemoveFreeHook(void);
+
+} // extern "C"
+
+#endif // SHIBOKEN_INSTALL_FREE_DEBUG_HOOK
+
+#endif // DEBUGFREEHOOK_H
diff --git a/sources/shiboken6/libshiboken/embed/embedding_generator.py b/sources/shiboken6/libshiboken/embed/embedding_generator.py
new file mode 100644
index 000000000..a058fd372
--- /dev/null
+++ b/sources/shiboken6/libshiboken/embed/embedding_generator.py
@@ -0,0 +1,220 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+embedding_generator.py
+
+This file takes the content of the two supported directories and inserts
+it into a zip file. The zip file is then converted into a C++ source
+file that can easily be unpacked again with Python (see signature.cpp,
+constant 'PySide_PythonCode').
+
+Note that this _is_ a zipfile, but since it is embedded into the shiboken
+binary, we cannot use the zipimport module from Python.
+But a similar solution is possible that allows for normal imports.
+
+See signature_bootstrap.py for details.
+"""
+
+import sys
+import os
+import subprocess
+import textwrap
+import tempfile
+import argparse
+import marshal
+import traceback
+from pathlib import Path
+
+# work_dir is set to the source for testing, only.
+# It can be overridden in the command line.
+work_dir = Path(__file__).parent.resolve()
+embed_dir = work_dir
+cur_dir = Path.cwd()
+source_dir = work_dir.parents[2]
+assert source_dir.name == "sources"
+build_script_dir = work_dir.parents[3]
+assert (build_script_dir / "build_scripts").exists()
+
+sys.path.insert(0, os.fspath(build_script_dir))
+
+from build_scripts import utils
+
+
+def runpy(cmd, **kw):
+ subprocess.call([sys.executable, '-E'] + cmd.split(), **kw)
+
+
+def create_zipfile(use_pyc, quiet):
+ """
+ Collect all Python files, compile them, create a zip file
+ and make a chunked base64 encoded file from it.
+ """
+ zip_name = "signature.zip"
+ inc_name = "signature_inc.h"
+ flag = '-b'
+ os.chdir(work_dir)
+
+ # Remove all left-over py[co] and other files first, in case we use '--reuse-build'.
+ # Note that we could improve that with the PyZipfile function to use .pyc files
+ # in different folders, but that makes only sense when COIN allows us to have
+ # multiple Python versions in parallel.
+ for root, dirs, files in os.walk(work_dir):
+ for name in files:
+ fpath = Path(root) / name
+ ew = name.endswith
+ if ew(".pyc") or ew(".pyo") or ew(".zip") or ew(".inc"):
+ os.remove(fpath)
+ # We copy every Python file into this dir, but only for the right version.
+ # For testing in the source dir, we need to filter.
+ ignore = []
+ utils.copydir(source_dir / "shiboken6" / "shibokenmodule" / "files.dir" / "shibokensupport",
+ work_dir / "shibokensupport",
+ ignore=ignore, file_filter_function=lambda name, n2: name.endswith(".py"))
+ if embed_dir != work_dir:
+ utils.copyfile(embed_dir / "signature_bootstrap.py", work_dir)
+
+ if not use_pyc:
+ pass # We cannot compile, unless we have folders per Python version
+ else:
+ files = ' '.join(fn for fn in os.listdir('.'))
+ runpy(f'-m compileall -q {flag} {files}')
+ files = ' '.join(fn for fn in os.listdir('.') if not fn == zip_name)
+ runpy(f'-m zipfile -c {zip_name} {files}')
+ tmp = tempfile.TemporaryFile(mode="w+")
+ runpy(f'-m base64 {zip_name}', stdout=tmp)
+ # now generate the include file
+ tmp.seek(0)
+ with open(inc_name, "w") as inc:
+ _embed_file(tmp, inc)
+ tmp.close()
+
+ # also generate a simple embeddable .pyc file for signature_bootstrap.pyc
+ boot_name = "signature_bootstrap.py" if not use_pyc else "signature_bootstrap.pyc"
+ with open(boot_name, "rb") as ldr, open("signature_bootstrap_inc.h", "w") as inc:
+ _embed_bytefile(ldr, inc, not use_pyc)
+ os.chdir(cur_dir)
+ if quiet:
+ return
+
+ # have a look at our populated folder unless quiet option
+ def tree(directory):
+ print(f'+ {directory}')
+ for path in sorted(directory.rglob('*')):
+ depth = len(path.relative_to(directory).parts)
+ spacer = ' ' * depth
+ print(f'{spacer}+ {path.name}')
+
+ print("++++ Current contents of")
+ tree(work_dir)
+ print("++++")
+
+
+def _embed_file(fin, fout):
+ """
+ Format a text file for embedding in a C++ source file.
+ """
+ # MSVC has a 64k string limitation. In C, it would be easy to create an
+ # array of 64 byte strings and use them as one big array. In C++ this does
+ # not work, since C++ insists in having the terminating nullbyte.
+ # Therefore, we split the string after an arbitrary number of lines
+ # (chunked file).
+ limit = 50
+ text = fin.readlines()
+ print(textwrap.dedent("""
+ // This is a ZIP archive of all Python files in the directory
+ // "shiboken6/shibokenmodule/files.dir/shibokensupport/signature"
+ // There is also a toplevel file "signature_bootstrap.py[c]" that will be
+ // directly executed from C++ as a bootstrap loader.
+ """).strip(), file=fout)
+ block, blocks = 0, len(text) // limit + 1
+ for idx, line in enumerate(text):
+ if idx % limit == 0:
+ if block:
+ fout.write(')"\n')
+ comma = "," if block else ""
+ block += 1
+ fout.write(f'\n{comma} // Block {block} of {blocks}\nR"(')
+ else:
+ fout.write('\n')
+ fout.write(line.strip())
+ fout.write(')"\n\n/* Sentinel */, ""\n')
+
+
+def _embed_bytefile(fin, fout, is_text):
+ """
+ Format a binary file for embedding in a C++ source file.
+ This version works directly with a single .pyc file.
+ """
+ fname = fin.name
+ remark = ("No .pyc file because '--LIMITED-API=yes'" if is_text else
+ "The .pyc header is stripped away")
+ print(textwrap.dedent(f"""
+ /*
+ * This is the file "{fname}" as a simple byte array.
+ * It can be directly embedded without any further processing.
+ * {remark}.
+ */
+ """), file=fout)
+ headsize = ( 0 if is_text else
+ 16 if sys.version_info >= (3, 7) else 12 if sys.version_info >= (3, 3) else 8)
+ binstr = fin.read()[headsize:]
+ if is_text:
+ try:
+ compile(binstr, fin.name, "exec")
+ except SyntaxError as e:
+ print(e)
+ traceback.print_exc(file=sys.stdout)
+ print(textwrap.dedent(f"""
+ *************************************************************************
+ ***
+ *** Could not compile the boot loader '{fname}'!
+ ***
+ *************************************************************************
+ """))
+ raise SystemError
+ else:
+ try:
+ marshal.loads(binstr)
+ except ValueError as e:
+ print(e)
+ traceback.print_exc(file=sys.stdout)
+ version = sys.version_info[:3]
+ print(textwrap.dedent(f"""
+ *************************************************************************
+ ***
+ *** This Python version {version} seems to have a new .pyc header size.
+ *** Please correct the 'headsize' constant ({headsize}).
+ ***
+ *************************************************************************
+ """))
+ raise SystemError
+
+ print(file=fout)
+ use_ord = sys.version_info[0] == 2
+ for i in range(0, len(binstr), 16):
+ for c in bytes(binstr[i : i + 16]):
+ ord_c = ord(c) if use_ord else c
+ print(f"{ord_c:#4},", file=fout, end="")
+ print(file=fout)
+ print("/* End Of File */", file=fout)
+
+
+def str2bool(v):
+ if v.lower() in ('yes', 'true', 't', 'y', '1'):
+ return True
+ elif v.lower() in ('no', 'false', 'f', 'n', '0'):
+ return False
+ else:
+ raise argparse.ArgumentTypeError('Boolean value expected.')
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--cmake-dir', nargs="?")
+ parser.add_argument('--use-pyc', type=str2bool)
+ parser.add_argument('--quiet', action='store_true')
+ args = parser.parse_args()
+ if args.cmake_dir:
+ work_dir = Path(args.cmake_dir).resolve()
+ create_zipfile(args.use_pyc, args.quiet)
diff --git a/sources/shiboken6/libshiboken/embed/module_collector.py b/sources/shiboken6/libshiboken/embed/module_collector.py
new file mode 100644
index 000000000..a58ce6e4f
--- /dev/null
+++ b/sources/shiboken6/libshiboken/embed/module_collector.py
@@ -0,0 +1,71 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+module_collector.py
+
+Collect a number of modules listed on the command line.
+
+The purpose of this script is to generate the scripts needed for
+a complete isolation of the signature extension.
+
+Usage:
+
+Run this script in one of the used python versions.
+It will create an executable archive of the files on the command line.
+"""
+
+import sys
+import os
+import argparse
+import pickle
+from textwrap import dedent
+from pathlib import path
+
+
+def source_archive(module, modname):
+ fname = Path(module.__file__).stem + ".py"
+ with open(fname) as source:
+ text = source.read()
+ encoded = text.replace("'''", "(triple_single)")
+ # modname = module.__name__
+ # Do not use: Some modules rename themselves!
+ version = ".".join(map(str, sys.version_info[:3]))
+ shortname = fname.stem
+ preamble = dedent(fr"""
+ # BEGIN SOURCE ARCHIVE Python {version} module {modname}
+
+ sources = {{}} if "sources" not in globals() else sources
+ sources["{modname}"] = '''\
+ {encoded}'''.replace("(triple_single)", "'''")
+
+ # END SOURCE ARCHIVE Python {version} module {modname}
+ """)
+ return preamble
+
+
+def read_all(modules):
+ collected = ""
+ for modname in modules:
+ mod = __import__(modname)
+ collected += source_archive(mod, modname)
+ return collected
+
+
+def license_header():
+ license = Path(__file__).parent / "qt_python_license.txt"
+ with license.open() as f:
+ return f.read()
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('modules', nargs="+")
+ args = parser.parse_args()
+ print("modules:", args.modules)
+ ret = license_header() + read_all(args.modules)
+ ma_mi = "_".join(map(str, sys.version_info[:2]))
+ outpath = Path(__file__).parents[2] / Path("shibokenmodule",
+ "files.dir", "shibokensupport", f"python_minilib_{ma_mi}.py")
+ with outpath.open("w") as f:
+ f.write(ret)
diff --git a/sources/shiboken6/libshiboken/embed/qt_python_license.txt b/sources/shiboken6/libshiboken/embed/qt_python_license.txt
new file mode 100644
index 000000000..e5fdfdf4d
--- /dev/null
+++ b/sources/shiboken6/libshiboken/embed/qt_python_license.txt
@@ -0,0 +1,48 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+##
+## PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+##
+## 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+## the Individual or Organization ("Licensee") accessing and otherwise using Python
+## 3.7.0 software in source or binary form and its associated documentation.
+##
+## 2. Subject to the terms and conditions of this License Agreement, PSF hereby
+## grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+## analyze, test, perform and/or display publicly, prepare derivative works,
+## distribute, and otherwise use Python 3.7.0 alone or in any derivative
+## version, provided, however, that PSF's License Agreement and PSF's notice of
+## copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+## Reserved" are retained in Python 3.7.0 alone or in any derivative version
+## prepared by Licensee.
+##
+## 3. In the event Licensee prepares a derivative work that is based on or
+## incorporates Python 3.7.0 or any part thereof, and wants to make the
+## derivative work available to others as provided herein, then Licensee hereby
+## agrees to include in any such work a brief summary of the changes made to Python
+## 3.7.0.
+##
+## 4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+## PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+## EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+## WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+## USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+##
+## 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+## FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+## MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+## THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+##
+## 6. This License Agreement will automatically terminate upon a material breach of
+## its terms and conditions.
+##
+## 7. Nothing in this License Agreement shall be deemed to create any relationship
+## of agency, partnership, or joint venture between PSF and Licensee. This License
+## Agreement does not grant permission to use PSF trademarks or trade name in a
+## trademark sense to endorse or promote products or services of Licensee, or any
+## third party.
+##
+## 8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+## to be bound by the terms and conditions of this License Agreement.
+##
diff --git a/sources/shiboken6/libshiboken/embed/signature_bootstrap.py b/sources/shiboken6/libshiboken/embed/signature_bootstrap.py
new file mode 100644
index 000000000..37f95cd35
--- /dev/null
+++ b/sources/shiboken6/libshiboken/embed/signature_bootstrap.py
@@ -0,0 +1,204 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+signature_bootstrap.py
+----------------------
+
+This file was originally directly embedded into the C source.
+After it grew more and more, I now prefer to have it as Python file.
+
+Meanwhile, there is also no more a stub loader necessary:
+Because we meanwhile have embedding support, we could also load this file
+directly from a .pyc file.
+
+This file replaces the hard to read Python stub in 'signature.cpp', and we
+could distinguish better between bootstrap related functions and loader
+functions.
+It is embedded into 'signature.cpp' as "embed/signature_bootstrap.inc".
+
+# PYSIDE-1436: Python 3.10 had a problem with EmbeddableZipImporter because the
+imports were in the functions. Moved them outside into the globals.
+"""
+
+recursion_trap = 0
+
+import base64
+import importlib
+import io
+import os
+import sys
+import traceback
+import zipfile
+
+from contextlib import contextmanager
+from importlib.machinery import ModuleSpec
+from pathlib import Path
+
+
+def bootstrap():
+
+ global recursion_trap
+ if recursion_trap:
+ # we are probably called from outside, already
+ print("Recursion occurred in Bootstrap. Did you start by hand? Then it's ok.")
+ print("But you should trigger start by '_init_pyside_extension()', only!")
+ recursion_trap += 1
+
+ @contextmanager
+ def ensure_shibokensupport(target, support_path):
+ # Make sure that we always have the shibokensupport containing package first.
+ # Also remove any prior loaded module of this name, just in case.
+ # PYSIDE-1621: support_path can also be a finder instance.
+ target.insert(0, support_path)
+
+ sbks = "shibokensupport"
+ if sbks in sys.modules:
+ del sys.modules[sbks]
+ prefix = sbks + "."
+ for key in list(key for key in sys.modules if key.startswith(prefix)):
+ del sys.modules[key]
+ try:
+ import shibokensupport
+ yield
+ except Exception as e:
+ f = sys.stderr
+ print("Problem importing shibokensupport:", file=f)
+ print(f"{e.__class__.__name__}: {e}", file=f)
+ traceback.print_exc()
+ print("sys.path:", file=f)
+ for p in sys.path:
+ print(" " + p, file=f)
+ f.flush()
+ sys.exit(-1)
+ target.remove(support_path)
+
+ # Here we decide if we re-incarnate the embedded files or use embedding.
+ incarnated = find_incarnated_files()
+ if incarnated:
+ target, support_path = sys.path, os.fspath(incarnated)
+ else:
+ target, support_path = prepare_zipfile()
+ with ensure_shibokensupport(target, support_path):
+ from shibokensupport.signature import loader
+ return loader
+
+# Newer functionality:
+# This function checks if the support directory exist and returns it.
+# If does not exist, we try to create it and return it.
+# Otherwise, we return None.
+
+def find_incarnated_files():
+ import shiboken6 as root
+ files_dir = Path(root.__file__).resolve().parent / "files.dir"
+ handle_embedding_switch(files_dir)
+ if files_dir.exists():
+ sys.path.insert(0, os.fspath(files_dir))
+ # Note: To avoid recursion problems, we need to preload the loader.
+ # But that has the side-effect that we need to delay the feature
+ # initialization until all function pointers are set.
+ # See `post_init_func` in signature_globals.cpp .
+ import shibokensupport.signature.loader
+ del sys.path[0]
+ return files_dir
+ return None
+
+
+def handle_embedding_switch(files_dir):
+ """
+ This handles the optional environment variable `SBK_EMBED`
+ if not set : do nothing
+ if set to 0, false, no : de-virtualize the Python files
+ if set to 1, true, yes : virtualize again (delete "files.dir")
+ """
+ env_name = "SBK_EMBED"
+ env_var = os.environ.get(env_name)
+ if not env_var:
+ return
+ if env_var.lower() in ("1", "t", "true", "y", "yes"):
+ import shutil
+ shutil.rmtree(files_dir, ignore_errors=True)
+ elif env_var.lower() in ("0", "f", "false", "n", "no"):
+ reincarnate_files(files_dir)
+
+
+def reincarnate_files(files_dir):
+ target, zip = prepare_zipfile()
+ names = (_ for _ in zip.zfile.namelist() if _.endswith(".py"))
+ try:
+ # First check mkdir to get an error when we cannot write.
+ files_dir.mkdir(exist_ok=True)
+ except os.error as e:
+ print(f"SBK_EMBED=False: Warning: Cannot write into {files_dir}")
+ return None
+ try:
+ # Then check for a real error when unpacking the zip file.
+ zip.zfile.extractall(path=files_dir, members=names)
+ return files_dir
+ except Exception as e:
+ print(f"{e.__class__.__name__}: {e}", file=sys.stderr)
+ traceback.print_exc()
+ raise
+
+# New functionality: Loading from a zip archive.
+# There exists the zip importer, but as it is written, only real zip files are
+# supported. Before I will start an own implementation, it is easiest to use
+# a temporary zip file.
+# PYSIDE-1621: make zip file access totally virtual
+
+def prepare_zipfile():
+ """
+ Old approach:
+
+ Write the zip file to a real file and return its name.
+ It will be implicitly opened as such when we add the name to sys.path .
+
+ New approach (Python 3, only):
+
+ Use EmbeddableZipImporter and pass the zipfile structure directly.
+ The sys.path way does not work, instead we need to use sys.meta_path .
+ See https://docs.python.org/3/library/sys.html#sys.meta_path
+ """
+
+ # 'zipstring_sequence' comes from signature.cpp
+ zipbytes = base64.b64decode(''.join(zipstring_sequence))
+ vzip = zipfile.ZipFile(io.BytesIO(zipbytes))
+ return sys.meta_path, EmbeddableZipImporter(vzip)
+
+
+class EmbeddableZipImporter(object):
+
+ def __init__(self, zip_file):
+ def p2m(filename):
+ if filename.endswith("/__init__.py"):
+ return filename[:-12].replace("/", ".")
+ if filename.endswith(".py"):
+ return filename[:-3].replace("/", ".")
+ return None
+
+ self.zfile = zip_file
+ self._mod2path = {p2m(_.filename) : _.filename for _ in zip_file.filelist}
+
+ def find_spec(self, fullname, path, target=None):
+ path = self._mod2path.get(fullname)
+ return ModuleSpec(fullname, self) if path else None
+
+ def create_module(self, spec):
+ return None
+
+ def exec_module(self, module):
+ fullname = module.__spec__.name
+ filename = self._mod2path[fullname]
+ with self.zfile.open(filename, "r") as f: # "rb" not for zipfile
+ codeob = compile(f.read(), filename, "exec")
+ exec(codeob, module.__dict__)
+ module.__file__ = filename
+ module.__loader__ = self
+ if filename.endswith("/__init__.py"):
+ module.__path__ = []
+ module.__package__ = fullname
+ else:
+ module.__package__ = fullname.rpartition('.')[0]
+ sys.modules[fullname] = module
+
+# eof
diff --git a/sources/shiboken6/libshiboken/gilstate.cpp b/sources/shiboken6/libshiboken/gilstate.cpp
new file mode 100644
index 000000000..8daa93b8b
--- /dev/null
+++ b/sources/shiboken6/libshiboken/gilstate.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "gilstate.h"
+
+namespace Shiboken
+{
+
+GilState::GilState()
+{
+ if (Py_IsInitialized()) {
+ m_gstate = PyGILState_Ensure();
+ m_locked = true;
+ }
+}
+
+GilState::~GilState()
+{
+ release();
+}
+
+void GilState::release()
+{
+ if (m_locked && Py_IsInitialized()) {
+ PyGILState_Release(m_gstate);
+ m_locked = false;
+ }
+}
+
+// Abandon the lock: Only for special situations, like termination of a
+// POSIX thread (PYSIDE 1282).
+void GilState::abandon()
+{
+ m_locked = false;
+}
+
+} // namespace Shiboken
+
diff --git a/sources/shiboken6/libshiboken/gilstate.h b/sources/shiboken6/libshiboken/gilstate.h
new file mode 100644
index 000000000..abad9d955
--- /dev/null
+++ b/sources/shiboken6/libshiboken/gilstate.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef GILSTATE_H
+#define GILSTATE_H
+
+#include <shibokenmacros.h>
+#include "sbkpython.h"
+
+namespace Shiboken
+{
+
+class LIBSHIBOKEN_API GilState
+{
+public:
+ GilState(const GilState &) = delete;
+ GilState(GilState &&) = delete;
+ GilState &operator=(const GilState &) = delete;
+ GilState &operator=(GilState &&) = delete;
+
+ GilState();
+ ~GilState();
+ void release();
+ void abandon();
+private:
+ PyGILState_STATE m_gstate;
+ bool m_locked = false;
+};
+
+} // namespace Shiboken
+
+#endif // GILSTATE_H
+
diff --git a/sources/shiboken6/libshiboken/helper.cpp b/sources/shiboken6/libshiboken/helper.cpp
new file mode 100644
index 000000000..46af68956
--- /dev/null
+++ b/sources/shiboken6/libshiboken/helper.cpp
@@ -0,0 +1,637 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "helper.h"
+#include "basewrapper_p.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings.h"
+#include "pep384impl.h"
+
+#include <algorithm>
+#include <optional>
+
+#include <iomanip>
+#include <iostream>
+#include <climits>
+#include <cstring>
+#include <cstdarg>
+#include <cctype>
+
+#ifdef _WIN32
+# include <sbkwindows.h>
+#else
+# include <pthread.h>
+#endif
+
+static std::optional<std::string> getStringAttr(PyObject *obj, const char *what)
+{
+ if (PyObject_HasAttrString(obj, what) != 0) { // Check first to suppress error.
+ Shiboken::AutoDecRef result(PyObject_GetAttrString(obj, what));
+ if (PyUnicode_Check(result.object()) != 0)
+ return _PepUnicode_AsString(result.object());
+ }
+ return std::nullopt;
+}
+
+static std::optional<int> getIntAttr(PyObject *obj, const char *what)
+{
+ if (PyObject_HasAttrString(obj, what) != 0) { // Check first to suppress error.
+ Shiboken::AutoDecRef result(PyObject_GetAttrString(obj, what));
+ if (PyLong_Check(result.object()) != 0)
+ return PyLong_AsLong(result.object());
+ }
+ return std::nullopt;
+}
+
+static bool verbose = false;
+
+static void formatTypeTuple(PyObject *t, const char *what, std::ostream &str);
+
+static void formatPyTypeObject(const PyTypeObject *obj, std::ostream &str, bool verbose)
+{
+ if (obj == nullptr) {
+ str << '0';
+ return;
+ }
+
+ str << '"' << obj->tp_name << '"';
+ if (verbose) {
+ bool immutableType = false;
+ str << ", 0x" << std::hex << obj->tp_flags << std::dec;
+ if (obj->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ str << " [heaptype]";
+ if (obj->tp_flags & Py_TPFLAGS_BASETYPE)
+ str << " [base]";
+ if (obj->tp_flags & Py_TPFLAGS_HAVE_GC)
+ str << " [gc]";
+ if (obj->tp_flags & Py_TPFLAGS_LONG_SUBCLASS)
+ str << " [long]";
+ if (obj->tp_flags & Py_TPFLAGS_LIST_SUBCLASS)
+ str << " [list]";
+ if (obj->tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS)
+ str << " [tuple]";
+ if (obj->tp_flags & Py_TPFLAGS_BYTES_SUBCLASS)
+ str << " [bytes]";
+ if (obj->tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS)
+ str << " [unicode]";
+ if (obj->tp_flags & Py_TPFLAGS_DICT_SUBCLASS)
+ str << " [dict]";
+ if (obj->tp_flags & Py_TPFLAGS_TYPE_SUBCLASS)
+ str << " [type]";
+ if (obj->tp_flags & Py_TPFLAGS_IS_ABSTRACT)
+ str << " [abstract]";
+ if (obj->tp_flags & Py_TPFLAGS_READY)
+ str << " [ready]";
+ if (obj->tp_flags & Py_TPFLAGS_READYING)
+ str << " [readying]";
+ if (obj->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
+ str << " [method_descriptor]";
+# ifndef Py_LIMITED_API
+ if (obj->tp_flags & Py_TPFLAGS_HAVE_VECTORCALL)
+ str << " [vectorcall]";
+# endif // !Py_LIMITED_API
+# if PY_VERSION_HEX >= 0x030A0000
+ immutableType = (obj->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) != 0;
+ if (immutableType)
+ str << " [immutabletype]";
+ if (obj->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)
+ str << " [disallow_instantiation]";
+# ifndef Py_LIMITED_API
+ if (obj->tp_flags & Py_TPFLAGS_MAPPING)
+ str << " [mapping]";
+ if (obj->tp_flags & Py_TPFLAGS_SEQUENCE)
+ str << " [sequence]";
+# endif // !Py_LIMITED_API
+# endif // 3.10
+ if (obj->tp_basicsize != 0)
+ str << ", basicsize=" << obj->tp_basicsize;
+ if (verbose) {
+ formatTypeTuple(obj->tp_bases, "bases", str);
+ formatTypeTuple(obj->tp_mro, "mro", str);
+ if (!immutableType) {
+ auto *underlying = reinterpret_cast<const PyObject *>(obj)->ob_type;
+ if (underlying != nullptr && underlying != obj) {
+ str << ", underlying=\"" << underlying->tp_name << '"';
+ }
+ }
+ }
+ }
+}
+
+static void formatTypeTuple(PyObject *t, const char *what, std::ostream &str)
+{
+ const Py_ssize_t size = t != nullptr && PyTuple_Check(t) != 0 ? PyTuple_Size(t) : 0;
+ if (size > 0) {
+ str << ", " << what << "=[" << size << "]{";
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ if (i != 0)
+ str << ", ";
+ Shiboken::AutoDecRef item(PyTuple_GetItem(t, i));
+ if (item.isNull())
+ str << '0'; // Observed with non-ready types
+ else
+ str << '"' << reinterpret_cast<PyTypeObject *>(item.object())->tp_name << '"';
+ }
+ str << '}';
+ }
+}
+
+static void formatPyObject(PyObject *obj, std::ostream &str);
+
+static void formatPySequence(PyObject *obj, std::ostream &str)
+{
+ const Py_ssize_t size = PySequence_Size(obj);
+ const Py_ssize_t printSize = std::min(size, Py_ssize_t(5));
+ str << size << " <";
+ for (Py_ssize_t i = 0; i < printSize; ++i) {
+ if (i)
+ str << ", ";
+ str << '(';
+ PyObject *item = PySequence_GetItem(obj, i);
+ formatPyObject(item, str);
+ str << ')';
+ Py_XDECREF(item);
+ }
+ if (printSize < size)
+ str << ",...";
+ str << '>';
+}
+
+static void formatPyTuple(PyObject *obj, std::ostream &str)
+{
+
+ const Py_ssize_t size = PyTuple_Size(obj);
+ str << size << " <";
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ if (i)
+ str << ", ";
+ str << '(';
+ PyObject *item = PyTuple_GetItem(obj, i);
+ formatPyObject(item, str);
+ str << ')';
+ Py_XDECREF(item);
+ }
+ str << '>';
+}
+
+static void formatPyDict(PyObject *obj, std::ostream &str)
+{
+ PyObject *key;
+ PyObject *value;
+ Py_ssize_t pos = 0;
+ str << '{';
+ while (PyDict_Next(obj, &pos, &key, &value) != 0) {
+ if (pos)
+ str << ", ";
+ str << Shiboken::debugPyObject(key) << '=' << Shiboken::debugPyObject(value);
+ }
+ str << '}';
+}
+
+// Helper to format a 0-terminated character sequence
+template <class Char>
+static void formatCharSequence(const Char *s, std::ostream &str)
+{
+ str << '"';
+ const auto oldFillC = str.fill('0');
+ str << std::hex;
+ for (; *s; ++s) {
+ const unsigned c = *s;
+ if (c < 127)
+ str << char(c);
+ else
+ str << "0x" << std::right << std::setw(sizeof(Char) * 2) << c << std::left;
+ }
+ str << std::dec;
+ str.fill(oldFillC);
+ str << '"';
+}
+
+static void formatPyUnicode(PyObject *obj, std::ostream &str)
+{
+ // Note: The below call create the PyCompactUnicodeObject.utf8 representation
+ str << '"' << _PepUnicode_AsString(obj) << '"';
+ if (!verbose)
+ return;
+
+ str << " (" << PyUnicode_GetLength(obj) << ')';
+ const auto kind = _PepUnicode_KIND(obj);
+ switch (kind) {
+#if PY_VERSION_HEX < 0x030C0000
+ case PepUnicode_WCHAR_KIND:
+ str << " [wchar]";
+ break;
+#endif
+ case PepUnicode_1BYTE_KIND:
+ str << " [1byte]";
+ break;
+ case PepUnicode_2BYTE_KIND:
+ str << " [2byte]";
+ break;
+ case PepUnicode_4BYTE_KIND:
+ str << " [4byte]";
+ break;
+ }
+
+ const bool ascii = _PepUnicode_IS_ASCII(obj);
+ if (ascii)
+ str << " [ascii]";
+ const bool compact = _PepUnicode_IS_COMPACT(obj);
+ if (compact)
+ str << " [compact]";
+ void *data =_PepUnicode_DATA(obj);
+ str << ", data=";
+ switch (kind) {
+#if PY_VERSION_HEX < 0x030C0000
+ case PepUnicode_WCHAR_KIND:
+ formatCharSequence(reinterpret_cast<const wchar_t *>(data), str);
+#endif
+ break;
+ case PepUnicode_1BYTE_KIND:
+ formatCharSequence(reinterpret_cast<const Py_UCS1 *>(data), str);
+ break;
+ case PepUnicode_2BYTE_KIND:
+ formatCharSequence(reinterpret_cast<const Py_UCS2 *>(data), str);
+ break;
+ case PepUnicode_4BYTE_KIND:
+ formatCharSequence(reinterpret_cast<const Py_UCS4 *>(data), str);
+ break;
+ }
+
+#ifndef Py_LIMITED_API
+ const char *utf8 = nullptr;
+ if (!ascii && compact && kind == PepUnicode_1BYTE_KIND) {
+ const auto *compactObj = reinterpret_cast<const PyCompactUnicodeObject *>(obj);
+ if (compactObj->utf8_length)
+ utf8 = compactObj->utf8;
+ }
+ if (utf8) {
+ str << ", utf8=";
+ formatCharSequence(reinterpret_cast<const Py_UCS1 *>(utf8), str);
+ } else {
+ str << ", no-utf8";
+ }
+#endif // !Py_LIMITED_API
+}
+
+static std::string getQualName(PyObject *obj)
+{
+ Shiboken::AutoDecRef result(PyObject_GetAttr(obj, Shiboken::PyMagicName::qualname()));
+ return result.object() != nullptr
+ ? _PepUnicode_AsString(result.object()) : std::string{};
+}
+
+static void formatPyFunction(PyObject *obj, std::ostream &str)
+{
+ str << '"' << getQualName(obj) << "()\"";
+}
+
+static void formatPyMethod(PyObject *obj, std::ostream &str)
+{
+ if (auto *func = PyMethod_Function(obj))
+ formatPyFunction(func, str);
+ str << ", instance=" << PyMethod_Self(obj);
+}
+
+static void formatPyCodeObject(PyObject *obj, std::ostream &str)
+{
+ if (auto name = getStringAttr(obj, "co_name"))
+ str << '"' << name.value() << '"';
+ if (auto qualName = getStringAttr(obj, "co_qualname"))
+ str << ", co_qualname=\"" << qualName.value() << '"';
+ if (auto flags = getIntAttr(obj, "co_flags"))
+ str << ", flags=0x" << std::hex << flags.value() << std::dec;
+ if (auto c = getIntAttr(obj, "co_argcount"))
+ str << ", co_argcounts=" << c.value();
+ if (auto c = getIntAttr(obj, "co_posonlyargcount"))
+ str << ", co_posonlyargcount=" << c.value();
+ if (auto c = getIntAttr(obj, "co_kwonlyargcount"))
+ str << ", co_kwonlyargcount=" << c.value();
+ if (auto fileName = getStringAttr(obj, "co_filename")) {
+ str << " @" << fileName.value();
+ if (auto l = getIntAttr(obj, "co_firstlineno"))
+ str << ':'<< l.value();
+ }
+}
+
+static void formatPyObjectHelper(PyObject *obj, std::ostream &str)
+{
+ str << ", ";
+ if (obj == Py_None) {
+ str << "None";
+ return;
+ }
+ if (obj == Py_True) {
+ str << "True";
+ return;
+ }
+ if (obj == Py_False) {
+ str << "False";
+ return;
+ }
+ const auto refs = Py_REFCNT(obj);
+ if (refs == UINT_MAX) // _Py_IMMORTAL_REFCNT
+ str << "immortal, ";
+ else
+ str << "refs=" << refs << ", ";
+ if (PyType_Check(obj)) {
+ str << "type: ";
+ formatPyTypeObject(reinterpret_cast<PyTypeObject *>(obj), str, true);
+ return;
+ }
+ formatPyTypeObject(obj->ob_type, str, false);
+ str << ", ";
+ if (PyLong_Check(obj)) {
+ const auto llv = PyLong_AsLongLong(obj);
+ if (PyErr_Occurred() != PyExc_OverflowError) {
+ str << llv;
+ } else {
+ PyErr_Clear();
+ str << "0x" << std::hex << PyLong_AsUnsignedLongLong(obj) << std::dec;
+ }
+ }
+ else if (PyFloat_Check(obj))
+ str << PyFloat_AsDouble(obj);
+ else if (PyUnicode_Check(obj))
+ formatPyUnicode(obj, str);
+ else if (PyFunction_Check(obj) != 0)
+ formatPyFunction(obj, str);
+ else if (PyMethod_Check(obj) != 0)
+ formatPyMethod(obj, str);
+ else if (PepCode_Check(obj) != 0)
+ formatPyCodeObject(obj, str);
+ else if (PySequence_Check(obj))
+ formatPySequence(obj, str);
+ else if (PyDict_Check(obj))
+ formatPyDict(obj, str);
+ else if (PyTuple_CheckExact(obj))
+ formatPyTuple(obj, str);
+ else
+ str << "<unknown>";
+}
+
+static void formatPyObject(PyObject *obj, std::ostream &str)
+{
+ str << obj;
+ if (obj)
+ formatPyObjectHelper(obj, str);
+}
+
+namespace Shiboken
+{
+
+debugPyObject::debugPyObject(PyObject *o) : m_object(o)
+{
+}
+
+debugSbkObject::debugSbkObject(SbkObject *o) : m_object(o)
+{
+}
+
+debugPyTypeObject::debugPyTypeObject(const PyTypeObject *o) : m_object(o)
+{
+}
+
+debugPyBuffer::debugPyBuffer(const Py_buffer &b) : m_buffer(b)
+{
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyTypeObject &o)
+{
+ str << "PyTypeObject(";
+ formatPyTypeObject(o.m_object, str, true);
+ str << ')';
+ return str;
+}
+
+std::ostream &operator<<(std::ostream &str, const debugSbkObject &o)
+{
+ str << "SbkObject(" << o.m_object;
+ if (o.m_object) {
+ Shiboken::Object::_debugFormat(str, o.m_object);
+ formatPyObjectHelper(reinterpret_cast<PyObject *>(o.m_object), str);
+ }
+ str << ')';
+ return str;
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyObject &o)
+{
+ str << "PyObject(";
+ formatPyObject(o.m_object, str);
+ str << ')';
+ return str;
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyBuffer &b)
+{
+ str << "PyBuffer(buf=" << b.m_buffer.buf << ", len="
+ << b.m_buffer.len << ", itemsize=" << b.m_buffer.itemsize
+ << ", readonly=" << b.m_buffer.readonly << ", ndim=" << b.m_buffer.ndim;
+ if (b.m_buffer.format)
+ str << ", format=\"" << b.m_buffer.format << '"';
+ str << ", shape=" << b.m_buffer.shape << ", strides=" << b.m_buffer.strides
+ << ", suboffsets=" << b.m_buffer.suboffsets << ')';
+ return str;
+}
+
+std::ios_base &debugVerbose(std::ios_base &s)
+{
+ verbose = true;
+ return s;
+}
+
+std::ios_base &debugBrief(std::ios_base &s)
+{
+ verbose = false;
+ return s;
+}
+
+#ifdef _WIN32
+// Converts a Unicode string to a string encoded in the Windows console's
+// code page via wchar_t for use with argv (PYSIDE-1425).
+// FIXME: Remove once Windows console uses UTF-8
+static char *toWindowsConsoleEncoding(PyObject *unicode)
+{
+ wchar_t *buf = PyUnicode_AsWideCharString(unicode, nullptr);
+ if (buf == nullptr)
+ return nullptr;
+ const int required = WideCharToMultiByte(CP_ACP, 0, buf, -1,
+ nullptr, 0, nullptr, nullptr);
+ if (required == 0) {
+ PyMem_Free(buf);
+ return nullptr;
+ }
+ char *result = new char[required];
+ WideCharToMultiByte(CP_ACP, 0, buf, -1,
+ result, required, nullptr, nullptr);
+ PyMem_Free(buf);
+ return result;
+}
+#endif // _WIN32
+
+// PySide-510: Changed from PySequence to PyList, which is correct.
+bool listToArgcArgv(PyObject *argList, int *argc, char ***argv, const char *defaultAppName)
+{
+ if (!PyList_Check(argList))
+ return false;
+
+ if (!defaultAppName)
+ defaultAppName = "PySideApplication";
+
+ // Check all items
+ Shiboken::AutoDecRef args(PySequence_Fast(argList, nullptr));
+ int numArgs = int(PySequence_Fast_GET_SIZE(argList));
+ for (int i = 0; i < numArgs; ++i) {
+ PyObject *item = PyList_GET_ITEM(args.object(), i);
+ if (!PyBytes_Check(item) && !PyUnicode_Check(item))
+ return false;
+ }
+
+ bool hasEmptyArgList = numArgs == 0;
+ if (hasEmptyArgList)
+ numArgs = 1;
+
+ *argc = numArgs;
+ *argv = new char *[*argc];
+
+ if (hasEmptyArgList) {
+ // Try to get the script name
+ PyObject *globals = PyEval_GetGlobals();
+ PyObject *appName = PyDict_GetItem(globals, Shiboken::PyMagicName::file());
+ (*argv)[0] = strdup(appName ? Shiboken::String::toCString(appName) : defaultAppName);
+ } else {
+ for (int i = 0; i < numArgs; ++i) {
+ PyObject *item = PyList_GET_ITEM(args.object(), i);
+ char *string = nullptr;
+ if (Shiboken::String::check(item)) {
+#ifdef _WIN32
+ string = toWindowsConsoleEncoding(item);
+#else
+ string = strdup(Shiboken::String::toCString(item));
+#endif
+ }
+ (*argv)[i] = string;
+ }
+ }
+
+ return true;
+}
+
+int *sequenceToIntArray(PyObject *obj, bool zeroTerminated)
+{
+ AutoDecRef seq(PySequence_Fast(obj, "Sequence of ints expected"));
+ if (seq.isNull())
+ return nullptr;
+
+ Py_ssize_t size = PySequence_Fast_GET_SIZE(seq.object());
+ int *array = new int[size + (zeroTerminated ? 1 : 0)];
+
+ for (int i = 0; i < size; i++) {
+ PyObject *item = PySequence_Fast_GET_ITEM(seq.object(), i);
+ if (!PyLong_Check(item)) {
+ PyErr_SetString(PyExc_TypeError, "Sequence of ints expected");
+ delete[] array;
+ return nullptr;
+ }
+ array[i] = PyLong_AsLong(item);
+ }
+
+ if (zeroTerminated)
+ array[size] = 0;
+
+ return array;
+}
+
+
+int warning(PyObject *category, int stacklevel, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+#ifdef _WIN32
+ va_list args2 = args;
+#else
+ va_list args2;
+ va_copy(args2, args);
+#endif
+
+ // check the necessary memory
+ int size = vsnprintf(nullptr, 0, format, args) + 1;
+ auto message = new char[size];
+ int result = 0;
+ if (message) {
+ // format the message
+ vsnprintf(message, size, format, args2);
+ result = PyErr_WarnEx(category, message, stacklevel);
+ delete [] message;
+ }
+ va_end(args2);
+ va_end(args);
+ return result;
+}
+
+ThreadId currentThreadId()
+{
+#if defined(_WIN32)
+ return GetCurrentThreadId();
+#elif defined(__APPLE_CC__)
+ return reinterpret_cast<ThreadId>(pthread_self());
+#else
+ return pthread_self();
+#endif
+}
+
+// Internal, used by init() from main thread
+static ThreadId _mainThreadId{0};
+void _initMainThreadId() { _mainThreadId = currentThreadId(); }
+
+ThreadId mainThreadId()
+{
+ return _mainThreadId;
+}
+
+const char *typeNameOf(const char *typeIdName)
+{
+ auto size = std::strlen(typeIdName);
+#if defined(Q_CC_MSVC) // MSVC: "class QPaintDevice * __ptr64"
+ if (auto *lastStar = strchr(typeName, '*')) {
+ // MSVC: "class QPaintDevice * __ptr64"
+ while (*--lastStar == ' ') {
+ }
+ size = lastStar - typeName + 1;
+ }
+#else // g++, Clang: "QPaintDevice *" -> "P12QPaintDevice"
+ if (size > 2 && typeIdName[0] == 'P' && std::isdigit(typeIdName[1])) {
+ ++typeIdName;
+ --size;
+ }
+#endif
+ char *result = new char[size + 1];
+ result[size] = '\0';
+ std::memcpy(result, typeIdName, size);
+ return result;
+}
+
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030A0000 && !defined(PYPY_VERSION)
+static int _getPyVerbose()
+{
+ PyConfig config;
+ PyConfig_InitPythonConfig(&config);
+ return config.verbose;
+}
+#endif // !Py_LIMITED_API >= 3.10
+
+int pyVerbose()
+{
+#ifdef Py_LIMITED_API
+ return Pep_GetVerboseFlag();
+#elif PY_VERSION_HEX >= 0x030A0000 && !defined(PYPY_VERSION)
+ static const int result = _getPyVerbose();
+ return result;
+#else
+ return Py_VerboseFlag;
+#endif
+}
+
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/helper.h b/sources/shiboken6/libshiboken/helper.h
new file mode 100644
index 000000000..f226e8c24
--- /dev/null
+++ b/sources/shiboken6/libshiboken/helper.h
@@ -0,0 +1,120 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef HELPER_H
+#define HELPER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+#include "autodecref.h"
+
+#include <iosfwd>
+
+#define SBK_UNUSED(x) (void)(x);
+
+namespace Shiboken
+{
+
+/**
+* It transforms a python sequence into two C variables, argc and argv.
+* This function tries to find the application (script) name and put it into argv[0], if
+* the application name can't be guessed, defaultAppName will be used.
+*
+* No memory is allocated is an error occur.
+*
+* \note argc must be a valid address.
+* \note The argv array is allocated using new operator and each item is allocated using malloc.
+* \returns True on sucess, false otherwise.
+*/
+LIBSHIBOKEN_API bool listToArgcArgv(PyObject *argList, int *argc, char ***argv, const char *defaultAppName = nullptr);
+
+/**
+ * Convert a python sequence into a heap-allocated array of ints.
+ *
+ * \returns The newly allocated array or NULL in case of error or empty sequence. Check with PyErr_Occurred
+ * if it was successfull.
+ */
+LIBSHIBOKEN_API int *sequenceToIntArray(PyObject *obj, bool zeroTerminated = false);
+
+/// Fix a type name returned by typeid(t).name(), depending on compiler.
+/// \returns Fixed name (allocated).
+LIBSHIBOKEN_API const char *typeNameOf(const char *typeIdName);
+
+/**
+ * Creates and automatically deallocates C++ arrays.
+ */
+template<class T>
+class AutoArrayPointer
+{
+ public:
+ AutoArrayPointer(const AutoArrayPointer &) = delete;
+ AutoArrayPointer(AutoArrayPointer &&) = delete;
+ AutoArrayPointer &operator=(const AutoArrayPointer &) = delete;
+ AutoArrayPointer &operator=(AutoArrayPointer &&) = delete;
+
+
+ explicit AutoArrayPointer(Py_ssize_t size) { data = new T[size]; }
+ T &operator[](Py_ssize_t pos) { return data[pos]; }
+ operator T *() const { return data; }
+ ~AutoArrayPointer() { delete[] data; }
+ private:
+ T *data;
+};
+
+using ThreadId = unsigned long long;
+LIBSHIBOKEN_API ThreadId currentThreadId();
+LIBSHIBOKEN_API ThreadId mainThreadId();
+
+LIBSHIBOKEN_API int pyVerbose();
+
+/**
+ * An utility function used to call PyErr_WarnEx with a formatted message.
+ */
+LIBSHIBOKEN_API int warning(PyObject *category, int stacklevel, const char *format, ...);
+
+struct LIBSHIBOKEN_API debugPyObject
+{
+ explicit debugPyObject(PyObject *o);
+
+ PyObject *m_object;
+};
+
+struct LIBSHIBOKEN_API debugSbkObject
+{
+ explicit debugSbkObject(SbkObject *o);
+
+ SbkObject *m_object;
+};
+
+struct LIBSHIBOKEN_API debugPyTypeObject
+{
+ explicit debugPyTypeObject(const PyTypeObject *o);
+
+ const PyTypeObject *m_object;
+};
+
+struct LIBSHIBOKEN_API debugPyBuffer
+{
+ explicit debugPyBuffer(const Py_buffer &b);
+
+ const Py_buffer &m_buffer;
+};
+
+struct debugPyArrayObject
+{
+ explicit debugPyArrayObject(PyObject *object) : m_object(object) {}
+
+ PyObject *m_object;
+};
+
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyObject &o);
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugSbkObject &o);
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyTypeObject &o);
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyBuffer &b);
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyArrayObject &b);
+LIBSHIBOKEN_API std::ios_base &debugVerbose(std::ios_base &s);
+LIBSHIBOKEN_API std::ios_base &debugBrief(std::ios_base &s);
+} // namespace Shiboken
+
+
+#endif // HELPER_H
diff --git a/sources/shiboken6/libshiboken/pep384ext.h b/sources/shiboken6/libshiboken/pep384ext.h
new file mode 100644
index 000000000..021c53d16
--- /dev/null
+++ b/sources/shiboken6/libshiboken/pep384ext.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PEP384EXT_H
+#define PEP384EXT_H
+
+#include "pep384impl.h"
+
+/// Returns the allocator slot of the PyTypeObject.
+inline allocfunc PepExt_Type_GetAllocSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<allocfunc>(PepType_GetSlot(t, Py_tp_alloc));
+}
+
+/// Invokes the allocator slot of the PyTypeObject.
+template <class Type>
+inline Type *PepExt_TypeCallAlloc(PyTypeObject *t, Py_ssize_t nitems)
+{
+ PyObject *result = PepExt_Type_GetAllocSlot(t)(t, nitems);
+ return reinterpret_cast<Type *>(result);
+}
+
+/// Returns the getattro slot of the PyTypeObject.
+inline getattrofunc PepExt_Type_GetGetAttroSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<getattrofunc>(PepType_GetSlot(t, Py_tp_getattro));
+}
+
+/// Returns the setattro slot of the PyTypeObject.
+inline setattrofunc PepExt_Type_GetSetAttroSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<setattrofunc>(PepType_GetSlot(t, Py_tp_setattro));
+}
+
+/// Returns the descr_get slot of the PyTypeObject.
+inline descrgetfunc PepExt_Type_GetDescrGetSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<descrgetfunc>(PepType_GetSlot(t, Py_tp_descr_get));
+}
+
+/// Invokes the descr_get slot of the PyTypeObject.
+inline PyObject *PepExt_Type_CallDescrGet(PyObject *self, PyObject *obj, PyObject *type)
+{
+ return PepExt_Type_GetDescrGetSlot(Py_TYPE(self))(self, obj, type);
+}
+
+/// Returns the descr_set slot of the PyTypeObject.
+inline descrsetfunc PepExt_Type_GetDescrSetSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<descrsetfunc>(PepType_GetSlot(t, Py_tp_descr_set));
+}
+
+/// Returns the call slot of the PyTypeObject.
+inline ternaryfunc PepExt_Type_GetCallSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<ternaryfunc>(PepType_GetSlot(t, Py_tp_call));
+}
+
+/// Returns the new slot of the PyTypeObject.
+inline newfunc PepExt_Type_GetNewSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<newfunc>(PepType_GetSlot(t, Py_tp_new));
+}
+
+/// Returns the init slot of the PyTypeObject.
+inline initproc PepExt_Type_GetInitSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<initproc>(PepType_GetSlot(t, Py_tp_init));
+}
+
+/// Returns the free slot of the PyTypeObject.
+inline freefunc PepExt_Type_GetFreeSlot(PyTypeObject *t)
+{
+ return reinterpret_cast<freefunc>(PepType_GetSlot(t, Py_tp_free));
+}
+
+/// Invokes the free slot of the PyTypeObject.
+inline void PepExt_TypeCallFree(PyTypeObject *t, void *object)
+{
+ PepExt_Type_GetFreeSlot(t)(object);
+}
+
+/// Invokes the free slot of the PyTypeObject.
+inline void PepExt_TypeCallFree(PyObject *object)
+{
+ PepExt_Type_GetFreeSlot(Py_TYPE(object))(object);
+}
+
+#endif // PEP384EXT_H
diff --git a/sources/shiboken6/libshiboken/pep384impl.cpp b/sources/shiboken6/libshiboken/pep384impl.cpp
new file mode 100644
index 000000000..5310207a3
--- /dev/null
+++ b/sources/shiboken6/libshiboken/pep384impl.cpp
@@ -0,0 +1,1319 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define PEP384_INTERN
+
+#include "sbkpython.h"
+#include "autodecref.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+#include "sbkenum.h"
+#include "voidptr.h"
+
+#include <cstdlib>
+#include <cstring>
+
+extern "C"
+{
+
+/*
+ * The documentation is located in `sources/pyside6/doc/developer/limited_api.rst`.
+
+ * Here is the verification code for PyTypeObject.
+ * We create a type object and check if its fields
+ * appear at the right offsets.
+ */
+#ifdef Py_LIMITED_API
+
+#define make_dummy_int(x) (x * sizeof(void *))
+#define make_dummy(x) (reinterpret_cast<void *>(make_dummy_int(x)))
+
+static PyObject *
+dummy_func(PyObject * /* self */, PyObject * /* args */)
+{
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef probe_methoddef[] = {
+ {"dummy", dummy_func, METH_NOARGS, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+static PyGetSetDef probe_getseters[] = {
+ {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
+};
+
+static PyMemberDef probe_members[] = {
+ {nullptr, 0, 0, 0, nullptr} /* Sentinel */
+};
+
+#define probe_tp_dealloc make_dummy(1)
+#define probe_tp_repr make_dummy(2)
+#define probe_tp_call make_dummy(3)
+#define probe_tp_getattro make_dummy(16)
+#define probe_tp_setattro make_dummy(17)
+#define probe_tp_str make_dummy(4)
+#define probe_tp_traverse make_dummy(5)
+#define probe_tp_clear make_dummy(6)
+#define probe_tp_iternext make_dummy(7)
+#define probe_tp_methods probe_methoddef
+#define probe_tp_members probe_members
+#define probe_tp_getset probe_getseters
+#define probe_tp_descr_get make_dummy(10)
+#define probe_tp_descr_set make_dummy(18)
+#define probe_tp_init make_dummy(11)
+#define probe_tp_alloc make_dummy(12)
+#define probe_tp_new make_dummy(13)
+#define probe_tp_free make_dummy(14)
+#define probe_tp_is_gc make_dummy(15)
+
+#define probe_tp_name "type.probe"
+#define probe_tp_basicsize make_dummy_int(42)
+
+static PyType_Slot typeprobe_slots[] = {
+ {Py_tp_dealloc, probe_tp_dealloc},
+ {Py_tp_repr, probe_tp_repr},
+ {Py_tp_call, probe_tp_call},
+ {Py_tp_getattro, probe_tp_getattro},
+ {Py_tp_setattro, probe_tp_setattro},
+ {Py_tp_str, probe_tp_str},
+ {Py_tp_traverse, probe_tp_traverse},
+ {Py_tp_clear, probe_tp_clear},
+ {Py_tp_iternext, probe_tp_iternext},
+ {Py_tp_methods, probe_tp_methods},
+ {Py_tp_members, probe_tp_members},
+ {Py_tp_getset, probe_tp_getset},
+ {Py_tp_descr_get, probe_tp_descr_get},
+ {Py_tp_descr_set, probe_tp_descr_set},
+ {Py_tp_init, probe_tp_init},
+ {Py_tp_alloc, probe_tp_alloc},
+ {Py_tp_new, probe_tp_new},
+ {Py_tp_free, probe_tp_free},
+ {Py_tp_is_gc, probe_tp_is_gc},
+ {0, nullptr}
+};
+static PyType_Spec typeprobe_spec = {
+ probe_tp_name,
+ probe_tp_basicsize,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ typeprobe_slots,
+};
+
+static void
+check_PyTypeObject_valid()
+{
+ 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 *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());
+ long probe_tp_dictoffset = PyLong_AsLong(d);
+ PyObject *probe_tp_mro = PyObject_GetAttr(obtype, Shiboken::PyMagicName::mro());
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(check));
+ auto *checkDict = tpDict.object();
+ if (false
+ || strcmp(probe_tp_name, check->tp_name) != 0
+ || probe_tp_basicsize != check->tp_basicsize
+ || probe_tp_dealloc != check->tp_dealloc
+ || probe_tp_repr != check->tp_repr
+ || probe_tp_call != check->tp_call
+ || probe_tp_getattro != check->tp_getattro
+ || probe_tp_setattro != check->tp_setattro
+ || probe_tp_str != check->tp_str
+ || probe_tp_traverse != check->tp_traverse
+ || probe_tp_clear != check->tp_clear
+ || probe_tp_weakrefoffset != typetype->tp_weaklistoffset
+ || probe_tp_iternext != check->tp_iternext
+ || probe_tp_methods != check->tp_methods
+ || probe_tp_getset != check->tp_getset
+ || probe_tp_base != typetype->tp_base
+ || !PyDict_Check(checkDict)
+ || !PyDict_GetItemString(checkDict, "dummy")
+ || probe_tp_descr_get != check->tp_descr_get
+ || probe_tp_descr_set != check->tp_descr_set
+ || probe_tp_dictoffset != typetype->tp_dictoffset
+ || probe_tp_init != check->tp_init
+ || probe_tp_alloc != check->tp_alloc
+ || probe_tp_new != check->tp_new
+ || probe_tp_free != check->tp_free
+ || probe_tp_is_gc != check->tp_is_gc
+ || probe_tp_bases != typetype->tp_bases
+ || 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(checkObj);
+ Py_DECREF(probe_tp_base_obj);
+ Py_DECREF(w);
+ Py_DECREF(d);
+ Py_DECREF(probe_tp_bases);
+ Py_DECREF(probe_tp_mro);
+}
+
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Additional for object.h / class properties
+ *
+ */
+#ifdef Py_LIMITED_API
+/*
+ * This implementation of `_PyType_Lookup` works for lookup in our classes.
+ * The implementation ignores all caching and versioning and is also
+ * less optimized. This is reduced from the Python implementation.
+ */
+
+/* Internal API to look for a name through the MRO, bypassing the method cache.
+ This returns a borrowed reference, and might set an exception.
+ 'error' is set to: -1: error with exception; 1: error without exception; 0: ok */
+static PyObject *
+find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
+{
+ Py_ssize_t i, n;
+ PyObject *mro, *res, *base;
+
+ /* Look in tp_dict of types in MRO */
+ mro = type->tp_mro;
+
+ res = nullptr;
+ /* Keep a strong reference to mro because type->tp_mro can be replaced
+ during dict lookup, e.g. when comparing to non-string keys. */
+ Py_INCREF(mro);
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ base = PyTuple_GET_ITEM(mro, i);
+ assert(PyType_Check(base));
+ auto *type = reinterpret_cast<PyTypeObject *>(base);
+ Shiboken::AutoDecRef dict(PepType_GetDict(type));
+ assert(!dict.isNull() && PyDict_Check(dict.object()));
+ res = PyDict_GetItem(dict.object(), name);
+ if (res != nullptr)
+ break;
+ if (PyErr_Occurred()) {
+ *error = -1;
+ goto done;
+ }
+ }
+ *error = 0;
+done:
+ Py_DECREF(mro);
+ return res;
+}
+
+/* Internal API to look for a name through the MRO.
+ This returns a borrowed reference, and doesn't set an exception! */
+PyObject *
+_PepType_Lookup(PyTypeObject *type, PyObject *name)
+{
+ PyObject *res;
+ int error;
+
+ /* We may end up clearing live exceptions below, so make sure it's ours. */
+ assert(!PyErr_Occurred());
+
+ res = find_name_in_mro(type, name, &error);
+ /* Only put NULL results into cache if there was no error. */
+ if (error) {
+ /* It's not ideal to clear the error condition,
+ but this function is documented as not setting
+ an exception, and I don't want to change that.
+ E.g., when PyType_Ready() can't proceed, it won't
+ set the "ready" flag, so future attempts to ready
+ the same type will call it again -- hopefully
+ in a context that propagates the exception out.
+ */
+ if (error == -1) {
+ PyErr_Clear();
+ }
+ return nullptr;
+ }
+ return res;
+}
+
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for unicodeobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+// structs and macros modelled after their equivalents in
+// cpython/Include/cpython/unicodeobject.h
+
+struct PepASCIIObject // since 3.12
+{
+ PyObject_HEAD
+ Py_ssize_t length; /* Number of code points in the string */
+ Py_hash_t hash; /* Hash value; -1 if not set */
+ struct {
+ unsigned int interned:2;
+ unsigned int kind:3;
+ unsigned int compact:1;
+ unsigned int ascii:1;
+ unsigned int ready:1;
+ unsigned int :24;
+ } state;
+};
+
+struct PepASCIIObject_311 : public PepASCIIObject
+{
+ wchar_t *wstr; /* wchar_t representation (null-terminated) */
+};
+
+struct PepCompactUnicodeObject // since 3.12
+{
+ PepASCIIObject _base;
+ Py_ssize_t utf8_length;
+ char *utf8; /* UTF-8 representation (null-terminated) */
+};
+
+struct PepCompactUnicodeObject_311 // since 3.12
+{
+ PepASCIIObject_311 _base;
+ Py_ssize_t utf8_length;
+ char *utf8; /* UTF-8 representation (null-terminated) */
+ Py_ssize_t wstr_length; /* Number of code points in wstr */
+};
+
+struct PepUnicodeObject // since 3.12
+{
+ PepCompactUnicodeObject _base;
+ union {
+ void *any;
+ Py_UCS1 *latin1;
+ Py_UCS2 *ucs2;
+ Py_UCS4 *ucs4;
+ } data; /* Canonical, smallest-form Unicode buffer */
+};
+
+struct PepUnicodeObject_311
+{
+ PepCompactUnicodeObject_311 _base;
+ union {
+ void *any;
+ Py_UCS1 *latin1;
+ Py_UCS2 *ucs2;
+ Py_UCS4 *ucs4;
+ } data; /* Canonical, smallest-form Unicode buffer */
+};
+
+int _PepUnicode_KIND(PyObject *str)
+{
+ return reinterpret_cast<PepASCIIObject *>(str)->state.kind;
+}
+
+int _PepUnicode_IS_ASCII(PyObject *str)
+{
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ return asciiObj->state.ascii;
+}
+
+int _PepUnicode_IS_COMPACT(PyObject *str)
+{
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ return asciiObj->state.compact;
+}
+
+static void *_PepUnicode_ASCII_DATA(PyObject *str)
+{
+ if (_PepRuntimeVersion() < 0x030C00) {
+ auto *asciiObj_311 = reinterpret_cast<PepASCIIObject_311 *>(str);
+ return asciiObj_311 + 1;
+ }
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ return asciiObj + 1;
+}
+
+static void *_PepUnicode_COMPACT_DATA(PyObject *str)
+{
+ if (_PepUnicode_IS_ASCII(str) != 0)
+ return _PepUnicode_ASCII_DATA(str);
+ if (_PepRuntimeVersion() < 0x030C00) {
+ auto *compactObj_311 = reinterpret_cast<PepCompactUnicodeObject_311 *>(str);
+ return compactObj_311 + 1;
+ }
+ auto *compactObj = reinterpret_cast<PepCompactUnicodeObject *>(str);
+ return compactObj + 1;
+}
+
+static void *_PepUnicode_NONCOMPACT_DATA(PyObject *str)
+{
+ return _PepRuntimeVersion() < 0x030C00
+ ? reinterpret_cast<PepUnicodeObject_311 *>(str)->data.any
+ : reinterpret_cast<PepUnicodeObject *>(str)->data.any;
+}
+
+void *_PepUnicode_DATA(PyObject *str)
+{
+ return _PepUnicode_IS_COMPACT(str)
+ ? _PepUnicode_COMPACT_DATA(str) : _PepUnicode_NONCOMPACT_DATA(str);
+}
+
+// Fast path accessing UTF8 data without doing a conversion similar
+// to _PyUnicode_AsUTF8String
+static const char *utf8FastPath_311(PyObject *str)
+{
+ if (PyUnicode_GetLength(str) == 0)
+ return "";
+ auto *asciiObj = reinterpret_cast<PepASCIIObject_311 *>(str);
+ if (asciiObj->state.kind != PepUnicode_1BYTE_KIND || asciiObj->state.compact == 0)
+ return nullptr; // Empirical: PyCompactUnicodeObject.utf8 is only valid for 1 byte
+ if (asciiObj->state.ascii) {
+ auto *data = asciiObj + 1;
+ return reinterpret_cast<const char *>(data);
+ }
+ auto *compactObj = reinterpret_cast<PepCompactUnicodeObject_311 *>(str);
+ if (compactObj->utf8_length)
+ return compactObj->utf8;
+ return nullptr;
+}
+
+static const char *utf8FastPath(PyObject *str)
+{
+ if (PyUnicode_GetLength(str) == 0)
+ return "";
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ if (asciiObj->state.kind != PepUnicode_1BYTE_KIND || asciiObj->state.compact == 0)
+ return nullptr; // Empirical: PyCompactUnicodeObject.utf8 is only valid for 1 byte
+ if (asciiObj->state.ascii) {
+ auto *data = asciiObj + 1;
+ return reinterpret_cast<const char *>(data);
+ }
+ auto *compactObj = reinterpret_cast<PepCompactUnicodeObject *>(str);
+ if (compactObj->utf8_length)
+ return compactObj->utf8;
+ return nullptr;
+}
+
+const char *_PepUnicode_AsString(PyObject *str)
+{
+ /*
+ * This function is the surrogate for PyUnicode_AsUTF8, which keeps the data
+ * in the unicode object as long as that object exists.
+ *
+ * The function does too much if not optimized by utf8, because it keeps the
+ * string alive, unconditionally.
+ * We should not rely on this behavior and think of PyUnicode_AsUTF8, only.
+ */
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define AT __FILE__ ":" TOSTRING(__LINE__)
+
+ if (const auto *utf8 = _PepRuntimeVersion() < 0x030C00
+ ? utf8FastPath_311(str) : utf8FastPath(str)) {
+ return utf8;
+ }
+
+ static PyObject *cstring_dict = nullptr;
+ if (cstring_dict == nullptr) {
+ cstring_dict = PyDict_New();
+ if (cstring_dict == nullptr)
+ Py_FatalError("Error in " AT);
+ }
+ PyObject *bytesStr = PyUnicode_AsEncodedString(str, "utf8", nullptr);
+ PyObject *entry = PyDict_GetItemWithError(cstring_dict, bytesStr);
+ if (entry == nullptr) {
+ int e = PyDict_SetItem(cstring_dict, bytesStr, bytesStr);
+ if (e != 0)
+ Py_FatalError("Error in " AT);
+ entry = bytesStr;
+ }
+ else
+ Py_DECREF(bytesStr);
+ return PyBytes_AsString(entry);
+}
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for pydebug.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+static PyObject *sys_flags = nullptr;
+
+int
+Pep_GetFlag(const char *name)
+{
+ static int initialized = 0;
+ int ret = -1;
+
+ if (!initialized) {
+ sys_flags = PySys_GetObject("flags");
+ // func gives no error if nullptr is returned and does not incref.
+ Py_XINCREF(sys_flags);
+ initialized = 1;
+ }
+ if (sys_flags != nullptr) {
+ PyObject *ob_ret = PyObject_GetAttrString(sys_flags, name);
+ if (ob_ret != nullptr) {
+ long long_ret = PyLong_AsLong(ob_ret);
+ Py_DECREF(ob_ret);
+ ret = (int) long_ret;
+ }
+ }
+ return ret;
+}
+
+int
+Pep_GetVerboseFlag()
+{
+ static int initialized = 0;
+ static int verbose_flag = -1;
+
+ if (!initialized) {
+ verbose_flag = Pep_GetFlag("verbose");
+ if (verbose_flag != -1)
+ initialized = 1;
+ }
+ return verbose_flag;
+}
+#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
+ *
+ */
+#ifdef Py_LIMITED_API
+
+int
+PepCode_Get(PepCodeObject *co, const char *name)
+{
+ PyObject *ob = reinterpret_cast<PyObject *>(co);
+ PyObject *ob_ret;
+ int ret = -1;
+
+ ob_ret = PyObject_GetAttrString(ob, name);
+ if (ob_ret != nullptr) {
+ long long_ret = PyLong_AsLong(ob_ret);
+ Py_DECREF(ob_ret);
+ ret = (int) long_ret;
+ }
+ return ret;
+}
+
+int PepCode_Check(PyObject *o)
+{
+ return o != nullptr && std::strcmp(Py_TYPE(o)->tp_name, "code") == 0 ? 1 : 0;
+}
+
+#endif // Py_LIMITED_API
+
+#if defined(Py_LIMITED_API) || defined(PYPY_VERSION)
+PyObject *PepFunction_GetDefaults(PyObject *function)
+{
+ auto *ob_ret = PyObject_GetAttrString(function, "__defaults__");
+ Py_XDECREF(ob_ret); // returns borrowed ref
+ return ob_ret != Py_None ? ob_ret : nullptr;
+}
+
+#endif // defined(Py_LIMITED_API) || defined(PYPY_VERSION)
+
+/*****************************************************************************
+ *
+ * Support for datetime.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+datetime_struc *PyDateTimeAPI = nullptr;
+
+static PyTypeObject *dt_getCheck(const char *name)
+{
+ PyObject *op = PyObject_GetAttrString(PyDateTimeAPI->module, name);
+ if (op == nullptr) {
+ fprintf(stderr, "datetime.%s not found\n", name);
+ Py_FatalError("aborting");
+ }
+ return reinterpret_cast<PyTypeObject *>(op);
+}
+
+// init_DateTime is called earlier than our module init.
+// We use the provided PyDateTime_IMPORT machinery.
+datetime_struc *
+init_DateTime(void)
+{
+ static int initialized = 0;
+ if (!initialized) {
+ PyDateTimeAPI = (datetime_struc *)malloc(sizeof(datetime_struc));
+ if (PyDateTimeAPI == nullptr)
+ Py_FatalError("PyDateTimeAPI malloc error, aborting");
+ PyDateTimeAPI->module = PyImport_ImportModule("datetime");
+ if (PyDateTimeAPI->module == nullptr)
+ Py_FatalError("datetime module not found, aborting");
+ PyDateTimeAPI->DateType = dt_getCheck("date");
+ PyDateTimeAPI->DateTimeType = dt_getCheck("datetime");
+ PyDateTimeAPI->TimeType = dt_getCheck("time");
+ PyDateTimeAPI->DeltaType = dt_getCheck("timedelta");
+ PyDateTimeAPI->TZInfoType = dt_getCheck("tzinfo");
+ initialized = 1;
+ }
+ return PyDateTimeAPI;
+}
+
+int
+PyDateTime_Get(PyObject *ob, const char *name)
+{
+ PyObject *ob_ret;
+ int ret = -1;
+
+ ob_ret = PyObject_GetAttrString(ob, name);
+ if (ob_ret != nullptr) {
+ long long_ret = PyLong_AsLong(ob_ret);
+ Py_DECREF(ob_ret);
+ ret = (int) long_ret;
+ }
+ return ret;
+}
+
+PyObject *
+PyDate_FromDate(int year, int month, int day)
+{
+ return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateType,
+ (char *)"(iii)", year, month, day);
+}
+
+PyObject *
+PyDateTime_FromDateAndTime(int year, int month, int day,
+ int hour, int min, int sec, int usec)
+{
+ return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateTimeType,
+ (char *)"(iiiiiii)", year, month, day,
+ hour, min, sec, usec);
+}
+
+PyObject *
+PyTime_FromTime(int hour, int min, int sec, int usec)
+{
+ return PyObject_CallFunction((PyObject *)PyDateTimeAPI->TimeType,
+ (char *)"(iiii)", hour, min, sec, usec);
+}
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for pythonrun.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+// Flags are ignored in these simple helpers.
+PyObject *
+PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
+{
+ PyObject *code = Py_CompileString(str, "pyscript", start);
+ PyObject *ret = nullptr;
+
+ if (code != nullptr) {
+ ret = PyEval_EvalCode(code, globals, locals);
+ }
+ Py_XDECREF(code);
+ return ret;
+}
+
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for classobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyTypeObject *PepMethod_TypePtr = nullptr;
+
+static PyTypeObject *getMethodType(void)
+{
+ static const char prog[] =
+ "class _C:\n"
+ " def _m(self): pass\n"
+ "result = type(_C()._m)\n";
+ return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
+}
+
+// We have no access to PyMethod_New and must call types.MethodType, instead.
+PyObject *
+PyMethod_New(PyObject *func, PyObject *self)
+{
+ return PyObject_CallFunction((PyObject *)PepMethod_TypePtr,
+ (char *)"(OO)", func, self);
+}
+
+PyObject *
+PyMethod_Function(PyObject *im)
+{
+ PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::func());
+
+ // We have to return a borrowed reference.
+ Py_DECREF(ret);
+ return ret;
+}
+
+PyObject *
+PyMethod_Self(PyObject *im)
+{
+ PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::self());
+
+ // We have to return a borrowed reference.
+ // If we don't obey that here, then we get a test error!
+ Py_DECREF(ret);
+ return ret;
+}
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for funcobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyObject *
+PepFunction_Get(PyObject *ob, const char *name)
+{
+ PyObject *ret;
+
+ // We have to return a borrowed reference.
+ ret = PyObject_GetAttrString(ob, name);
+ Py_XDECREF(ret);
+ return ret;
+}
+
+// This became necessary after Windows was activated.
+
+PyTypeObject *PepFunction_TypePtr = nullptr;
+
+static PyTypeObject *getFunctionType(void)
+{
+ static const char prog[] =
+ "from types import FunctionType as result\n";
+ return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
+}
+#endif // Py_LIMITED_API || Python 2
+
+/*****************************************************************************
+ *
+ * Support for dictobject.h
+ *
+ */
+
+/*****************************************************************************
+ *
+ * Extra support for signature.cpp
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyTypeObject *PepStaticMethod_TypePtr = nullptr;
+
+static PyTypeObject *
+getStaticMethodType(void)
+{
+ static const char prog[] =
+ "result = type(str.__dict__['maketrans'])\n";
+ return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *sm_callable;
+ PyObject *sm_dict;
+} staticmethod;
+
+PyObject *
+PyStaticMethod_New(PyObject *callable)
+{
+ staticmethod *sm = (staticmethod *)
+ PyType_GenericAlloc(PepStaticMethod_TypePtr, 0);
+ if (sm != nullptr) {
+ Py_INCREF(callable);
+ sm->sm_callable = callable;
+ }
+ return reinterpret_cast<PyObject *>(sm);
+}
+#endif // Py_LIMITED_API
+
+#ifdef PYPY_VERSION
+PyTypeObject *PepBuiltinMethod_TypePtr = nullptr;
+
+static PyTypeObject *
+getBuiltinMethodType(void)
+{
+ // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
+ //
+ // There is no public declaration for the "builtin method" type.
+ // We also cannot grep it with a Python script since the import is too early.
+ // Pick a demo "builtin method" by using the VoidPtr type.
+ // Create the equivalent of
+ // "from shiboken6.Shiboken import VoidPtr\n"
+ // "result = type(VoidPtr(0).toBytes)\n";
+ auto *pyVoidP = reinterpret_cast<PyObject *>(SbkVoidPtr_TypeF());
+ Shiboken::AutoDecRef arg(Py_BuildValue("i", 0));
+ Shiboken::AutoDecRef inst(PyObject_CallFunctionObjArgs(pyVoidP, arg.object(), nullptr));
+ Shiboken::AutoDecRef meth(PyObject_GetAttrString(inst, "toBytes"));
+ auto *result = reinterpret_cast<PyTypeObject *>(PyObject_Type(meth));
+ return result;
+}
+#endif
+
+/*****************************************************************************
+ *
+ * Common newly needed functions
+ *
+ */
+
+// The introduction of heaptypes converted many type names to the
+// dotted form, since PyType_FromSpec uses it to compute the module
+// name. This function reverts this effect.
+const char *
+PepType_GetNameStr(PyTypeObject *type)
+{
+ const char *ret = type->tp_name;
+ const char *nodots = std::strrchr(ret, '.');
+ if (nodots)
+ ret = nodots + 1;
+ return ret;
+}
+
+// PYSIDE-2264: Find the _functools or functools module and retrieve the
+// partial function. This can be tampered with, check carefully.
+PyObject *
+Pep_GetPartialFunction(void)
+{
+ static bool initialized = false;
+ static PyObject *result{};
+ if (initialized) {
+ Py_INCREF(result);
+ return result;
+ }
+ auto *functools = PyImport_ImportModule("_functools");
+ if (!functools) {
+ PyErr_Clear();
+ functools = PyImport_ImportModule("functools");
+ }
+ if (!functools)
+ Py_FatalError("functools cannot be found");
+ result = PyObject_GetAttrString(functools, "partial");
+ if (!result || !PyCallable_Check(result))
+ Py_FatalError("partial not found or not a function");
+ initialized = true;
+ return result;
+}
+
+/*****************************************************************************
+ *
+ * Newly introduced convenience functions
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyObject *
+PyImport_GetModule(PyObject *name)
+{
+ PyObject *m;
+ PyObject *modules = PyImport_GetModuleDict();
+ if (modules == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
+ return NULL;
+ }
+ Py_INCREF(modules);
+ if (PyDict_CheckExact(modules)) {
+ m = PyDict_GetItemWithError(modules, name); /* borrowed */
+ Py_XINCREF(m);
+ }
+ else {
+ m = PyObject_GetItem(modules, name);
+ if (m == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ }
+ }
+ Py_DECREF(modules);
+ return m;
+}
+
+#endif // Py_LIMITED_API
+
+// 2020-06-16: For simplicity of creating arbitrary things, this function
+// is now made public.
+
+PyObject *
+PepRun_GetResult(const char *command)
+{
+ /*
+ * Evaluate a string and return the variable `result`
+ */
+ PyObject *d, *v, *res;
+
+ d = PyDict_New();
+ if (d == nullptr
+ || PyDict_SetItem(d, Shiboken::PyMagicName::builtins(), PyEval_GetBuiltins()) < 0) {
+ return nullptr;
+ }
+ v = PyRun_String(command, Py_file_input, d, d);
+ res = v ? PyDict_GetItem(d, Shiboken::PyName::result()) : nullptr;
+ Py_XDECREF(v);
+ Py_DECREF(d);
+ return res;
+}
+
+PyTypeObject *PepType_Type_tp_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
+{
+ auto ret = PyType_Type.tp_new(metatype, args, kwds);
+ return reinterpret_cast<PyTypeObject *>(ret);
+}
+
+/*****************************************************************************
+ *
+ * Extra support for name mangling
+ *
+ */
+
+#ifdef Py_LIMITED_API
+// We keep these definitions local, because they don't work in Python 2.
+# define PyUnicode_GET_LENGTH(op) PyUnicode_GetLength((PyObject *)(op))
+# define PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar((PyObject *)(u), (i))
+#endif // Py_LIMITED_API
+
+PyObject *
+_Pep_PrivateMangle(PyObject *self, PyObject *name)
+{
+ /*
+ * Name mangling: __private becomes _classname__private.
+ * This function is modelled after _Py_Mangle, but is optimized
+ * a little for our purpose.
+ */
+ if (PyUnicode_READ_CHAR(name, 0) != '_' ||
+ PyUnicode_READ_CHAR(name, 1) != '_') {
+ Py_INCREF(name);
+ return name;
+ }
+ size_t nlen = PyUnicode_GET_LENGTH(name);
+ /* Don't mangle __id__ or names with dots. */
+ if ((PyUnicode_READ_CHAR(name, nlen-1) == '_' &&
+ PyUnicode_READ_CHAR(name, nlen-2) == '_') ||
+ PyUnicode_FindChar(name, '.', 0, nlen, 1) != -1) {
+ Py_INCREF(name);
+ return name;
+ }
+ Shiboken::AutoDecRef privateobj(PyObject_GetAttr(
+ reinterpret_cast<PyObject *>(Py_TYPE(self)), Shiboken::PyMagicName::name()));
+
+ // PYSIDE-1436: _Py_Mangle is no longer exposed; implement it always.
+ // The rest of this function is our own implementation of _Py_Mangle.
+ // Please compare the original function in compile.c .
+ size_t plen = PyUnicode_GET_LENGTH(privateobj.object());
+ /* Strip leading underscores from class name */
+ size_t ipriv = 0;
+ while (PyUnicode_READ_CHAR(privateobj.object(), ipriv) == '_')
+ ipriv++;
+ if (ipriv == plen) {
+ Py_INCREF(name);
+ return name; /* Don't mangle if class is just underscores */
+ }
+ plen -= ipriv;
+
+ if (plen + nlen >= PY_SSIZE_T_MAX - 1) {
+ PyErr_SetString(PyExc_OverflowError,
+ "private identifier too large to be mangled");
+ return nullptr;
+ }
+ size_t const amount = ipriv + 1 + plen + nlen;
+ size_t const big_stack = 1000;
+ wchar_t bigbuf[big_stack];
+ wchar_t *resbuf = amount <= big_stack ? bigbuf : (wchar_t *)malloc(sizeof(wchar_t) * amount);
+ if (!resbuf)
+ return nullptr;
+ /* ident = "_" + priv[ipriv:] + ident # i.e. 1+plen+nlen bytes */
+ resbuf[0] = '_';
+ if (PyUnicode_AsWideChar(privateobj, resbuf + 1, ipriv + plen) < 0)
+ return nullptr;
+ if (PyUnicode_AsWideChar(name, resbuf + ipriv + plen + 1, nlen) < 0)
+ return nullptr;
+ PyObject *result = PyUnicode_FromWideChar(resbuf + ipriv, 1 + plen + nlen);
+ if (amount > big_stack)
+ free(resbuf);
+ return result;
+}
+
+/*****************************************************************************
+ *
+ * Runtime support for Python 3.8 incompatibilities
+ *
+ */
+
+int PepRuntime_38_flag = 0;
+
+static void
+init_PepRuntime()
+{
+ // We expect a string of the form "\d\.\d+\."
+ const char *version = Py_GetVersion();
+ if (version[0] < '3')
+ return;
+ if (std::atoi(version + 2) >= 8)
+ PepRuntime_38_flag = 1;
+}
+
+static long _GetPepRuntimeVersion()
+{
+ auto *version = PySys_GetObject("version_info");
+ const auto major = PyLong_AsLong(PyTuple_GetItem(version, 0));
+ const auto minor = PyLong_AsLong(PyTuple_GetItem(version, 1));
+ const auto micro = PyLong_AsLong(PyTuple_GetItem(version, 2));
+ return major << 16 | minor << 8 | micro;
+}
+
+long _PepRuntimeVersion()
+{
+ static const auto number = _GetPepRuntimeVersion();
+ return number;
+}
+
+/*****************************************************************************
+ *
+ * PYSIDE-535: Support for PyPy
+ *
+ * This has the nice side effect of a more clean implementation,
+ * and we don't keep the old macro version.
+ *
+ */
+
+///////////////////////////////////////////////////////////////////////
+//
+// PEP 697: Support for embedded type structures.
+//
+// According to `https://docs.python.org/3/c-api/object.html?highlight=pyobject_gettypedata#c.PyObject_GetTypeData`
+// the function `PyObject_GetTypeData` should belong to the Stable API
+// since version 3.12.0, but it does not. We use instead some copies
+// from Python source code.
+
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+
+# define PepObject_GetTypeData PyObject_GetTypeData
+
+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, meta);
+ return reinterpret_cast<SbkObjectTypePrivate *>(data);
+}
+
+void PepType_SOTP_delete(PyTypeObject * /*type*/)
+{
+}
+
+#else
+
+// The following comments are directly copied from Python 3.12
+//
+
+// Make sure we have maximum alignment, even if the current compiler
+// does not support max_align_t. Note that:
+// - Autoconf reports alignment of unknown types to 0.
+// - 'long double' has maximum alignment on *most* platforms,
+// looks like the best we can do for pre-C11 compilers.
+// - The value is tested, see test_alignof_max_align_t
+# if !defined(ALIGNOF_MAX_ALIGN_T) || ALIGNOF_MAX_ALIGN_T == 0
+# undef ALIGNOF_MAX_ALIGN_T
+# define ALIGNOF_MAX_ALIGN_T alignof(long double)
+# endif
+
+/* Align up to the nearest multiple of alignof(max_align_t)
+ * (like _Py_ALIGN_UP, but for a size rather than pointer)
+ */
+static Py_ssize_t _align_up(Py_ssize_t size)
+{
+ return (size + ALIGNOF_MAX_ALIGN_T - 1) & ~(ALIGNOF_MAX_ALIGN_T - 1);
+}
+
+static void *PepObject_GetTypeData(PyObject *obj, PyTypeObject *cls)
+{
+ assert(PyObject_TypeCheck(obj, cls));
+ return reinterpret_cast<char *>(obj) + _align_up(cls->tp_base->tp_basicsize);
+}
+//
+///////////////////////////////////////////////////////////////////////
+
+/*
+ * PyTypeObject extender
+ */
+
+static std::unordered_map<PyTypeObject *, SbkObjectTypePrivate > SOTP_extender{};
+static thread_local PyTypeObject *SOTP_key{};
+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, meta);
+ return reinterpret_cast<SbkObjectTypePrivate *>(data);
+ }
+ if (type == SOTP_key)
+ return SOTP_value;
+ auto it = SOTP_extender.find(type);
+ if (it == SOTP_extender.end()) {
+ it = SOTP_extender.insert({type, {}}).first;
+ memset(&it->second, 0, sizeof(SbkObjectTypePrivate));
+ }
+ SOTP_key = type;
+ SOTP_value = &it->second;
+ return SOTP_value;
+}
+
+void PepType_SOTP_delete(PyTypeObject *type)
+{
+ static bool use_312 = _PepRuntimeVersion() >= 0x030C00;
+ assert(SbkObjectType_Check(type));
+ if (use_312)
+ return;
+ SOTP_extender.erase(type);
+ SOTP_key = nullptr;
+}
+
+#endif // !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+
+/*
+ * SbkEnumType extender
+ */
+static std::unordered_map<SbkEnumType *, SbkEnumTypePrivate> SETP_extender{};
+static thread_local SbkEnumType *SETP_key{};
+static thread_local SbkEnumTypePrivate *SETP_value{};
+
+SbkEnumTypePrivate *PepType_SETP(SbkEnumType *enumType)
+{
+ // PYSIDE-2230: This makes no sense at all for Enum types.
+ if (enumType == SETP_key)
+ return SETP_value;
+ auto it = SETP_extender.find(enumType);
+ if (it == SETP_extender.end()) {
+ it = SETP_extender.insert({enumType, {}}).first;
+ memset(&it->second, 0, sizeof(SbkEnumTypePrivate));
+ }
+ SETP_key = enumType;
+ SETP_value = &it->second;
+ return SETP_value;
+}
+
+void PepType_SETP_delete(SbkEnumType *enumType)
+{
+ SETP_extender.erase(enumType);
+ SETP_key = nullptr;
+}
+
+#ifdef Py_LIMITED_API
+static PyObject *emulatePyType_GetDict(PyTypeObject *type)
+{
+ if (_PepRuntimeVersion() < 0x030C00 || type->tp_dict) {
+ auto *res = type->tp_dict;
+ Py_XINCREF(res);
+ return res;
+ }
+ // PYSIDE-2230: Here we are really cheating. We don't know how to
+ // access an internal dict, and so we simply pretend
+ // it were an empty dict. This works great for our types.
+ // This was an unexpectedly simple solution :D
+ return PyDict_New();
+}
+#endif
+
+// PyType_GetDict: replacement for <static type>.tp_dict, which is
+// zero for builtin types since 3.12.
+PyObject *PepType_GetDict(PyTypeObject *type)
+{
+#if !defined(Py_LIMITED_API)
+# if PY_VERSION_HEX >= 0x030C0000
+ return PyType_GetDict(type);
+# else
+ // pre 3.12 fallback code, mimicking the addref-behavior.
+ Py_XINCREF(type->tp_dict);
+ return type->tp_dict;
+# endif
+#else
+ return emulatePyType_GetDict(type);
+#endif // Py_LIMITED_API
+}
+
+int PepType_SetDict(PyTypeObject *type, PyObject *dict)
+{
+ type->tp_dict = dict;
+ return 0;
+}
+
+// Pre 3.10, PyType_GetSlot() would only work for heap types.
+// FIXME: PyType_GetSlot() can be used unconditionally when the
+// minimum limited API version is >= 3.10.
+void *PepType_GetSlot(PyTypeObject *type, int aSlot)
+{
+ static const bool is310 = _PepRuntimeVersion() >= 0x030A00;
+ if (is310 || (type->tp_flags & Py_TPFLAGS_HEAPTYPE) != 0)
+ return PyType_GetSlot(type, aSlot);
+
+ switch (aSlot) {
+ case Py_tp_alloc:
+ return reinterpret_cast<void *>(type->tp_alloc);
+ case Py_tp_getattro:
+ return reinterpret_cast<void *>(type->tp_getattro);
+ case Py_tp_setattro:
+ return reinterpret_cast<void *>(type->tp_setattro);
+ case Py_tp_descr_get:
+ return reinterpret_cast<void *>(type->tp_descr_get);
+ case Py_tp_descr_set:
+ return reinterpret_cast<void *>(type->tp_descr_set);
+ case Py_tp_call:
+ return reinterpret_cast<void *>(type->tp_call);
+ case Py_tp_new:
+ return reinterpret_cast<void *>(type->tp_new);
+ case Py_tp_init:
+ return reinterpret_cast<void *>(type->tp_init);
+ case Py_tp_free:
+ return reinterpret_cast<void *>(type->tp_free);
+ }
+ assert(false);
+ return nullptr;
+}
+
+/***************************************************************************
+ *
+ * PYSIDE-535: The enum/flag error
+ * -------------------------------
+ *
+ * This is a fragment of the code which was used to find the enum/flag
+ * alias error. See the change to `setTypeConverter` in sbkenum.cpp .
+ *
+
+Usage:
+
+python3 -c "from PySide6 import QtCore" 2>&1 | python3 tools/debug_renamer.py | uniq -c | head -10
+
+ 5 PepType_ExTP:940 x_A SOTP s=96
+ 4 PepType_ExTP:940 x_B SETP s=24
+ 2 PepType_ExTP:940 x_C PFTP s=16
+ 4 PepType_ExTP:940 x_D SETP s=24
+ 1 PepType_ExTP:940 x_C SETP s=24
+ 2 PepType_ExTP:940 x_E PFTP s=16
+ 4 PepType_ExTP:940 x_F SETP s=24
+ 1 PepType_ExTP:940 x_E SETP s=24
+ 4 PepType_ExTP:940 x_G SETP s=24
+ 4 PepType_ExTP:940 x_H SETP s=24
+
+static inline void *PepType_ExTP(PyTypeObject *type, size_t size)
+{
+ static const char *env_p = std::getenv("PFTP");
+ if (env_p) {
+ static PyTypeObject *alias{};
+ const char *kind = size == sizeof(SbkObjectTypePrivate) ? "SOTP" :
+ size == sizeof(SbkEnumTypePrivate) ? "SETP" :
+ size == sizeof(SbkQFlagsTypePrivate) ? "PFTP" :
+ "unk.";
+ fprintf(stderr, "%s:%d %p x %s s=%ld\n", __func__, __LINE__, type, kind, size);
+ PyObject *kill{};
+ if (strlen(env_p) > 0) {
+ if (size == sizeof(SbkQFlagsTypePrivate)) {
+ if (alias == nullptr)
+ alias = type;
+ }
+ if (size != sizeof(SbkQFlagsTypePrivate)) {
+ if (type == alias)
+ Py_INCREF(kill);
+ }
+ }
+ }
+ const auto ikey = reinterpret_cast<std::uintptr_t>(type);
+ if (ikey == cached_key)
+ return cached_value;
+ auto it = SOTP_extender.find(ikey);
+ if (it == SOTP_extender.end()) {
+ PepType_ExTP_init(type, size);
+ return PepType_ExTP(type, size);
+ }
+ cached_key = ikey;
+ cached_value = reinterpret_cast<void *>(it->second);
+ return cached_value;
+}
+*/
+
+/*****************************************************************************
+ *
+ * Module Initialization
+ *
+ */
+
+void
+Pep384_Init()
+{
+ init_PepRuntime();
+#ifdef Py_LIMITED_API
+ check_PyTypeObject_valid();
+ Pep_GetVerboseFlag();
+ PepMethod_TypePtr = getMethodType();
+ PepFunction_TypePtr = getFunctionType();
+ PepStaticMethod_TypePtr = getStaticMethodType();
+#endif // Py_LIMITED_API
+#ifdef PYPY_VERSION
+ PepBuiltinMethod_TypePtr = getBuiltinMethodType();
+#endif
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/pep384impl.h b/sources/shiboken6/libshiboken/pep384impl.h
new file mode 100644
index 000000000..7188366e2
--- /dev/null
+++ b/sources/shiboken6/libshiboken/pep384impl.h
@@ -0,0 +1,611 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PEP384IMPL_H
+#define PEP384IMPL_H
+
+extern "C"
+{
+
+/*****************************************************************************
+ *
+ * RESOLVED: memoryobject.h
+ *
+ */
+
+// Extracted into bufferprocs27.h
+#ifdef Py_LIMITED_API
+#include "bufferprocs_py37.h"
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: object.h
+ *
+ */
+#ifdef Py_LIMITED_API
+// Why the hell is this useful debugging function not allowed?
+// BTW: When used, it breaks on Windows, intentionally!
+LIBSHIBOKEN_API void _PyObject_Dump(PyObject *);
+#endif
+
+/*
+ * There are a few structures that are needed, but cannot be used without
+ * breaking the API. We use some heuristics to get those fields anyway
+ * and validate that we really found them, see pep384impl.cpp .
+ */
+
+#ifdef Py_LIMITED_API
+
+/*
+ * These are the type object fields that we use.
+ * We will verify that they never change.
+ * The unused fields are intentionally named as "void *Xnn" because
+ * the chance is smaller to forget to validate a field.
+ * When we need more fields, we replace it back and add it to the
+ * validation.
+ */
+typedef struct _typeobject {
+ PyVarObject ob_base;
+ const char *tp_name;
+ Py_ssize_t tp_basicsize;
+ void *X03; // Py_ssize_t tp_itemsize;
+#ifdef PEP384_INTERN
+ destructor tp_dealloc;
+#else
+ destructor X04;
+#endif
+ void *X05; // Py_ssize_t tp_vectorcall_offset;
+ void *X06; // getattrfunc tp_getattr;
+ void *X07; // setattrfunc tp_setattr;
+ void *X08; // PyAsyncMethods *tp_as_async;
+#ifdef PEP384_INTERN
+ reprfunc tp_repr;
+#else
+ reprfunc X09;
+#endif
+ void *X10; // PyNumberMethods *tp_as_number;
+ void *X11; // PySequenceMethods *tp_as_sequence;
+ void *X12; // PyMappingMethods *tp_as_mapping;
+ void *X13; // hashfunc tp_hash;
+#ifdef PEP384_INTERN
+ ternaryfunc tp_call;
+#else
+ ternaryfunc X14;
+#endif
+ reprfunc tp_str; // Only used for PEP384_INTERN and a shiboken test
+ getattrofunc tp_getattro;
+ setattrofunc tp_setattro;
+ void *X18; // PyBufferProcs *tp_as_buffer;
+ unsigned long tp_flags;
+ void *X20; // const char *tp_doc;
+#ifdef PEP384_INTERN
+ traverseproc tp_traverse;
+ inquiry tp_clear;
+#else
+ traverseproc X21;
+ inquiry X22;
+#endif
+ void *X23; // richcmpfunc tp_richcompare;
+ Py_ssize_t tp_weaklistoffset;
+ void *X25; // getiterfunc tp_iter;
+#ifdef PEP384_INTERN
+ iternextfunc tp_iternext;
+#else
+ iternextfunc X26;
+#endif
+ struct PyMethodDef *tp_methods;
+ struct PyMemberDef *tp_members;
+ struct PyGetSetDef *tp_getset;
+ struct _typeobject *tp_base;
+#ifdef PEP384_INTERN
+ PyObject *tp_dict;
+ descrgetfunc tp_descr_get;
+ descrsetfunc tp_descr_set;
+#else
+ void *X31;
+ descrgetfunc X32;
+ descrsetfunc X33;
+#endif
+ Py_ssize_t tp_dictoffset;
+#ifdef PEP384_INTERN
+ initproc tp_init;
+ allocfunc tp_alloc;
+#else
+ initproc X39;
+ allocfunc X40;
+#endif
+ newfunc tp_new;
+#ifdef PEP384_INTERN
+ freefunc tp_free;
+ inquiry tp_is_gc; /* For PyObject_IS_GC */
+#else
+ freefunc X41;
+ inquiry X42; /* For PyObject_IS_GC */
+#endif
+ PyObject *tp_bases;
+ PyObject *tp_mro; /* method resolution order */
+
+} PyTypeObject;
+
+#ifndef PyObject_IS_GC
+/* Test if an object has a GC head */
+#define PyObject_IS_GC(o) \
+ (PyType_IS_GC(Py_TYPE(o)) \
+ && (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o)))
+#endif
+
+LIBSHIBOKEN_API PyObject *_PepType_Lookup(PyTypeObject *type, PyObject *name);
+
+#else // Py_LIMITED_API
+
+#define _PepType_Lookup(type, name) _PyType_Lookup(type, name)
+
+#endif // Py_LIMITED_API
+
+/// PYSIDE-939: We need the runtime version, given major << 16 + minor << 8 + micro
+LIBSHIBOKEN_API long _PepRuntimeVersion();
+/*****************************************************************************
+ *
+ * PYSIDE-535: Implement a clean type extension for PyPy
+ *
+ */
+
+struct SbkObjectTypePrivate;
+
+LIBSHIBOKEN_API SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type);
+LIBSHIBOKEN_API void PepType_SOTP_delete(PyTypeObject *type);
+
+struct SbkEnumType;
+struct SbkEnumTypePrivate;
+
+LIBSHIBOKEN_API SbkEnumTypePrivate *PepType_SETP(SbkEnumType *type);
+LIBSHIBOKEN_API void PepType_SETP_delete(SbkEnumType *enumType);
+
+struct PySideQFlagsType;
+struct SbkQFlagsTypePrivate;
+
+/*****************************************************************************/
+
+// functions used everywhere
+LIBSHIBOKEN_API const char *PepType_GetNameStr(PyTypeObject *type);
+
+LIBSHIBOKEN_API PyObject *Pep_GetPartialFunction(void);
+
+/*****************************************************************************
+ *
+ * RESOLVED: pydebug.h
+ *
+ */
+#ifdef Py_LIMITED_API
+/*
+ * We have no direct access to Py_VerboseFlag because debugging is not
+ * supported. The python developers are partially a bit too rigorous.
+ * Instead, we compute the value and use a function call macro.
+ * Was before: extern LIBSHIBOKEN_API int Py_VerboseFlag;
+ */
+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
+ *
+ */
+
+///////////////////////////////////////////////////////////////////////
+//
+// PYSIDE-813: About The Length Of Unicode Objects
+// -----------------------------------------------
+//
+// In Python 2 and before Python 3.3, the macro PyUnicode_GET_SIZE
+// worked fine and really like a macro.
+//
+// Meanwhile, the unicode objects have changed their layout very much,
+// and the former cheap macro call has become a real function call
+// that converts objects and needs PyMemory.
+//
+// That is not only inefficient, but also requires the GIL!
+// This problem was visible by debug Python and qdatastream_test.py .
+// It was found while fixing the refcount problem of PYSIDE-813 which
+// needed a debug Python.
+//
+
+// PyUnicode_GetSize is deprecated in favor of PyUnicode_GetLength.
+#define PepUnicode_GetLength(op) PyUnicode_GetLength((PyObject *)(op))
+
+// Unfortunately, we cannot ask this at runtime
+// #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000
+// FIXME: Python 3.10: Replace _PepUnicode_AsString by PyUnicode_AsUTF8
+#ifdef Py_LIMITED_API
+
+LIBSHIBOKEN_API const char *_PepUnicode_AsString(PyObject *);
+
+enum PepUnicode_Kind {
+#if PY_VERSION_HEX < 0x030C0000
+ PepUnicode_WCHAR_KIND = 0,
+#endif
+ PepUnicode_1BYTE_KIND = 1,
+ PepUnicode_2BYTE_KIND = 2,
+ PepUnicode_4BYTE_KIND = 4
+};
+
+LIBSHIBOKEN_API int _PepUnicode_KIND(PyObject *);
+LIBSHIBOKEN_API int _PepUnicode_IS_ASCII(PyObject *str);
+LIBSHIBOKEN_API int _PepUnicode_IS_COMPACT(PyObject *str);
+
+LIBSHIBOKEN_API void *_PepUnicode_DATA(PyObject *str);
+
+#else
+
+enum PepUnicode_Kind {
+#if PY_VERSION_HEX < 0x030C0000
+ PepUnicode_WCHAR_KIND = PyUnicode_WCHAR_KIND,
+#endif
+ PepUnicode_1BYTE_KIND = PyUnicode_1BYTE_KIND,
+ PepUnicode_2BYTE_KIND = PyUnicode_2BYTE_KIND,
+ PepUnicode_4BYTE_KIND = PyUnicode_4BYTE_KIND
+};
+
+#define _PepUnicode_AsString PyUnicode_AsUTF8
+#define _PepUnicode_KIND PyUnicode_KIND
+#define _PepUnicode_DATA PyUnicode_DATA
+#define _PepUnicode_IS_COMPACT PyUnicode_IS_COMPACT
+#define _PepUnicode_IS_ASCII PyUnicode_IS_ASCII
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: bytesobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+#define PyBytes_AS_STRING(op) PyBytes_AsString(op)
+#define PyBytes_GET_SIZE(op) PyBytes_Size(op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: floatobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+#define PyFloat_AS_DOUBLE(op) PyFloat_AsDouble(op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: tupleobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+#define PyTuple_GET_ITEM(op, i) PyTuple_GetItem((PyObject *)op, i)
+#define PyTuple_SET_ITEM(op, i, v) PyTuple_SetItem(op, i, v)
+#define PyTuple_GET_SIZE(op) PyTuple_Size((PyObject *)op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: listobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+#define PyList_GET_ITEM(op, i) PyList_GetItem(op, i)
+#define PyList_SET_ITEM(op, i, v) PyList_SetItem(op, i, v)
+#define PyList_GET_SIZE(op) PyList_Size(op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: methodobject.h
+ *
+ */
+
+#ifdef Py_LIMITED_API
+
+using PyCFunctionObject = struct _pycfunc;
+#define PyCFunction_GET_FUNCTION(func) PyCFunction_GetFunction((PyObject *)func)
+#define PyCFunction_GET_SELF(func) PyCFunction_GetSelf((PyObject *)func)
+#define PyCFunction_GET_FLAGS(func) PyCFunction_GetFlags((PyObject *)func)
+#define PepCFunction_GET_NAMESTR(func) \
+ _PepUnicode_AsString(PyObject_GetAttrString((PyObject *)func, "__name__"))
+#else
+#define PepCFunction_GET_NAMESTR(func) ((func)->m_ml->ml_name)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: pythonrun.h
+ *
+ */
+#ifdef Py_LIMITED_API
+LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject *);
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: abstract.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+// This definition breaks the limited API a little, because it re-enables the
+// buffer functions.
+// But this is no problem as we check it's validity for every version.
+
+// PYSIDE-1960 The buffer interface is since Python 3.11 part of the stable
+// API and we do not need to check the compatibility by hand anymore.
+
+typedef struct {
+ getbufferproc bf_getbuffer;
+ releasebufferproc bf_releasebuffer;
+} PyBufferProcs;
+
+typedef struct _Pepbuffertype {
+ PyVarObject ob_base;
+ void *skip[17];
+ PyBufferProcs *tp_as_buffer;
+} PepBufferType;
+
+#define PepType_AS_BUFFER(type) \
+ reinterpret_cast<PepBufferType *>(type)->tp_as_buffer
+
+#define PyObject_CheckBuffer(obj) \
+ ((PepType_AS_BUFFER(Py_TYPE(obj)) != NULL) && \
+ (PepType_AS_BUFFER(Py_TYPE(obj))->bf_getbuffer != NULL))
+
+LIBSHIBOKEN_API int PyObject_GetBuffer(PyObject *ob, Pep_buffer *view, int flags);
+LIBSHIBOKEN_API void PyBuffer_Release(Pep_buffer *view);
+
+#else
+
+#define Pep_buffer Py_buffer
+#define PepType_AS_BUFFER(type) ((type)->tp_as_buffer)
+
+#endif /* Py_LIMITED_API */
+
+/*****************************************************************************
+ *
+ * RESOLVED: funcobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+typedef struct _func PyFunctionObject;
+
+extern LIBSHIBOKEN_API PyTypeObject *PepFunction_TypePtr;
+LIBSHIBOKEN_API PyObject *PepFunction_Get(PyObject *, const char *);
+
+#define PyFunction_Check(op) (Py_TYPE(op) == PepFunction_TypePtr)
+#define PyFunction_GET_CODE(func) PyFunction_GetCode(func)
+
+#define PyFunction_GetCode(func) PepFunction_Get((PyObject *)func, "__code__")
+#define PepFunction_GetName(func) PepFunction_Get((PyObject *)func, "__name__")
+#else
+#define PepFunction_TypePtr (&PyFunction_Type)
+#define PepFunction_GetName(func) (((PyFunctionObject *)func)->func_name)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: classobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+typedef struct _meth PyMethodObject;
+
+extern LIBSHIBOKEN_API PyTypeObject *PepMethod_TypePtr;
+
+LIBSHIBOKEN_API PyObject *PyMethod_New(PyObject *, PyObject *);
+LIBSHIBOKEN_API PyObject *PyMethod_Function(PyObject *);
+LIBSHIBOKEN_API PyObject *PyMethod_Self(PyObject *);
+
+#define PyMethod_Check(op) ((op)->ob_type == PepMethod_TypePtr)
+
+#define PyMethod_GET_SELF(op) PyMethod_Self(op)
+#define PyMethod_GET_FUNCTION(op) PyMethod_Function(op)
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: code.h
+ *
+ */
+#ifdef Py_LIMITED_API
+/* Bytecode object */
+
+// we have to grab the code object from python
+typedef struct _code PepCodeObject;
+
+LIBSHIBOKEN_API int PepCode_Get(PepCodeObject *co, const char *name);
+LIBSHIBOKEN_API int PepCode_Check(PyObject *o);
+
+# define PepCode_GET_FLAGS(o) PepCode_Get(o, "co_flags")
+# define PepCode_GET_ARGCOUNT(o) PepCode_Get(o, "co_argcount")
+
+LIBSHIBOKEN_API PyObject *PepFunction_GetDefaults(PyObject *function);
+
+/* Masks for co_flags above */
+# define CO_OPTIMIZED 0x0001
+# define CO_NEWLOCALS 0x0002
+# define CO_VARARGS 0x0004
+# define CO_VARKEYWORDS 0x0008
+# define CO_NESTED 0x0010
+# define CO_GENERATOR 0x0020
+
+#else
+
+# define PepCodeObject PyCodeObject
+# define PepCode_GET_FLAGS(o) ((o)->co_flags)
+# define PepCode_GET_ARGCOUNT(o) ((o)->co_argcount)
+# define PepCode_Check PyCode_Check
+
+# ifdef PYPY_VERSION
+
+LIBSHIBOKEN_API PyObject *PepFunction_GetDefaults(PyObject *function);
+
+# else
+# define PepFunction_GetDefaults PyFunction_GetDefaults
+# endif
+#endif
+
+/*****************************************************************************
+ *
+ * RESOLVED: datetime.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+LIBSHIBOKEN_API int PyDateTime_Get(PyObject *ob, const char *name);
+
+#define PyDateTime_GetYear(o) PyDateTime_Get(o, "year")
+#define PyDateTime_GetMonth(o) PyDateTime_Get(o, "month")
+#define PyDateTime_GetDay(o) PyDateTime_Get(o, "day")
+#define PyDateTime_GetHour(o) PyDateTime_Get(o, "hour")
+#define PyDateTime_GetMinute(o) PyDateTime_Get(o, "minute")
+#define PyDateTime_GetSecond(o) PyDateTime_Get(o, "second")
+#define PyDateTime_GetMicrosecond(o) PyDateTime_Get(o, "microsecond")
+#define PyDateTime_GetFold(o) PyDateTime_Get(o, "fold")
+
+#define PyDateTime_GET_YEAR(o) PyDateTime_GetYear(o)
+#define PyDateTime_GET_MONTH(o) PyDateTime_GetMonth(o)
+#define PyDateTime_GET_DAY(o) PyDateTime_GetDay(o)
+
+#define PyDateTime_DATE_GET_HOUR(o) PyDateTime_GetHour(o)
+#define PyDateTime_DATE_GET_MINUTE(o) PyDateTime_GetMinute(o)
+#define PyDateTime_DATE_GET_SECOND(o) PyDateTime_GetSecond(o)
+#define PyDateTime_DATE_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o)
+#define PyDateTime_DATE_GET_FOLD(o) PyDateTime_GetFold(o)
+
+#define PyDateTime_TIME_GET_HOUR(o) PyDateTime_GetHour(o)
+#define PyDateTime_TIME_GET_MINUTE(o) PyDateTime_GetMinute(o)
+#define PyDateTime_TIME_GET_SECOND(o) PyDateTime_GetSecond(o)
+#define PyDateTime_TIME_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o)
+#define PyDateTime_TIME_GET_FOLD(o) PyDateTime_GetFold(o)
+
+/* Define structure slightly similar to C API. */
+typedef struct {
+ PyObject *module;
+ /* type objects */
+ PyTypeObject *DateType;
+ PyTypeObject *DateTimeType;
+ PyTypeObject *TimeType;
+ PyTypeObject *DeltaType;
+ PyTypeObject *TZInfoType;
+} datetime_struc;
+
+LIBSHIBOKEN_API datetime_struc *init_DateTime(void);
+
+#define PyDateTime_IMPORT PyDateTimeAPI = init_DateTime()
+
+extern LIBSHIBOKEN_API datetime_struc *PyDateTimeAPI;
+
+#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType)
+#define PyDateTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateTimeType)
+#define PyTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TimeType)
+
+LIBSHIBOKEN_API PyObject *PyDate_FromDate(int year, int month, int day);
+LIBSHIBOKEN_API PyObject *PyDateTime_FromDateAndTime(
+ int year, int month, int day, int hour, int min, int sec, int usec);
+LIBSHIBOKEN_API PyObject *PyTime_FromTime(
+ int hour, int minute, int second, int usecond);
+
+#endif /* Py_LIMITED_API */
+
+/*****************************************************************************
+ *
+ * Extra support for name mangling
+ *
+ */
+
+// PYSIDE-772: This function supports the fix, but is not meant as public.
+LIBSHIBOKEN_API PyObject *_Pep_PrivateMangle(PyObject *self, PyObject *name);
+
+/*****************************************************************************
+ *
+ * Extra support for signature.cpp
+ *
+ */
+
+#ifdef Py_LIMITED_API
+extern LIBSHIBOKEN_API PyTypeObject *PepStaticMethod_TypePtr;
+LIBSHIBOKEN_API PyObject *PyStaticMethod_New(PyObject *callable);
+#else
+#define PepStaticMethod_TypePtr &PyStaticMethod_Type
+#endif
+
+#ifdef PYPY_VERSION
+extern LIBSHIBOKEN_API PyTypeObject *PepBuiltinMethod_TypePtr;
+#endif
+
+// Although not PEP specific, we resolve this similar issue, here:
+#define PepMethodDescr_TypePtr &PyMethodDescr_Type
+
+/*****************************************************************************
+ *
+ * Newly introduced convenience functions
+ *
+ * This is not defined if Py_LIMITED_API is defined.
+ */
+#ifdef Py_LIMITED_API
+LIBSHIBOKEN_API PyObject *PyImport_GetModule(PyObject *name);
+#endif // Py_LIMITED_API
+
+// Evaluate a script and return the variable `result`
+LIBSHIBOKEN_API PyObject *PepRun_GetResult(const char *command);
+
+// Call PyType_Type.tp_new returning a PyType object.
+LIBSHIBOKEN_API PyTypeObject *PepType_Type_tp_new(PyTypeObject *metatype,
+ PyObject *args,
+ PyObject *kwds);
+
+/*****************************************************************************
+ *
+ * Runtime support for Python 3.8 incompatibilities
+ *
+ */
+
+#ifndef Py_TPFLAGS_METHOD_DESCRIPTOR
+/* Objects behave like an unbound method */
+#define Py_TPFLAGS_METHOD_DESCRIPTOR (1UL << 17)
+#endif
+
+extern LIBSHIBOKEN_API int PepRuntime_38_flag;
+
+/*****************************************************************************
+ *
+ * Runtime support for Python 3.12 incompatibility
+ *
+ */
+
+LIBSHIBOKEN_API PyObject *PepType_GetDict(PyTypeObject *type);
+
+// This function does not exist as PyType_SetDict. But because tp_dict
+// is no longer considered to be accessible, we treat it as such.
+LIBSHIBOKEN_API int PepType_SetDict(PyTypeObject *type, PyObject *dict);
+
+LIBSHIBOKEN_API void *PepType_GetSlot(PyTypeObject *type, int aSlot);
+
+/*****************************************************************************
+ *
+ * Module Initialization
+ *
+ */
+
+LIBSHIBOKEN_API void Pep384_Init(void);
+
+} // extern "C"
+
+#endif // PEP384IMPL_H
diff --git a/sources/shiboken6/libshiboken/pyobjectholder.h b/sources/shiboken6/libshiboken/pyobjectholder.h
new file mode 100644
index 000000000..857748c2f
--- /dev/null
+++ b/sources/shiboken6/libshiboken/pyobjectholder.h
@@ -0,0 +1,86 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYOBJECTHOLDER_H
+#define PYOBJECTHOLDER_H
+
+#include "sbkpython.h"
+
+#include <cassert>
+#include <utility>
+
+namespace Shiboken
+{
+
+/// PyObjectHolder holds a PyObject pointer, keeping a reference decrementing
+/// its reference counter when destroyed. It makes sure to hold the GIL when
+/// releasing. It implements copy/move semantics and is mainly intended as a
+/// base class for functors holding a callable which can be passed around and
+/// stored in containers or moved from freely.
+/// For one-shot functors, release() can be invoked after the call.
+class PyObjectHolder
+{
+public:
+ PyObjectHolder() noexcept = default;
+
+ /// PyObjectHolder constructor.
+ /// \param pyobj A reference to a Python object
+ explicit PyObjectHolder(PyObject *pyObj) noexcept : m_pyObj(pyObj)
+ {
+ assert(pyObj != nullptr);
+ Py_INCREF(m_pyObj);
+ }
+
+ PyObjectHolder(const PyObjectHolder &o) noexcept : m_pyObj(o.m_pyObj)
+ {
+ Py_XINCREF(m_pyObj);
+ }
+
+ PyObjectHolder &operator=(const PyObjectHolder &o) noexcept
+ {
+ if (this != &o) {
+ m_pyObj = o.m_pyObj;
+ Py_XINCREF(m_pyObj);
+ }
+ return *this;
+ }
+
+ PyObjectHolder(PyObjectHolder &&o) noexcept : m_pyObj{std::exchange(o.m_pyObj, nullptr)} {}
+
+ PyObjectHolder &operator=(PyObjectHolder &&o) noexcept
+ {
+ m_pyObj = std::exchange(o.m_pyObj, nullptr);
+ return *this;
+ }
+
+ /// Decref the python reference
+ ~PyObjectHolder() { release(); }
+
+ [[nodiscard]] bool isNull() const { return m_pyObj == nullptr; }
+ [[nodiscard]] operator bool() const { return m_pyObj != nullptr; }
+
+ /// Returns the pointer of the Python object being held.
+ [[nodiscard]] PyObject *object() const { return m_pyObj; }
+ [[nodiscard]] operator PyObject *() const { return m_pyObj; }
+
+ [[nodiscard]] PyObject *operator->() { return m_pyObj; }
+
+protected:
+ void release()
+ {
+ if (m_pyObj != nullptr) {
+ assert(Py_IsInitialized());
+ auto gstate = PyGILState_Ensure();
+ Py_DECREF(m_pyObj);
+ PyGILState_Release(gstate);
+ m_pyObj = nullptr;
+ }
+ }
+
+private:
+ PyObject *m_pyObj = nullptr;
+};
+
+} // namespace Shiboken
+
+#endif // PYOBJECTHOLDER_H
diff --git a/sources/shiboken6/libshiboken/qt_attribution.json b/sources/shiboken6/libshiboken/qt_attribution.json
new file mode 100644
index 000000000..36e7f6868
--- /dev/null
+++ b/sources/shiboken6/libshiboken/qt_attribution.json
@@ -0,0 +1,12 @@
+{
+ "Id": "python",
+ "Name": "Python",
+ "QDocModule": "QtForPython",
+ "QtUsage": "Used for Qt for Python in the signature extension.",
+ "Description": "Qt for Python is an add-on for Python. The libshiboken packages of PySide uses certain parts of the source files (bufferprocs_py37.cpp, bufferprocs_py37.h). See the folder sources/shiboken6/libshiboken .",
+ "Homepage": "http://www.python.org/",
+ "Version": "3.7.0",
+ "License": "PSF LICENSE AGREEMENT FOR PYTHON 3.7.0",
+ "LicenseFile": "bufferprocs_py37.h",
+ "Copyright": "© Copyright 2001-2018, Python Software Foundation."
+}
diff --git a/sources/shiboken6/libshiboken/sbkarrayconverter.cpp b/sources/shiboken6/libshiboken/sbkarrayconverter.cpp
new file mode 100644
index 000000000..bcc3fb767
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkarrayconverter.cpp
@@ -0,0 +1,246 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkarrayconverter.h"
+#include "sbkarrayconverter_p.h"
+#include "helper.h"
+#include "sbkconverter.h"
+#include "sbkconverter_p.h"
+
+#include <longobject.h>
+#include <floatobject.h>
+
+#include <algorithm>
+
+static SbkArrayConverter *ArrayTypeConverters[Shiboken::Conversions::SBK_ARRAY_IDX_SIZE] [2] = {};
+
+namespace Shiboken::Conversions {
+
+// Check whether Predicate is true for all elements of a sequence
+template <class Predicate>
+static bool sequenceAllOf(PyObject *pyIn, Predicate p)
+{
+ const Py_ssize_t size = PySequence_Size(pyIn);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ PyObject *item = PySequence_GetItem(pyIn, i);
+ const bool ok = p(item);
+ Py_XDECREF(item);
+ if (!ok)
+ return false;
+ }
+ return true;
+}
+
+// Convert a sequence to output iterator
+template <class T, class Converter>
+inline void convertPySequence(PyObject *pyIn, Converter c, T *out)
+{
+ const Py_ssize_t size = PySequence_Size(pyIn);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ PyObject *item = PySequence_GetItem(pyIn, i);
+ *out++ = c(item);
+ Py_XDECREF(item);
+ }
+}
+
+// Internal, for usage by numpy
+SbkArrayConverter *createArrayConverter(IsArrayConvertibleToCppFunc toCppCheckFunc)
+{
+ auto *result = new SbkArrayConverter;
+ result->toCppConversions.push_back(toCppCheckFunc);
+ return result;
+}
+
+static PythonToCppFunc unimplementedArrayCheck(PyObject *, int, int)
+{
+ return nullptr;
+}
+
+SbkArrayConverter *unimplementedArrayConverter()
+{
+ static SbkArrayConverter *result = createArrayConverter(unimplementedArrayCheck);
+ return result;
+}
+
+// Integers
+
+static inline bool intCheck(PyObject *pyIn)
+{
+ return PyLong_Check(pyIn);
+}
+
+static short toShort(PyObject *pyIn) { return short(PyLong_AsLong(pyIn)); }
+
+static void sequenceToCppShortArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<short> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, toShort, handle->data());
+}
+
+static inline bool sequenceSizeCheck(PyObject *pyIn, int expectedSize = -1)
+{
+ if (expectedSize >= 0) {
+ const int size = int(PySequence_Size(pyIn));
+ if (size < expectedSize) {
+ warning(PyExc_RuntimeWarning, 0, "A sequence of size %d was passed to a function that expects %d.",
+ size, expectedSize);
+ return false;
+ }
+ }
+ return true;
+}
+
+static inline bool intArrayCheck(PyObject *pyIn, int expectedSize = -1)
+{
+ return PySequence_Check(pyIn) && sequenceAllOf(pyIn, intCheck)
+ && sequenceSizeCheck(pyIn, expectedSize);
+}
+
+static PythonToCppFunc sequenceToCppShortArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppShortArray : nullptr;
+}
+
+static short toUnsignedShort(PyObject *pyIn) { return static_cast<unsigned short>(PyLong_AsUnsignedLong(pyIn)); }
+
+static void sequenceToCppUnsignedShortArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<unsigned short> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, toUnsignedShort, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppUnsignedShortArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppUnsignedShortArray : nullptr;
+}
+
+static void sequenceToCppIntArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<int> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyLong_AsLong, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppIntArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppIntArray : nullptr;
+}
+
+static void sequenceToCppUnsignedArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<unsigned> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyLong_AsUnsignedLong, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppUnsignedArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppUnsignedArray : nullptr;
+}
+
+static void sequenceToCppLongLongArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<long long> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyLong_AsLongLong, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppLongLongArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppLongLongArray : nullptr;
+}
+
+static void sequenceToCppUnsignedLongLongArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<unsigned long long> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyLong_AsUnsignedLongLong, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppUnsignedLongLongArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return intArrayCheck(pyIn, dim1) ? sequenceToCppUnsignedLongLongArray : nullptr;
+}
+
+// Float
+
+static inline bool floatCheck(PyObject *pyIn) { return PyFloat_Check(pyIn); }
+
+static inline bool floatArrayCheck(PyObject *pyIn, int expectedSize = -1)
+{
+ return PySequence_Check(pyIn) && sequenceAllOf(pyIn, floatCheck)
+ && sequenceSizeCheck(pyIn, expectedSize);
+}
+
+static void sequenceToCppDoubleArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<double> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, PyFloat_AsDouble, handle->data());
+}
+
+static inline float pyToFloat(PyObject *pyIn) { return float(PyFloat_AsDouble(pyIn)); }
+
+static void sequenceToCppFloatArray(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<float> *>(cppOut);
+ handle->allocate(PySequence_Size(pyIn));
+ convertPySequence(pyIn, pyToFloat, handle->data());
+}
+
+static PythonToCppFunc sequenceToCppFloatArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return floatArrayCheck(pyIn, dim1) ? sequenceToCppFloatArray : nullptr;
+}
+
+static PythonToCppFunc sequenceToCppDoubleArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return floatArrayCheck(pyIn, dim1) ? sequenceToCppDoubleArray : nullptr;
+}
+
+#ifdef HAVE_NUMPY
+void initNumPyArrayConverters();
+#endif
+
+void initArrayConverters()
+{
+ SbkArrayConverter **start = &ArrayTypeConverters[0][0];
+ std::fill(start, start + sizeof(ArrayTypeConverters) / sizeof(ArrayTypeConverters[0][0]), nullptr);
+ // Populate 1-dimensional sequence converters
+ ArrayTypeConverters[SBK_DOUBLE_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppDoubleArrayCheck);
+ ArrayTypeConverters[SBK_FLOAT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppFloatArrayCheck);
+ ArrayTypeConverters[SBK_SHORT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppShortArrayCheck);
+ ArrayTypeConverters[SBK_UNSIGNEDSHORT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppUnsignedShortArrayCheck);
+ ArrayTypeConverters[SBK_INT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppIntArrayCheck);
+ ArrayTypeConverters[SBK_UNSIGNEDINT_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppUnsignedArrayCheck);
+ ArrayTypeConverters[SBK_LONGLONG_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppLongLongArrayCheck);
+ ArrayTypeConverters[SBK_UNSIGNEDLONGLONG_ARRAY_IDX][0] =
+ createArrayConverter(sequenceToCppUnsignedLongLongArrayCheck);
+
+#ifdef HAVE_NUMPY
+ initNumPyArrayConverters();
+#endif
+}
+
+SbkArrayConverter *arrayTypeConverter(int index, int dimension)
+{
+ SbkArrayConverter *c = ArrayTypeConverters[index][dimension - 1];
+ return c ? c : unimplementedArrayConverter();
+}
+
+// Internal, for usage by numpy
+void setArrayTypeConverter(int index, int dimension, SbkArrayConverter *c)
+{
+ ArrayTypeConverters[index][dimension - 1] = c;
+}
+
+} // namespace Shiboken::Conversions
diff --git a/sources/shiboken6/libshiboken/sbkarrayconverter.h b/sources/shiboken6/libshiboken/sbkarrayconverter.h
new file mode 100644
index 000000000..f07cb1d70
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkarrayconverter.h
@@ -0,0 +1,136 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKARRAYCONVERTERS_H
+#define SBKARRAYCONVERTERS_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+extern "C" {
+struct SbkArrayConverter;
+}
+
+namespace Shiboken::Conversions {
+
+enum : int {
+ SBK_UNIMPLEMENTED_ARRAY_IDX,
+ SBK_DOUBLE_ARRAY_IDX,
+ SBK_FLOAT_ARRAY_IDX,
+ SBK_SHORT_ARRAY_IDX,
+ SBK_UNSIGNEDSHORT_ARRAY_IDX,
+ SBK_INT_ARRAY_IDX,
+ SBK_UNSIGNEDINT_ARRAY_IDX,
+ SBK_LONGLONG_ARRAY_IDX,
+ SBK_UNSIGNEDLONGLONG_ARRAY_IDX,
+ SBK_ARRAY_IDX_SIZE
+};
+
+/**
+ * ArrayHandle is the type expected by shiboken6's array converter
+ * functions. It provides access to array data which it may own
+ * (in the case of conversions from PySequence) or a flat pointer
+ * to internal data (in the case of array modules like numpy).
+ */
+
+template <class T>
+class ArrayHandle
+{
+public:
+ ArrayHandle(const ArrayHandle &) = delete;
+ ArrayHandle& operator=(const ArrayHandle &) = delete;
+ ArrayHandle(ArrayHandle &&) = delete;
+ ArrayHandle& operator=(ArrayHandle &&) = delete;
+
+ ArrayHandle() = default;
+ ~ArrayHandle() { destroy(); }
+
+ void allocate(Py_ssize_t size);
+ void setData(T *d, size_t size);
+
+ size_t size() const { return m_size; }
+ T *data() const { return m_data; }
+ operator T *() const { return m_data; }
+
+private:
+ void destroy();
+
+ T *m_data = nullptr;
+ Py_ssize_t m_size = 0;
+ bool m_owned = false;
+};
+
+/**
+ * Similar to ArrayHandle for fixed size 2 dimensional arrays.
+ * columns is the size of the last dimension
+ * It only has a setData() methods since it will be used for numpy only.
+ */
+
+template <class T, int columns>
+class Array2Handle
+{
+public:
+ typedef T RowType[columns];
+
+ Array2Handle() = default;
+
+ operator RowType *() const { return m_rows; }
+
+ void setData(RowType *d) { m_rows = d; }
+
+private:
+ RowType *m_rows = nullptr;
+};
+
+/// Returns the converter for an array type.
+LIBSHIBOKEN_API SbkArrayConverter *arrayTypeConverter(int index, int dimension = 1);
+
+template <class T>
+struct ArrayTypeIndex{
+ enum : int { index = SBK_UNIMPLEMENTED_ARRAY_IDX };
+};
+
+template <> struct ArrayTypeIndex<double> { enum : int { index = SBK_DOUBLE_ARRAY_IDX }; };
+template <> struct ArrayTypeIndex<float> { enum : int { index = SBK_FLOAT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<short> { enum : int { index = SBK_SHORT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<unsigned short> { enum : int { index = SBK_UNSIGNEDSHORT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<int> { enum : int { index = SBK_INT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<unsigned> { enum : int { index = SBK_UNSIGNEDINT_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<long long> { enum : int { index = SBK_LONGLONG_ARRAY_IDX };};
+template <> struct ArrayTypeIndex<unsigned long long> { enum : int { index = SBK_UNSIGNEDLONGLONG_ARRAY_IDX };};
+
+template<typename T> SbkArrayConverter *ArrayTypeConverter(int dimension)
+{ return arrayTypeConverter(ArrayTypeIndex<T>::index, dimension); }
+
+// ArrayHandle methods
+template<class T>
+void ArrayHandle<T>::allocate(Py_ssize_t size)
+{
+ destroy();
+ m_data = new T[size];
+ m_size = size;
+ m_owned = true;
+}
+
+template<class T>
+void ArrayHandle<T>::setData(T *d, size_t size)
+{
+ destroy();
+ m_data = d;
+ m_size = size;
+ m_owned = false;
+}
+
+template<class T>
+void ArrayHandle<T>::destroy()
+{
+ if (m_owned)
+ delete [] m_data;
+ m_data = nullptr;
+ m_size = 0;
+ m_owned = false;
+}
+
+} // namespace Shiboken::Conversions
+
+#endif // SBKARRAYCONVERTERS_H
diff --git a/sources/shiboken6/libshiboken/sbkarrayconverter_p.h b/sources/shiboken6/libshiboken/sbkarrayconverter_p.h
new file mode 100644
index 000000000..63d03fb12
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkarrayconverter_p.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKARRAYCONVERTER_P_H
+#define SBKARRAYCONVERTER_P_H
+
+#include "sbkconverter_p.h"
+#include <vector>
+
+extern "C"
+{
+
+using IsArrayConvertibleToCppFunc = PythonToCppFunc (*)(PyObject *, int dim1, int dim2);
+/**
+ * \internal
+ * Private structure of SbkArrayConverter.
+ */
+
+struct SbkArrayConverter
+{
+ std::vector<IsArrayConvertibleToCppFunc> toCppConversions;
+};
+
+} // extern "C"
+
+#endif // SBKARRAYCONVERTER_P_H
diff --git a/sources/shiboken6/libshiboken/sbkcontainer.cpp b/sources/shiboken6/libshiboken/sbkcontainer.cpp
new file mode 100644
index 000000000..7de1f03e6
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcontainer.cpp
@@ -0,0 +1,19 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkcontainer.h"
+#include "sbkstaticstrings.h"
+#include "autodecref.h"
+
+namespace Shiboken
+{
+bool isOpaqueContainer(PyObject *o)
+{
+ if (!o)
+ return false;
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(o->ob_type));
+ return o != nullptr && o != Py_None
+ && PyDict_Contains(tpDict.object(), Shiboken::PyMagicName::opaque_container()) == 1;
+
+}
+} // Shiboken
diff --git a/sources/shiboken6/libshiboken/sbkcontainer.h b/sources/shiboken6/libshiboken/sbkcontainer.h
new file mode 100644
index 000000000..8ad5aadc6
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcontainer.h
@@ -0,0 +1,259 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_CONTAINER_H
+#define SBK_CONTAINER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+#include "shibokenbuffer.h"
+
+#include <algorithm>
+#include <iterator>
+#include <optional>
+#include <utility>
+
+extern "C"
+{
+struct LIBSHIBOKEN_API ShibokenContainer
+{
+ PyObject_HEAD
+ void *d;
+};
+
+} // extern "C"
+
+// Conversion helper traits for container values (Keep it out of namespace as
+// otherwise clashes occur).
+template <class Value>
+struct ShibokenContainerValueConverter
+{
+ static bool checkValue(PyObject *pyArg);
+ static PyObject *convertValueToPython(Value v);
+ static std::optional<Value> convertValueToCpp(PyObject pyArg);
+};
+
+// SFINAE test for the presence of reserve() in a sequence container (std::vector/QList)
+template <typename T>
+class ShibokenContainerHasReserve
+{
+private:
+ using YesType = char[1];
+ using NoType = char[2];
+
+ template <typename C> static YesType& test( decltype(&C::reserve) ) ;
+ template <typename C> static NoType& test(...);
+
+public:
+ enum { value = sizeof(test<T>(nullptr)) == sizeof(YesType) };
+};
+
+template <class SequenceContainer>
+class ShibokenSequenceContainerPrivate // Helper for sequence type containers
+{
+public:
+ using value_type = typename SequenceContainer::value_type;
+ using OptionalValue = typename std::optional<value_type>;
+
+ SequenceContainer *m_list{};
+ bool m_ownsList = false;
+ bool m_const = false;
+ static constexpr const char *msgModifyConstContainer =
+ "Attempt to modify a constant container.";
+
+ static PyObject *tpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
+ {
+ allocfunc allocFunc = reinterpret_cast<allocfunc>(PepType_GetSlot(subtype, Py_tp_alloc));
+ auto *me = reinterpret_cast<ShibokenContainer *>(allocFunc(subtype, 0));
+ auto *d = new ShibokenSequenceContainerPrivate;
+ d->m_list = new SequenceContainer;
+ d->m_ownsList = true;
+ me->d = d;
+ return reinterpret_cast<PyObject *>(me);
+ }
+
+ static PyObject *tpNewInvalid(PyTypeObject * /* subtype */, PyObject * /* args */, PyObject * /* kwds */)
+ {
+ return PyErr_Format(PyExc_NotImplementedError,
+ "Opaque containers of type '%s' cannot be instantiated.",
+ typeid(SequenceContainer).name());
+ }
+
+ static int tpInit(PyObject * /* self */, PyObject * /* args */, PyObject * /* kwds */)
+ {
+ return 0;
+ }
+
+ static void tpFree(void *self)
+ {
+ auto *pySelf = reinterpret_cast<PyObject *>(self);
+ auto *d = get(pySelf);
+ if (d->m_ownsList)
+ delete d->m_list;
+ delete d;
+ auto freeFunc = reinterpret_cast<freefunc>(PepType_GetSlot(Py_TYPE(pySelf)->tp_base,
+ Py_tp_free));
+ freeFunc(self);
+ }
+
+ static Py_ssize_t sqLen(PyObject *self)
+ {
+ return get(self)->m_list->size();
+ }
+
+ static PyObject *sqGetItem(PyObject *self, Py_ssize_t i)
+ {
+ auto *d = get(self);
+ 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);
+ }
+
+ static int sqSetItem(PyObject *self, Py_ssize_t i, PyObject *pyArg)
+ {
+ auto *d = get(self);
+ if (i < 0 || i >= Py_ssize_t(d->m_list->size())) {
+ PyErr_SetString(PyExc_IndexError, "index out of bounds");
+ return -1;
+ }
+ auto it = std::begin(*d->m_list);
+ std::advance(it, i);
+ OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
+ if (!value.has_value())
+ return -1;
+ *it = value.value();
+ return 0;
+ }
+
+ static PyObject *push_back(PyObject *self, PyObject *pyArg)
+ {
+ auto *d = get(self);
+ 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())
+ return nullptr;
+ d->m_list->push_back(value.value());
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *push_front(PyObject *self, PyObject *pyArg)
+ {
+ auto *d = get(self);
+ 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())
+ return nullptr;
+ d->m_list->push_front(value.value());
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *clear(PyObject *self)
+ {
+ auto *d = get(self);
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
+
+ d->m_list->clear();
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *pop_back(PyObject *self)
+ {
+ auto *d = get(self);
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
+
+ d->m_list->pop_back();
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *pop_front(PyObject *self)
+ {
+ auto *d = get(self);
+ if (d->m_const)
+ return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
+
+ d->m_list->pop_front();
+ Py_RETURN_NONE;
+ }
+
+ // Support for containers with reserve/capacity
+ static PyObject *reserve(PyObject *self, PyObject *pyArg)
+ {
+ auto *d = get(self);
+ 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 {
+ return PyErr_Format(PyExc_TypeError, "Container does not support reserve().");
+ }
+
+ Py_RETURN_NONE;
+ }
+
+ static PyObject *capacity(PyObject *self)
+ {
+ Py_ssize_t result = -1;
+ if constexpr (ShibokenContainerHasReserve<SequenceContainer>::value) {
+ const auto *d = get(self);
+ result = d->m_list->capacity();
+ }
+ return PyLong_FromSsize_t(result);
+ }
+
+ static PyObject *data(PyObject *self)
+ {
+ PyObject *result = nullptr;
+ if constexpr (ShibokenContainerHasReserve<SequenceContainer>::value) {
+ const auto *d = get(self);
+ auto *data = d->m_list->data();
+ const Py_ssize_t size = sizeof(value_type) * d->m_list->size();
+ result = Shiboken::Buffer::newObject(data, size, Shiboken::Buffer::ReadWrite);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Container does not support data().");
+ }
+ return result;
+ }
+
+ static PyObject *constData(PyObject *self)
+ {
+ PyObject *result = nullptr;
+ if constexpr (ShibokenContainerHasReserve<SequenceContainer>::value) {
+ const auto *d = get(self);
+ const auto *data = std::as_const(d->m_list)->data();
+ const Py_ssize_t size = sizeof(value_type) * d->m_list->size();
+ result = Shiboken::Buffer::newObject(data, size);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Container does not support constData().");
+ }
+ return result;
+ }
+
+ static ShibokenSequenceContainerPrivate *get(PyObject *self)
+ {
+ auto *data = reinterpret_cast<ShibokenContainer *>(self);
+ return reinterpret_cast<ShibokenSequenceContainerPrivate *>(data->d);
+ }
+};
+
+namespace Shiboken
+{
+LIBSHIBOKEN_API bool isOpaqueContainer(PyObject *o);
+}
+
+#endif // SBK_CONTAINER_H
diff --git a/sources/shiboken6/libshiboken/sbkconverter.cpp b/sources/shiboken6/libshiboken/sbkconverter.cpp
new file mode 100644
index 000000000..9ab674415
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkconverter.cpp
@@ -0,0 +1,910 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkconverter.h"
+#include "sbkconverter_p.h"
+#include "sbkarrayconverter_p.h"
+#include "sbkmodule.h"
+#include "basewrapper_p.h"
+#include "bindingmanager.h"
+#include "autodecref.h"
+#include "helper.h"
+#include "voidptr.h"
+
+#include <string>
+#include <cstring>
+#include <iostream>
+#include <unordered_map>
+#include <unordered_set>
+#include <map>
+#include <set>
+
+static SbkConverter **PrimitiveTypeConverters;
+
+using ConvertersMap = std::unordered_map<std::string, SbkConverter *>;
+static ConvertersMap converters;
+
+namespace Shiboken::Conversions {
+
+void initArrayConverters();
+
+void init()
+{
+ static SbkConverter *primitiveTypeConverters[] = {
+ Primitive<PY_LONG_LONG>::createConverter(),
+ Primitive<bool>::createConverter(),
+ Primitive<char>::createConverter(),
+ Primitive<const char *>::createConverter(),
+ Primitive<double>::createConverter(),
+ Primitive<float>::createConverter(),
+ Primitive<int>::createConverter(),
+ Primitive<long>::createConverter(),
+ Primitive<short>::createConverter(),
+ Primitive<signed char>::createConverter(),
+ Primitive<std::string>::createConverter(),
+ Primitive<std::wstring>::createConverter(),
+ Primitive<unsigned PY_LONG_LONG>::createConverter(),
+ Primitive<unsigned char>::createConverter(),
+ Primitive<unsigned int>::createConverter(),
+ Primitive<unsigned long>::createConverter(),
+ Primitive<unsigned short>::createConverter(),
+ VoidPtr::createConverter(),
+ Primitive<std::nullptr_t>::createConverter()
+ };
+ PrimitiveTypeConverters = primitiveTypeConverters;
+
+ assert(converters.empty());
+ converters["PY_LONG_LONG"] = primitiveTypeConverters[SBK_PY_LONG_LONG_IDX];
+ converters["bool"] = primitiveTypeConverters[SBK_BOOL_IDX_1];
+ converters["char"] = primitiveTypeConverters[SBK_CHAR_IDX];
+ converters["const char *"] = primitiveTypeConverters[SBK_CONSTCHARPTR_IDX];
+ converters["double"] = primitiveTypeConverters[SBK_DOUBLE_IDX];
+ converters["float"] = primitiveTypeConverters[SBK_FLOAT_IDX];
+ converters["int"] = primitiveTypeConverters[SBK_INT_IDX];
+ converters["long"] = primitiveTypeConverters[SBK_LONG_IDX];
+ converters["short"] = primitiveTypeConverters[SBK_SHORT_IDX];
+ converters["signed char"] = primitiveTypeConverters[SBK_SIGNEDCHAR_IDX];
+ converters["std::string"] = primitiveTypeConverters[SBK_STD_STRING_IDX];
+ converters["std::wstring"] = primitiveTypeConverters[SBK_STD_WSTRING_IDX];
+ converters["unsigned PY_LONG_LONG"] = primitiveTypeConverters[SBK_UNSIGNEDPY_LONG_LONG_IDX];
+ converters["unsigned char"] = primitiveTypeConverters[SBK_UNSIGNEDCHAR_IDX];
+ converters["unsigned int"] = primitiveTypeConverters[SBK_UNSIGNEDINT_IDX];
+ converters["unsigned long"] = primitiveTypeConverters[SBK_UNSIGNEDLONG_IDX];
+ converters["unsigned short"] = primitiveTypeConverters[SBK_UNSIGNEDSHORT_IDX];
+ converters["void*"] = primitiveTypeConverters[SBK_VOIDPTR_IDX];
+ converters["std::nullptr_t"] = primitiveTypeConverters[SBK_NULLPTR_T_IDX];
+
+ 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,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc)
+{
+ auto converter = new SbkConverter;
+ converter->pythonType = type;
+ // PYSIDE-595: All types are heaptypes now, so provide reference.
+ Py_XINCREF(type);
+
+ converter->pointerToPython = pointerToPythonFunc;
+ converter->copyToPython = copyToPythonFunc;
+
+ if (toCppPointerCheckFunc && toCppPointerConvFunc)
+ converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc);
+ converter->toCppConversions.clear();
+
+ return converter;
+}
+
+SbkConverter *createConverter(PyTypeObject *type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc)
+{
+ SbkConverter *converter =
+ createConverterObject(type,
+ toCppPointerConvFunc, toCppPointerCheckFunc,
+ pointerToPythonFunc, copyToPythonFunc);
+ PepType_SOTP(type)->converter = converter;
+ return converter;
+}
+
+SbkConverter *createConverter(PyTypeObject *type, CppToPythonFunc toPythonFunc)
+{
+ return createConverterObject(type, nullptr, nullptr, nullptr, toPythonFunc);
+}
+
+void deleteConverter(SbkConverter *converter)
+{
+ if (converter) {
+ converter->toCppConversions.clear();
+ delete converter;
+ }
+}
+
+void setCppPointerToPythonFunction(SbkConverter *converter, CppToPythonFunc pointerToPythonFunc)
+{
+ converter->pointerToPython = pointerToPythonFunc;
+}
+
+void setPythonToCppPointerFunctions(SbkConverter *converter,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc)
+{
+ converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc);
+}
+
+void addPythonToCppValueConversion(SbkConverter *converter,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+ converter->toCppConversions.push_back(std::make_pair(isConvertibleToCppFunc, pythonToCppFunc));
+}
+
+void addPythonToCppValueConversion(PyTypeObject *type,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+ auto *sotp = PepType_SOTP(type);
+ addPythonToCppValueConversion(sotp->converter, pythonToCppFunc, isConvertibleToCppFunc);
+}
+
+void addPythonToCppValueConversion(Shiboken::Module::TypeInitStruct typeStruct,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+ addPythonToCppValueConversion(typeStruct.type, pythonToCppFunc, isConvertibleToCppFunc);
+}
+
+PyObject *pointerToPython(PyTypeObject *type, const void *cppIn)
+{
+ auto *sotp = PepType_SOTP(type);
+ return pointerToPython(sotp->converter, cppIn);
+}
+
+PyObject *pointerToPython(const SbkConverter *converter, const void *cppIn)
+{
+ assert(converter);
+ if (!cppIn)
+ Py_RETURN_NONE;
+ if (!converter->pointerToPython) {
+ warning(PyExc_RuntimeWarning, 0, "pointerToPython(): SbkConverter::pointerToPython is null for \"%s\".",
+ converter->pythonType->tp_name);
+ Py_RETURN_NONE;
+ }
+ return converter->pointerToPython(cppIn);
+}
+
+PyObject *referenceToPython(PyTypeObject *type, const void *cppIn)
+{
+ auto *sotp = PepType_SOTP(type);
+ return referenceToPython(sotp->converter, cppIn);
+}
+
+PyObject *referenceToPython(const SbkConverter *converter, const void *cppIn)
+{
+ assert(cppIn);
+
+ auto *pyOut = reinterpret_cast<PyObject *>(BindingManager::instance().retrieveWrapper(cppIn));
+ if (pyOut) {
+ Py_INCREF(pyOut);
+ return pyOut;
+ }
+ if (!converter->pointerToPython) {
+ warning(PyExc_RuntimeWarning, 0, "referenceToPython(): SbkConverter::pointerToPython is null for \"%s\".",
+ converter->pythonType->tp_name);
+ Py_RETURN_NONE;
+ }
+ return converter->pointerToPython(cppIn);
+}
+
+static inline PyObject *CopyCppToPython(const SbkConverter *converter, const void *cppIn)
+{
+ if (!cppIn)
+ Py_RETURN_NONE;
+ if (!converter->copyToPython) {
+ warning(PyExc_RuntimeWarning, 0, "CopyCppToPython(): SbkConverter::copyToPython is null for \"%s\".",
+ converter->pythonType->tp_name);
+ Py_RETURN_NONE;
+ }
+ return converter->copyToPython(cppIn);
+}
+
+PyObject *copyToPython(PyTypeObject *type, const void *cppIn)
+{
+ auto *sotp = PepType_SOTP(type);
+ return CopyCppToPython(sotp->converter, cppIn);
+}
+
+PyObject *copyToPython(const SbkConverter *converter, const void *cppIn)
+{
+ return CopyCppToPython(converter, cppIn);
+}
+
+PythonToCppFunc isPythonToCppPointerConvertible(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(pyIn);
+ auto *sotp = PepType_SOTP(type);
+ return sotp->converter->toCppPointerConversion.first(pyIn);
+}
+
+PythonToCppConversion pythonToCppPointerConversion(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn == nullptr)
+ return {};
+ if (PythonToCppFunc toCppPtr = isPythonToCppPointerConvertible(type, pyIn))
+ return {toCppPtr, PythonToCppConversion::Pointer};
+ return {};
+}
+
+PythonToCppConversion pythonToCppPointerConversion(Module::TypeInitStruct typeStruct, PyObject *pyIn)
+{
+ return pythonToCppPointerConversion(typeStruct.type, pyIn);
+}
+
+static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn)
+{
+ assert(pyIn);
+ for (const ToCppConversion &c : converter->toCppConversions) {
+ if (PythonToCppFunc toCppFunc = c.first(pyIn))
+ return toCppFunc;
+ }
+ return nullptr;
+}
+
+PythonToCppFunc isPythonToCppValueConvertible(PyTypeObject *type, PyObject *pyIn)
+{
+ auto *sotp = PepType_SOTP(type);
+ return IsPythonToCppConvertible(sotp->converter, pyIn);
+}
+
+PythonToCppConversion pythonToCppValueConversion(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn == nullptr)
+ return {};
+ if (PythonToCppFunc toCppVal = isPythonToCppValueConvertible(type, pyIn))
+ return {toCppVal, PythonToCppConversion::Value};
+ return {};
+}
+
+PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn)
+{
+ return IsPythonToCppConvertible(converter, pyIn);
+}
+
+PythonToCppConversion pythonToCppReferenceConversion(const SbkConverter *converter, PyObject *pyIn)
+{
+ if (converter->toCppPointerConversion.first) {
+ if (auto toCppPtr = converter->toCppPointerConversion.first(pyIn))
+ return {toCppPtr, PythonToCppConversion::Pointer};
+ }
+ for (const ToCppConversion &c : converter->toCppConversions) {
+ if (PythonToCppFunc toCppFunc = c.first(pyIn))
+ return {toCppFunc, PythonToCppConversion::Value};
+ }
+ return {};
+}
+
+PythonToCppConversion pythonToCppConversion(const SbkConverter *converter, PyObject *pyIn)
+{
+ if (auto func = IsPythonToCppConvertible(converter, pyIn))
+ return {func, PythonToCppConversion::Value};
+ return {};
+}
+
+PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter,
+ int dim1, int dim2, PyObject *pyIn)
+{
+ assert(pyIn);
+ for (IsArrayConvertibleToCppFunc f : converter->toCppConversions) {
+ if (PythonToCppFunc c = f(pyIn, dim1, dim2))
+ return c;
+ }
+ return nullptr;
+}
+
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppConversion(const SbkArrayConverter *converter,
+ int dim1, int dim2, PyObject *pyIn)
+{
+ if (auto func = isPythonToCppConvertible(converter, dim1, dim2, pyIn))
+ return {func, PythonToCppConversion::Value};
+ return {};
+}
+
+PythonToCppFunc isPythonToCppReferenceConvertible(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn != Py_None) {
+ PythonToCppFunc toCpp = isPythonToCppPointerConvertible(type, pyIn);
+ if (toCpp)
+ return toCpp;
+ }
+ return isPythonToCppValueConvertible(type, pyIn);
+}
+
+PythonToCppConversion pythonToCppReferenceConversion(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn == nullptr)
+ return {};
+ if (pyIn != Py_None) {
+ if (PythonToCppFunc toCppPtr = isPythonToCppPointerConvertible(type, pyIn))
+ return {toCppPtr, PythonToCppConversion::Pointer};
+ }
+ if (PythonToCppFunc toCppVal = isPythonToCppValueConvertible(type, pyIn))
+ return {toCppVal, PythonToCppConversion::Value};
+ return {};
+}
+
+void nonePythonToCppNullPtr(PyObject *, void *cppOut)
+{
+ assert(cppOut);
+ *static_cast<void **>(cppOut) = nullptr;
+}
+
+void *cppPointer(PyTypeObject *desiredType, SbkObject *pyIn)
+{
+ assert(pyIn);
+ if (!ObjectType::checkType(desiredType))
+ return pyIn;
+ auto *inType = Py_TYPE(pyIn);
+ if (ObjectType::hasCast(inType))
+ return ObjectType::cast(inType, pyIn, desiredType);
+ return Object::cppPointer(pyIn, desiredType);
+}
+
+void pythonToCppPointer(PyTypeObject *type, PyObject *pyIn, void *cppOut)
+{
+ assert(type);
+ assert(pyIn);
+ assert(cppOut);
+ *reinterpret_cast<void **>(cppOut) = pyIn == Py_None
+ ? nullptr
+ : cppPointer(type, reinterpret_cast<SbkObject *>(pyIn));
+}
+
+void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut)
+{
+ assert(converter);
+ assert(pyIn);
+ assert(cppOut);
+ *reinterpret_cast<void **>(cppOut) = pyIn == Py_None
+ ? nullptr
+ : cppPointer(converter->pythonType, reinterpret_cast<SbkObject *>(pyIn));
+}
+
+static void _pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut)
+{
+ assert(converter);
+ assert(pyIn);
+ assert(cppOut);
+ PythonToCppFunc toCpp = IsPythonToCppConvertible(converter, pyIn);
+ if (toCpp)
+ toCpp(pyIn, cppOut);
+}
+
+void pythonToCppCopy(PyTypeObject *type, PyObject *pyIn, void *cppOut)
+{
+ assert(type);
+ auto *sotp = PepType_SOTP(type);
+ _pythonToCppCopy(sotp->converter, pyIn, cppOut);
+}
+
+void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut)
+{
+ _pythonToCppCopy(converter, pyIn, cppOut);
+}
+
+bool isImplicitConversion(PyTypeObject *type, PythonToCppFunc toCppFunc)
+{
+ auto *sotp = PepType_SOTP(type);
+ // This is the Object Type or Value Type conversion that only
+ // retrieves the C++ pointer held in the Python wrapper.
+ if (toCppFunc == sotp->converter->toCppPointerConversion.second)
+ return false;
+
+ // Object Types doesn't have any kind of value conversion,
+ // only C++ pointer retrieval.
+ if (sotp->converter->toCppConversions.empty())
+ return false;
+
+ // The first conversion of the non-pointer conversion list is
+ // a Value Type's copy to C++ function, which is not an implicit
+ // conversion.
+ // Otherwise it must be one of the implicit conversions.
+ // Note that we don't check if the Python to C++ conversion is in
+ // the list of the type's conversions, for it is expected that the
+ // caller knows what he's doing.
+ const auto conv = sotp->converter->toCppConversions.cbegin();
+ return toCppFunc != (*conv).second;
+}
+
+void registerConverterName(SbkConverter *converter, const char *typeName)
+{
+ auto iter = converters.find(typeName);
+ if (iter == converters.end())
+ converters.insert(std::make_pair(typeName, converter));
+}
+
+static std::string getRealTypeName(const std::string &typeName)
+{
+ auto size = typeName.size();
+ if (std::isalnum(typeName[size - 1]) == 0)
+ return typeName.substr(0, size - 1);
+ return 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
+ // which have this name and try again.
+ Shiboken::Module::loadLazyClassesWithName(getRealTypeName(typeName).c_str());
+ 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 + "'.";
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.c_str(), 0);
+ }
+ 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];
+}
+
+bool checkIterableTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ Shiboken::AutoDecRef it(PyObject_GetIter(pyIn));
+ if (it.isNull()) {
+ PyErr_Clear();
+ return false;
+ }
+
+ while (true) {
+ Shiboken::AutoDecRef pyItem(PyIter_Next(it.object()));
+ if (pyItem.isNull()) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ break;
+ }
+ if (!PyObject_TypeCheck(pyItem, type))
+ return false;
+ }
+ return true;
+}
+
+bool checkSequenceTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(type);
+ assert(pyIn);
+ if (PySequence_Size(pyIn) < 0) {
+ // clear the error if < 0 which means no length at all
+ PyErr_Clear();
+ return false;
+ }
+ const Py_ssize_t size = PySequence_Size(pyIn);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, i)), type))
+ return false;
+ }
+ return true;
+}
+
+bool convertibleIterableTypes(const SbkConverter *converter, PyObject *pyIn)
+{
+ Shiboken::AutoDecRef it(PyObject_GetIter(pyIn));
+ if (it.isNull()) {
+ PyErr_Clear();
+ return false;
+ }
+
+ while (true) {
+ Shiboken::AutoDecRef pyItem(PyIter_Next(it.object()));
+ if (pyItem.isNull()) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ break;
+ }
+ if (!isPythonToCppConvertible(converter, pyItem))
+ return false;
+ }
+ return true;
+}
+
+bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn)
+{
+ assert(converter);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ const Py_ssize_t size = PySequence_Size(pyIn);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ if (!isPythonToCppConvertible(converter, AutoDecRef(PySequence_GetItem(pyIn, i))))
+ return false;
+ }
+ return true;
+}
+bool convertibleSequenceTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(type);
+ auto *sotp = PepType_SOTP(type);
+ return convertibleSequenceTypes(sotp->converter, pyIn);
+}
+
+bool convertibleIterableTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(type);
+ auto *sotp = PepType_SOTP(type);
+ return convertibleIterableTypes(sotp->converter, pyIn);
+}
+
+bool checkPairTypes(PyTypeObject *firstType, PyTypeObject *secondType, PyObject *pyIn)
+{
+ assert(firstType);
+ assert(secondType);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ if (PySequence_Size(pyIn) != 2)
+ return false;
+ if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, 0)), firstType))
+ return false;
+ if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, 1)), secondType))
+ return false;
+ return true;
+}
+bool convertiblePairTypes(const SbkConverter *firstConverter, bool firstCheckExact,
+ const SbkConverter *secondConverter, bool secondCheckExact,
+ PyObject *pyIn)
+{
+ assert(firstConverter);
+ assert(secondConverter);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ if (PySequence_Size(pyIn) != 2)
+ return false;
+ AutoDecRef firstItem(PySequence_GetItem(pyIn, 0));
+ if (firstCheckExact) {
+ if (!PyObject_TypeCheck(firstItem, firstConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(firstConverter, firstItem)) {
+ return false;
+ }
+ AutoDecRef secondItem(PySequence_GetItem(pyIn, 1));
+ if (secondCheckExact) {
+ if (!PyObject_TypeCheck(secondItem, secondConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(secondConverter, secondItem)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool checkDictTypes(PyTypeObject *keyType, PyTypeObject *valueType, PyObject *pyIn)
+{
+ assert(keyType);
+ assert(valueType);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+
+ PyObject *key;
+ PyObject *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &value)) {
+ if (!PyObject_TypeCheck(key, keyType))
+ return false;
+ if (!PyObject_TypeCheck(value, valueType))
+ return false;
+ }
+ return true;
+}
+
+bool checkMultiDictTypes(PyTypeObject *keyType, PyTypeObject *valueType,
+ PyObject *pyIn)
+{
+ assert(keyType);
+ assert(valueType);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+
+ PyObject *key;
+ PyObject *values;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &values)) {
+ if (!PyObject_TypeCheck(key, keyType))
+ return false;
+ if (!PySequence_Check(values))
+ return false;
+ const Py_ssize_t size = PySequence_Size(values);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ AutoDecRef value(PySequence_GetItem(values, i));
+ if (!PyObject_TypeCheck(value, valueType))
+ return false;
+ }
+ }
+ return true;
+}
+
+bool convertibleDictTypes(const SbkConverter *keyConverter, bool keyCheckExact, const SbkConverter *valueConverter,
+ bool valueCheckExact, PyObject *pyIn)
+{
+ assert(keyConverter);
+ assert(valueConverter);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+ PyObject *key;
+ PyObject *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &value)) {
+ if (keyCheckExact) {
+ if (!PyObject_TypeCheck(key, keyConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(keyConverter, key)) {
+ return false;
+ }
+ if (valueCheckExact) {
+ if (!PyObject_TypeCheck(value, valueConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(valueConverter, value)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool convertibleMultiDictTypes(const SbkConverter *keyConverter, bool keyCheckExact,
+ const SbkConverter *valueConverter,
+ bool valueCheckExact, PyObject *pyIn)
+{
+ assert(keyConverter);
+ assert(valueConverter);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+ PyObject *key;
+ PyObject *values;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &values)) {
+ if (keyCheckExact) {
+ if (!PyObject_TypeCheck(key, keyConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(keyConverter, key)) {
+ return false;
+ }
+ if (!PySequence_Check(values))
+ return false;
+ const Py_ssize_t size = PySequence_Size(values);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ AutoDecRef value(PySequence_GetItem(values, i));
+ if (valueCheckExact) {
+ if (!PyObject_TypeCheck(value.object(), valueConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(valueConverter, value.object())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+PyTypeObject *getPythonTypeObject(const SbkConverter *converter)
+{
+ if (converter)
+ return converter->pythonType;
+ return nullptr;
+}
+
+PyTypeObject *getPythonTypeObject(const char *typeName)
+{
+ return getPythonTypeObject(getConverter(typeName));
+}
+
+bool pythonTypeIsValueType(const SbkConverter *converter)
+{
+ // Unlikely to happen but for multi-inheritance SbkObjs
+ // the converter is not defined, hence we need a default return.
+ if (!converter)
+ return false;
+ return converter->pointerToPython && converter->copyToPython;
+}
+
+bool pythonTypeIsObjectType(const SbkConverter *converter)
+{
+ return converter->pointerToPython && !converter->copyToPython;
+}
+
+bool pythonTypeIsWrapperType(const SbkConverter *converter)
+{
+ return converter->pointerToPython != nullptr;
+}
+
+SpecificConverter::SpecificConverter(const char *typeName)
+ : m_type(InvalidConversion)
+{
+ m_converter = getConverter(typeName);
+ if (!m_converter)
+ return;
+ const Py_ssize_t len = strlen(typeName);
+ char lastChar = typeName[len -1];
+ if (lastChar == '&') {
+ m_type = ReferenceConversion;
+ } else if (lastChar == '*' || pythonTypeIsObjectType(m_converter)) {
+ m_type = PointerConversion;
+ } else {
+ m_type = CopyConversion;
+ }
+}
+
+PyObject *SpecificConverter::toPython(const void *cppIn)
+{
+ switch (m_type) {
+ case CopyConversion:
+ return copyToPython(m_converter, cppIn);
+ case PointerConversion:
+ return pointerToPython(m_converter, *static_cast<const void * const *>(cppIn));
+ case ReferenceConversion:
+ return referenceToPython(m_converter, cppIn);
+ default:
+ PyErr_SetString(PyExc_RuntimeError, "tried to use invalid converter in 'C++ to Python' conversion");
+ }
+ return nullptr;
+}
+
+void SpecificConverter::toCpp(PyObject *pyIn, void *cppOut)
+{
+ switch (m_type) {
+ case CopyConversion:
+ pythonToCppCopy(m_converter, pyIn, cppOut);
+ break;
+ case PointerConversion:
+ pythonToCppPointer(m_converter, pyIn, cppOut);
+ break;
+ case ReferenceConversion:
+ pythonToCppPointer(m_converter, pyIn, &cppOut);
+ break;
+ default:
+ PyErr_SetString(PyExc_RuntimeError, "tried to use invalid converter in 'Python to C++' conversion");
+ }
+}
+
+} // namespace Shiboken::Conversions
diff --git a/sources/shiboken6/libshiboken/sbkconverter.h b/sources/shiboken6/libshiboken/sbkconverter.h
new file mode 100644
index 000000000..0d68f3faf
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkconverter.h
@@ -0,0 +1,422 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_CONVERTER_H
+#define SBK_CONVERTER_H
+
+#include "sbkpython.h"
+#include "sbkmodule.h"
+#include "shibokenmacros.h"
+#include "sbkenum.h"
+#include "basewrapper_p.h"
+
+#include <limits>
+#include <string>
+
+struct SbkObject;
+
+/**
+ * This is a convenience macro identical to Python's PyObject_TypeCheck,
+ * except that the arguments have swapped places, for the great convenience
+ * of generator.
+ */
+#define SbkObject_TypeCheck(tp, ob) \
+ (Py_TYPE(ob) == (tp) || PyType_IsSubtype(Py_TYPE(ob), (tp)))
+
+extern "C"
+{
+
+/**
+ * SbkConverter is used to perform type conversions from C++
+ * to Python and vice-versa;.and it is also used for type checking.
+ * SbkConverter is a private structure that must be accessed
+ * using the functions provided by the converter API.
+ */
+struct SbkConverter;
+struct SbkArrayConverter;
+
+/**
+ * Given a void pointer to a C++ object, this function must return
+ * the proper Python object. It may be either an existing wrapper
+ * for the C++ object, or a newly create one. Or even the Python
+ * equivalent of the C++ value passed in the argument.
+ *
+ * C++ -> Python
+ */
+using CppToPythonFunc = PyObject *(*)(const void *);
+
+/**
+ * This function converts a Python object to a C++ value, it may be
+ * a pointer, value, class, container or primitive type, passed via
+ * a void pointer, that will be cast properly inside the function.
+ * This function is usually returned by an IsConvertibleToCppFunc
+ * function, or obtained knowing the type of the Python object input,
+ * thus it will not check the Python object type, and will expect
+ * the void pointer to be pointing to a proper variable.
+ *
+ * Python -> C++
+ */
+using PythonToCppFunc = void (*)(PyObject *,void *);
+
+/**
+ * Checks if the Python object passed in the argument is convertible to a
+ * C++ type defined inside the function, it returns the converter function
+ * that will transform a Python argument into a C++ value.
+ * It returns NULL if the Python object is not convertible to the C++ type
+ * that the function represents.
+ *
+ * Python -> C++ ?
+ */
+using IsConvertibleToCppFunc = PythonToCppFunc (*)(PyObject *);
+
+} // extern "C"
+
+namespace Shiboken {
+namespace Conversions {
+
+
+class LIBSHIBOKEN_API SpecificConverter
+{
+public:
+ enum Type
+ {
+ InvalidConversion,
+ CopyConversion,
+ PointerConversion,
+ ReferenceConversion
+ };
+
+ explicit SpecificConverter(const char *typeName);
+
+ inline SbkConverter *converter() { return m_converter; }
+ inline operator SbkConverter *() const { return m_converter; }
+
+ inline bool isValid() { return m_type != InvalidConversion; }
+ inline operator bool() const { return m_type != InvalidConversion; }
+
+ inline Type conversionType() { return m_type; }
+
+ PyObject *toPython(const void *cppIn);
+ void toCpp(PyObject *pyIn, void *cppOut);
+private:
+ SbkConverter *m_converter;
+ Type m_type;
+};
+
+
+/**
+ * Creates a converter for a wrapper type.
+ * \param type A Shiboken.ObjectType that will receive the new converter.
+ * \param toCppPointerConvFunc Function to retrieve the C++ pointer held by a Python wrapper.
+ * \param toCppPointerCheckFunc Check and return the retriever function of the C++ pointer held by a Python wrapper.
+ * \param pointerToPythonFunc Function to convert a C++ object to a Python \p type wrapper, keeping their identity.
+ * \param copyToPythonFunc Function to convert a C++ object to a Python \p type, copying the object.
+ * \returns The new converter referred by the wrapper \p type.
+ */
+LIBSHIBOKEN_API SbkConverter *createConverter(PyTypeObject *type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc = nullptr);
+
+/**
+ * Creates a converter for a non wrapper type (primitive or container type).
+ * \param type Python type representing to the new converter.
+ * \param toPythonFunc Function to convert a C++ object to a Python \p type.
+ * \returns A new type converter.
+ */
+LIBSHIBOKEN_API SbkConverter *createConverter(PyTypeObject *type, CppToPythonFunc toPythonFunc);
+
+LIBSHIBOKEN_API void deleteConverter(SbkConverter *converter);
+
+/// Sets the Python object to C++ pointer conversion function.
+LIBSHIBOKEN_API void setCppPointerToPythonFunction(SbkConverter *converter, CppToPythonFunc pointerToPythonFunc);
+
+/// Sets the C++ pointer to Python object conversion functions.
+LIBSHIBOKEN_API void setPythonToCppPointerFunctions(SbkConverter *converter,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc);
+
+/**
+ * Adds a new conversion of a Python object to a C++ value.
+ * This is used in copy and implicit conversions.
+ */
+LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkConverter *converter,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc);
+LIBSHIBOKEN_API void addPythonToCppValueConversion(PyTypeObject *type,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc);
+LIBSHIBOKEN_API void addPythonToCppValueConversion(Shiboken::Module::TypeInitStruct typeStruct,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc);
+
+// C++ -> Python ---------------------------------------------------------------------------
+
+/**
+ * Retrieves the Python wrapper object for the given \p cppIn C++ pointer object.
+ * This function is used only for Value and Object Types.
+ * Example usage:
+ * TYPE *var;
+ * PyObject *pyVar = pointerToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject *pointerToPython(PyTypeObject *type, const void *cppIn);
+LIBSHIBOKEN_API PyObject *pointerToPython(const SbkConverter *converter, const void *cppIn);
+
+/**
+ * For the given \p cppIn C++ reference it returns the Python wrapper object,
+ * always for Object Types, and when they already exist for reference types;
+ * for when the latter doesn't have an existing wrapper type, the C++ object
+ * is copied to Python.
+ * Example usage:
+ * TYPE &var = SOMETHING;
+ * PyObject *pyVar = referenceToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject *referenceToPython(PyTypeObject *type, const void *cppIn);
+LIBSHIBOKEN_API PyObject *referenceToPython(const SbkConverter *converter, const void *cppIn);
+
+/**
+ * Retrieves the Python wrapper object for the given C++ value pointed by \p cppIn.
+ * This function is used only for Value Types.
+ * Example usage:
+ * TYPE var;
+ * PyObject *pyVar = copyToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject *copyToPython(PyTypeObject *type, const void *cppIn);
+LIBSHIBOKEN_API PyObject *copyToPython(const SbkConverter *converter, const void *cppIn);
+
+// Python -> C++ ---------------------------------------------------------------------------
+
+struct PythonToCppConversion
+{
+ enum Type {Invalid, Pointer, Value};
+
+ operator bool() const { return type != Invalid; }
+
+ void operator()(PyObject *po,void *cpp) const { function(po, cpp); }
+
+ bool isValue() const { return type == Value; }
+
+ PythonToCppFunc function = nullptr;
+ Type type = Invalid;
+};
+
+/**
+ * Returns a Python to C++ conversion function if the Python object is convertible to a C++ pointer.
+ * It returns NULL if the Python object is not convertible to \p type.
+ */
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(PyTypeObject *type, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppPointerConversion(PyTypeObject *type, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppPointerConversion(Module::TypeInitStruct typeStruct, PyObject *pyIn);
+
+/**
+ * Returns a Python to C++ conversion function if the Python object is convertible to a C++ value.
+ * The resulting converter function will create a copy of the Python object in C++, or implicitly
+ * convert the object to the expected \p type.
+ * It returns NULL if the Python object is not convertible to \p type.
+ */
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(PyTypeObject *type, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppValueConversion(PyTypeObject *type, PyObject *pyIn);
+
+/**
+ * Returns a Python to C++ conversion function if the Python object is convertible to a C++ reference.
+ * The resulting converter function will return the underlying C++ object held by the Python wrapper,
+ * or a new C++ value if it must be a implicit conversion.
+ * It returns NULL if the Python object is not convertible to \p type.
+ */
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(PyTypeObject *type, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppReferenceConversion(PyTypeObject *type, PyObject *pyIn);
+
+/// This is the same as isPythonToCppValueConvertible function.
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppReferenceConversion(const SbkConverter *converter, PyObject *pyIn);
+
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppConversion(const SbkConverter *converter, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter,
+ int dim1, int dim2, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppConversion(const SbkArrayConverter *converter,
+ int dim1, int dim2, PyObject *pyIn);
+
+/**
+ * Returns the C++ pointer for the \p pyIn object cast to the type passed via \p desiredType.
+ * It differs from Shiboken::Object::cppPointer because it casts the pointer to a proper
+ * memory offset depending on the desired type.
+ */
+LIBSHIBOKEN_API void *cppPointer(PyTypeObject *desiredType, SbkObject *pyIn);
+
+/// Converts a Python object \p pyIn to C++ and stores the result in the C++ pointer passed in \p cppOut.
+LIBSHIBOKEN_API void pythonToCppPointer(PyTypeObject *type, PyObject *pyIn, void *cppOut);
+LIBSHIBOKEN_API void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut);
+
+/// Converts a Python object \p pyIn to C++, and copies the result in the C++ variable passed in \p cppOut.
+LIBSHIBOKEN_API void pythonToCppCopy(PyTypeObject *type, PyObject *pyIn, void *cppOut);
+LIBSHIBOKEN_API void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut);
+
+/**
+ * Helper function returned by generated convertible checking functions
+ * that returns a C++ NULL when the input Python object is None.
+ */
+LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject *, void *cppOut);
+
+/**
+ * Returns true if the \p toCpp function passed is an implicit conversion of Python \p type.
+ * It is used when C++ expects a reference argument, so it may be the same object received
+ * from Python, or another created through implicit conversion.
+ */
+[[deprecated]] LIBSHIBOKEN_API bool isImplicitConversion(PyTypeObject *type, PythonToCppFunc toCpp);
+
+/// Registers a converter with a type name that may be used to retrieve the converter.
+LIBSHIBOKEN_API void registerConverterName(SbkConverter *converter, const char *typeName);
+
+/// Returns the converter for a given type name, or NULL if it wasn't registered before.
+LIBSHIBOKEN_API SbkConverter *getConverter(const char *typeName);
+
+/// Returns the converter for a primitive type.
+LIBSHIBOKEN_API SbkConverter *primitiveTypeConverter(int index);
+
+/// Returns true if a Python sequence is comprised of objects of the given \p type.
+LIBSHIBOKEN_API bool checkSequenceTypes(PyTypeObject *type, PyObject *pyIn);
+
+/// Returns true if a Python type is iterable and comprised of objects of the
+/// given \p type.
+LIBSHIBOKEN_API bool checkIterableTypes(PyTypeObject *type, PyObject *pyIn);
+
+/// Returns true if a Python sequence is comprised of objects of a type convertible to the one represented by the given \p converter.
+LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn);
+
+/// Returns true if a Python sequence is comprised of objects of a type convertible to \p type.
+LIBSHIBOKEN_API bool convertibleSequenceTypes(PyTypeObject *type, PyObject *pyIn);
+
+/// Returns true if a Python type is iterable and comprised of objects of a
+/// type convertible to the one represented by the given \p converter.
+LIBSHIBOKEN_API bool convertibleIterableTypes(const SbkConverter *converter, PyObject *pyIn);
+
+/// Returns true if a Python type is iterable and comprised of objects of a
+/// type convertible to \p type.
+LIBSHIBOKEN_API bool convertibleIterableTypes(PyTypeObject *type, PyObject *pyIn);
+
+/// Returns true if a Python sequence can be converted to a C++ pair.
+LIBSHIBOKEN_API bool checkPairTypes(PyTypeObject *firstType, PyTypeObject *secondType, PyObject *pyIn);
+
+/// Returns true if a Python sequence can be converted to a C++ pair.
+LIBSHIBOKEN_API bool convertiblePairTypes(const SbkConverter *firstConverter, bool firstCheckExact,
+ const SbkConverter *secondConverter, bool secondCheckExact,
+ PyObject *pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ hash or map.
+LIBSHIBOKEN_API bool checkDictTypes(PyTypeObject *keyType, PyTypeObject *valueType, PyObject *pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ multi hash/map.
+/// The Python dictionary is expected to contain lists of values
+bool checkMultiDictTypes(PyTypeObject *keyType, PyTypeObject *valueType,
+ PyObject *pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ hash or map.
+LIBSHIBOKEN_API bool convertibleDictTypes(const SbkConverter *keyConverter, bool keyCheckExact,
+ const SbkConverter *valueConverter, bool valueCheckExact,
+ PyObject *pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ multi hash/map.
+/// The Python dictionary is expected to contain lists of values
+LIBSHIBOKEN_API bool convertibleMultiDictTypes(const SbkConverter *keyConverter,
+ bool keyCheckExact,
+ const SbkConverter *valueConverter,
+ bool valueCheckExact,
+ PyObject *pyIn);
+
+/// Returns the Python type object associated with the given \p converter.
+LIBSHIBOKEN_API PyTypeObject *getPythonTypeObject(const SbkConverter *converter);
+
+/// Returns the Python type object for the given \p typeName.
+LIBSHIBOKEN_API PyTypeObject *getPythonTypeObject(const char *typeName);
+
+/// Returns true if the Python type associated with the converter is a value type.
+LIBSHIBOKEN_API bool pythonTypeIsValueType(const SbkConverter *converter);
+
+/// Returns true if the Python type associated with the converter is an object type.
+LIBSHIBOKEN_API bool pythonTypeIsObjectType(const SbkConverter *converter);
+
+/// Returns true if the Python type associated with the converter is a wrapper type.
+LIBSHIBOKEN_API bool pythonTypeIsWrapperType(const SbkConverter *converter);
+
+#define SBK_PY_LONG_LONG_IDX 0
+// Qt5: name collision in QtCore after QBool is replaced by bool
+#define SBK_BOOL_IDX_1 1
+#define SBK_CHAR_IDX 2
+#define SBK_CONSTCHARPTR_IDX 3
+#define SBK_DOUBLE_IDX 4
+#define SBK_FLOAT_IDX 5
+#define SBK_INT_IDX 6
+#define SBK_SIGNEDINT_IDX 6
+#define SBK_LONG_IDX 7
+#define SBK_SHORT_IDX 8
+#define SBK_SIGNEDCHAR_IDX 9
+#define SBK_STD_STRING_IDX 10
+#define SBK_STD_WSTRING_IDX 11
+#define SBK_UNSIGNEDPY_LONG_LONG_IDX 12
+#define SBK_UNSIGNEDCHAR_IDX 13
+#define SBK_UNSIGNEDINT_IDX 14
+#define SBK_UNSIGNEDLONG_IDX 15
+#define SBK_UNSIGNEDSHORT_IDX 16
+#define SBK_VOIDPTR_IDX 17
+#define SBK_NULLPTR_T_IDX 18
+
+template<typename T> SbkConverter *PrimitiveTypeConverter() { return nullptr; }
+template<> inline SbkConverter *PrimitiveTypeConverter<PY_LONG_LONG>() { return primitiveTypeConverter(SBK_PY_LONG_LONG_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<bool>() { return primitiveTypeConverter(SBK_BOOL_IDX_1); }
+template<> inline SbkConverter *PrimitiveTypeConverter<char>() { return primitiveTypeConverter(SBK_CHAR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<const char *>() { return primitiveTypeConverter(SBK_CONSTCHARPTR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<double>() { return primitiveTypeConverter(SBK_DOUBLE_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<float>() { return primitiveTypeConverter(SBK_FLOAT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<int>() { return primitiveTypeConverter(SBK_INT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<long>() { return primitiveTypeConverter(SBK_LONG_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<short>() { return primitiveTypeConverter(SBK_SHORT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<signed char>() { return primitiveTypeConverter(SBK_SIGNEDCHAR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<std::string>() { return primitiveTypeConverter(SBK_STD_STRING_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<std::wstring>() { return primitiveTypeConverter(SBK_STD_WSTRING_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned PY_LONG_LONG>() { return primitiveTypeConverter(SBK_UNSIGNEDPY_LONG_LONG_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned char>() { return primitiveTypeConverter(SBK_UNSIGNEDCHAR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned int>() { return primitiveTypeConverter(SBK_UNSIGNEDINT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned long>() { return primitiveTypeConverter(SBK_UNSIGNEDLONG_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<unsigned short>() { return primitiveTypeConverter(SBK_UNSIGNEDSHORT_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<void *>() { return primitiveTypeConverter(SBK_VOIDPTR_IDX); }
+template<> inline SbkConverter *PrimitiveTypeConverter<std::nullptr_t>() { return primitiveTypeConverter(SBK_NULLPTR_T_IDX); }
+
+} // namespace Shiboken::Conversions
+
+/**
+* This function template is used to get the PyTypeObject of a C++ type T.
+* All implementations should be provided by template specializations generated by the generator when
+* T isn't a C++ primitive type.
+* \see SpecialCastFunction
+*/
+template<typename T> PyTypeObject *SbkType() { return nullptr; }
+
+// Below are the template specializations for C++ primitive types.
+template<> inline PyTypeObject *SbkType<PY_LONG_LONG>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<bool>() { return &PyBool_Type; }
+template<> inline PyTypeObject *SbkType<char>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<double>() { return &PyFloat_Type; }
+template<> inline PyTypeObject *SbkType<float>() { return &PyFloat_Type; }
+template<> inline PyTypeObject *SbkType<int>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<long>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<short>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<signed char>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned PY_LONG_LONG>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned char>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned int>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned long>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<unsigned short>() { return &PyLong_Type; }
+template<> inline PyTypeObject *SbkType<std::nullptr_t>() { return Py_TYPE(&_Py_NoneStruct); }
+
+} // namespace Shiboken
+
+#define SbkChar_Check(X) (PyNumber_Check(X) || Shiboken::String::checkChar(X))
+
+struct PySideQFlagsType;
+struct SbkQFlagsTypePrivate
+{
+ SbkConverter *converter;
+};
+
+#endif // SBK_CONVERTER_H
diff --git a/sources/shiboken6/libshiboken/sbkconverter_p.h b/sources/shiboken6/libshiboken/sbkconverter_p.h
new file mode 100644
index 000000000..08fc4c8e1
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkconverter_p.h
@@ -0,0 +1,542 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_CONVERTER_P_H
+#define SBK_CONVERTER_P_H
+
+#include "sbkpython.h"
+#include "sbkconverter.h"
+#include "sbkcppstring.h"
+#include "sbkstring.h"
+#include <limits>
+#include <typeinfo>
+#include <sstream>
+#include <iostream>
+#include <vector>
+
+extern "C"
+{
+
+using ToCppConversion = std::pair<IsConvertibleToCppFunc, PythonToCppFunc>;
+using ToCppConversionVector = std::vector<ToCppConversion>;
+
+/**
+ * \internal
+ * Private structure of SbkConverter.
+ */
+struct SbkConverter
+{
+ /**
+ * Python type associated with this converter. If the type is a Shiboken
+ * wrapper, then it must be a SbkObjectType; otherwise it will be the
+ * Python type to which the C++ value will be converted (note that the
+ * C++ type could be produced from various Python types).
+ */
+ PyTypeObject *pythonType;
+ /**
+ * This function converts a C++ object to a Python object of the type
+ * indicated in pythonType. The identity of the C++ object is kept,
+ * because it looks for an already existing Python wrapper associated
+ * with the C++ instance.
+ * It is used to convert C++ pointers and references to Python objects.
+ */
+ CppToPythonFunc pointerToPython;
+ /**
+ * This function converts a C++ object to a Python object of the type
+ * indicated in pythonType. The identity of the object is not kept,
+ * because a new instance of the C++ object is created.
+ * It is used to convert objects passed by value, or reference, if said
+ * reference can't be traced to an object that already has a Python
+ * wrapper assigned for it.
+ */
+ CppToPythonFunc copyToPython;
+ /**
+ * This is a special case of a Python to C++ conversion. It returns
+ * the underlying C++ pointer of a Python wrapper passed as parameter
+ * or NULL if the Python object is a None value.
+ * It comes separated from the other toCppConversions because if you
+ * have a Python object representing a Value Type the type checking
+ * for both ValueType and ValueType *would be the same, thus the first
+ * check would be true and the second would never be reached.
+ */
+ ToCppConversion toCppPointerConversion;
+ /**
+ * This is a list of type checking functions that return the
+ * proper Python to C++ conversion function, for the given Python
+ * object.
+ * For Object Types, that never have implicit conversions, this
+ * list is always empty.
+ */
+ ToCppConversionVector toCppConversions;
+};
+
+} // extern "C"
+
+template<typename T, typename MaxLimitType, bool isSigned>
+struct OverFlowCheckerBase {
+ static void formatOverFlowMessage(const MaxLimitType &value,
+ const std::string *valueAsString = nullptr)
+ {
+ std::ostringstream str;
+ str << "libshiboken: Overflow: Value ";
+ if (valueAsString != nullptr && !valueAsString->empty())
+ str << *valueAsString;
+ else
+ str << value;
+ str << " exceeds limits of type "
+ << " [" << (isSigned ? "signed" : "unsigned")
+ << "] \"" << typeid(T).name()
+ << "\" (" << sizeof(T) << "bytes).";
+ const std::string message = str.str();
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.c_str(), 0);
+ }
+
+ // Checks if an overflow occurred inside Python code.
+ // Precondition: use after calls like PyLong_AsLongLong or PyLong_AsUnsignedLongLong.
+ // Postcondition: if error ocurred, sets the string reference to the string representation of
+ // the passed value.
+ static bool checkForInternalPyOverflow(PyObject *pyIn, std::string &valueAsString)
+ {
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyObject *stringRepresentation = PyObject_Str(pyIn);
+ const char *cString = Shiboken::String::toCString(stringRepresentation);
+ valueAsString.assign(cString);
+ Py_DECREF(stringRepresentation);
+ return true;
+ }
+ return false;
+ }
+};
+
+// Helper template for checking if a value overflows when cast to type T.
+// The MaxLimitType size is usually >= than type T size, so that it can still represent values that
+// can't be stored in T (unless the types are of course the same).
+// TLDR: MaxLimitType is either long long or unsigned long long.
+template<typename T, typename MaxLimitType = PY_LONG_LONG,
+ bool isSigned = std::numeric_limits<T>::is_signed >
+struct OverFlowChecker;
+
+template<typename T, typename MaxLimitType>
+struct OverFlowChecker<T, MaxLimitType, true> :
+ public OverFlowCheckerBase<T, MaxLimitType, true> {
+ static bool check(const MaxLimitType &value, PyObject *pyIn)
+ {
+ std::string valueAsString;
+ const bool isOverflow =
+ OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString)
+ || value < std::numeric_limits<T>::min()
+ || value > std::numeric_limits<T>::max();
+ if (isOverflow)
+ OverFlowChecker::formatOverFlowMessage(value, &valueAsString);
+ return isOverflow;
+ }
+};
+
+template<typename T, typename MaxLimitType>
+struct OverFlowChecker<T, MaxLimitType, false>
+ : public OverFlowCheckerBase<T, MaxLimitType, false> {
+ static bool check(const MaxLimitType &value, PyObject *pyIn)
+ {
+ std::string valueAsString;
+ const bool isOverflow =
+ OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString)
+ || value < 0
+ || static_cast<unsigned long long>(value) > std::numeric_limits<T>::max();
+ if (isOverflow)
+ OverFlowChecker::formatOverFlowMessage(value, &valueAsString);
+ return isOverflow;
+ }
+};
+template<>
+struct OverFlowChecker<PY_LONG_LONG, PY_LONG_LONG, true> :
+ public OverFlowCheckerBase<PY_LONG_LONG, PY_LONG_LONG, true> {
+ static bool check(const PY_LONG_LONG &value, PyObject *pyIn) {
+ std::string valueAsString;
+ const bool isOverflow = checkForInternalPyOverflow(pyIn, valueAsString);
+ if (isOverflow)
+ OverFlowChecker::formatOverFlowMessage(value, &valueAsString);
+ return isOverflow;
+
+ }
+};
+template<>
+struct OverFlowChecker<double, PY_LONG_LONG, true> {
+ static bool check(const double &, PyObject *) { return false; }
+};
+template<>
+struct OverFlowChecker<float, PY_LONG_LONG, true> :
+ public OverFlowCheckerBase<float, PY_LONG_LONG, true> {
+ static bool check(const double &value, PyObject *)
+ {
+ const bool result = value < std::numeric_limits<float>::min()
+ || value > std::numeric_limits<float>::max();
+ if (result)
+ formatOverFlowMessage(value);
+ return result;
+ }
+};
+
+// Basic primitive type converters ---------------------------------------------------------
+
+template <typename T> struct Primitive {};
+
+template <typename T>
+struct OnePrimitive
+{
+ static PyObject *toPython(const void *) { return nullptr; }
+ static PythonToCppFunc isConvertible(PyObject *) { return nullptr; }
+ static void toCpp(PyObject *, void *) {}
+ static SbkConverter *createConverter()
+ {
+ SbkConverter *converter = Shiboken::Conversions::createConverter(Shiboken::SbkType<T>(),
+ Primitive<T>::toPython);
+ Shiboken::Conversions::addPythonToCppValueConversion(converter,
+ Primitive<T>::toCpp,
+ Primitive<T>::isConvertible);
+ return converter;
+ }
+};
+template <typename T>
+struct TwoPrimitive : OnePrimitive<T>
+{
+ static PythonToCppFunc isOtherConvertible(PyObject *) { return nullptr; }
+ static void otherToCpp(PyObject *, void *) {}
+ static SbkConverter *createConverter()
+ {
+ SbkConverter *converter = OnePrimitive<T>::createConverter();
+ Shiboken::Conversions::addPythonToCppValueConversion(converter, Primitive<T>::otherToCpp, Primitive<T>::isOtherConvertible);
+ return converter;
+ }
+};
+
+// Integers --------------------------------------------------------------------------------
+
+template <typename INT>
+struct IntPrimitive : TwoPrimitive<INT>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromLong(*reinterpret_cast<const INT *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ double result = PyFloat_AS_DOUBLE(pyIn);
+ // If cast to long directly it could overflow silently.
+ if (OverFlowChecker<INT>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<INT * >(cppOut) = static_cast<INT>(result);
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyFloat_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyIn);
+ if (OverFlowChecker<INT>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<INT * >(cppOut) = static_cast<INT>(result);
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+template <> struct Primitive<int> : IntPrimitive<int> {};
+template <> struct Primitive<long> : IntPrimitive<long> {};
+template <> struct Primitive<short> : IntPrimitive<short> {};
+template <> struct Primitive<unsigned short> : IntPrimitive<unsigned short> {};
+
+// Unsigned Long Integers ------------------------------------------------------------------
+
+template <typename LONG>
+struct UnsignedLongPrimitive : IntPrimitive<LONG>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromUnsignedLong(*reinterpret_cast<const LONG *>(cppIn));
+ }
+};
+template <> struct Primitive<unsigned int> : UnsignedLongPrimitive<unsigned int> {};
+template <> struct Primitive<unsigned long> : UnsignedLongPrimitive<unsigned long> {};
+
+// Big integers ----------------------------------------------------------------------------
+
+template <>
+struct Primitive<PY_LONG_LONG> : OnePrimitive<PY_LONG_LONG>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromLongLong(*reinterpret_cast<const PY_LONG_LONG *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyIn);
+ if (OverFlowChecker<PY_LONG_LONG>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<PY_LONG_LONG * >(cppOut) = result;
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+};
+
+template <>
+struct Primitive<unsigned PY_LONG_LONG> : OnePrimitive<unsigned PY_LONG_LONG>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromUnsignedLongLong(*static_cast<const unsigned PY_LONG_LONG *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ if (PyLong_Check(pyIn)) {
+ unsigned PY_LONG_LONG result = PyLong_AsUnsignedLongLong(pyIn);
+ if (OverFlowChecker<unsigned PY_LONG_LONG, unsigned PY_LONG_LONG>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<unsigned PY_LONG_LONG * >(cppOut) = result;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion");
+ }
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+};
+
+// Floating point --------------------------------------------------------------------------
+
+template <typename FLOAT>
+struct FloatPrimitive : TwoPrimitive<FLOAT>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyFloat_FromDouble(*reinterpret_cast<const FLOAT *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<FLOAT *>(cppOut) = FLOAT(PyLong_AsDouble(pyIn));
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyLong_Check(pyIn) || PyLong_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<FLOAT *>(cppOut) = FLOAT(PyFloat_AsDouble(pyIn));
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+template <> struct Primitive<float> : FloatPrimitive<float> {};
+template <> struct Primitive<double> : FloatPrimitive<double> {};
+
+// Boolean ---------------------------------------------------------------------------------
+
+template <>
+struct Primitive<bool> : OnePrimitive<bool>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyBool_FromLong(*reinterpret_cast<const bool *>(cppIn));
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<bool *>(cppOut) = PyLong_AS_LONG(pyIn) != 0;
+ }
+};
+
+// Characters ------------------------------------------------------------------------------
+
+template <typename CHAR>
+struct CharPrimitive : IntPrimitive<CHAR>
+{
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<CHAR *>(cppOut) = CHAR(Shiboken::String::toCString(pyIn)[0]);
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (Shiboken::String::checkChar(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyIn);
+ if (OverFlowChecker<CHAR>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<CHAR *>(cppOut) = CHAR(result);
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+ static SbkConverter *createConverter()
+ {
+ SbkConverter *converter = IntPrimitive<CHAR>::createConverter();
+ Shiboken::Conversions::addPythonToCppValueConversion(converter, CharPrimitive<CHAR>::otherToCpp, CharPrimitive<CHAR>::isOtherConvertible);
+ return converter;
+ }
+
+};
+template <> struct Primitive<signed char> : CharPrimitive<signed char> {};
+template <> struct Primitive<unsigned char> : CharPrimitive<unsigned char> {};
+template <> struct Primitive<char> : CharPrimitive<char> {
+ using CharPrimitive<char>::toPython;
+ static PyObject *toPython(const void *cppIn) {
+ return Shiboken::String::fromCString(reinterpret_cast<const char *>(cppIn), 1);
+ }
+};
+
+
+
+// Strings ---------------------------------------------------------------------------------
+
+template <>
+struct Primitive<const char *> : TwoPrimitive<const char *>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ if (!cppIn)
+ Py_RETURN_NONE;
+ return Shiboken::String::fromCString(reinterpret_cast<const char *>(cppIn));
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ *reinterpret_cast<const char **>(cppOut) = nullptr;
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<const char **>(cppOut) = Shiboken::String::toCString(pyIn);
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (Shiboken::String::check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+
+template <>
+struct Primitive<std::string> : TwoPrimitive<std::string>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return Shiboken::String::fromCppString(*reinterpret_cast<const std::string *>(cppIn));
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ reinterpret_cast<std::string *>(cppOut)->clear();
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ Shiboken::String::toCppString(pyIn, reinterpret_cast<std::string *>(cppOut));
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (Shiboken::String::check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+
+template <>
+struct Primitive<std::wstring> : TwoPrimitive<std::wstring>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return Shiboken::String::fromCppWString(*reinterpret_cast<const std::wstring *>(cppIn));
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ reinterpret_cast<std::wstring *>(cppOut)->clear();
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ return pyIn == Py_None ? toCpp : nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ Shiboken::String::toCppWString(pyIn, reinterpret_cast<std::wstring *>(cppOut));
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ return PyUnicode_Check(pyIn) ? otherToCpp : nullptr;
+ }
+};
+
+// nullptr_t
+template <>
+struct Primitive<std::nullptr_t> : OnePrimitive<std::nullptr_t>
+{
+ static PyObject *toPython(const void * /* cppIn */)
+ {
+ Py_RETURN_NONE;
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ *reinterpret_cast<std::nullptr_t *>(cppOut) = nullptr;
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+};
+
+namespace Shiboken::Conversions {
+
+SbkConverter *createConverterObject(PyTypeObject *type,
+ PythonToCppFunc toCppPointerConvFunc,
+ 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/sbkcppstring.cpp b/sources/shiboken6/libshiboken/sbkcppstring.cpp
new file mode 100644
index 000000000..8e8324f5e
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcppstring.cpp
@@ -0,0 +1,54 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkcppstring.h"
+#include "autodecref.h"
+
+namespace Shiboken::String
+{
+
+PyObject *fromCppString(const std::string &value)
+{
+ return PyUnicode_FromStringAndSize(value.data(), value.size());
+}
+
+PyObject *fromCppStringView(std::string_view value)
+{
+ return PyUnicode_FromStringAndSize(value.data(), value.size());
+}
+
+PyObject *fromCppWString(const std::wstring &value)
+{
+ return PyUnicode_FromWideChar(value.data(), value.size());
+}
+
+void toCppString(PyObject *str, std::string *value)
+{
+ value->clear();
+
+ if (str == Py_None)
+ return;
+
+ if (PyUnicode_Check(str)) {
+ if (PyUnicode_GetLength(str) > 0)
+ value->assign(_PepUnicode_AsString(str));
+ return;
+ }
+
+ if (PyBytes_Check(str))
+ value->assign(PyBytes_AS_STRING(str));
+}
+
+void toCppWString(PyObject *str, std::wstring *value)
+{
+ value->clear();
+
+ if (str == Py_None || PyUnicode_Check(str) == 0 || PyUnicode_GetLength(str) == 0)
+ return;
+
+ wchar_t *w = PyUnicode_AsWideCharString(str, nullptr);
+ value->assign(w);
+ PyMem_Free(w);
+}
+
+} // namespace Shiboken::String
diff --git a/sources/shiboken6/libshiboken/sbkcppstring.h b/sources/shiboken6/libshiboken/sbkcppstring.h
new file mode 100644
index 000000000..7ffe11c75
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcppstring.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKCPPSTRING_H
+#define SBKCPPSTRING_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+#include <string>
+#include <string_view>
+
+namespace Shiboken::String
+{
+ LIBSHIBOKEN_API PyObject *fromCppString(const std::string &value);
+ LIBSHIBOKEN_API PyObject *fromCppStringView(std::string_view value);
+ LIBSHIBOKEN_API PyObject *fromCppWString(const std::wstring &value);
+ LIBSHIBOKEN_API void toCppString(PyObject *str, std::string *value);
+ LIBSHIBOKEN_API void toCppWString(PyObject *str, std::wstring *value);
+} // namespace Shiboken::String
+
+#endif // SBKCPPSTRING_H
diff --git a/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp b/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp
new file mode 100644
index 000000000..7637efa70
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcpptonumpy.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// included by sbknumpy.cpp
+
+namespace Shiboken::Numpy {
+
+#ifdef HAVE_NUMPY
+
+// Helper to create a 1-dimensional numpy array
+template <class Type>
+static PyObject *_createArray1(Py_ssize_t size, int numpyType, const Type *data)
+{
+ const npy_intp dims[1] = {size};
+ PyObject *result = PyArray_EMPTY(1, dims, numpyType, 0);
+ auto *array = reinterpret_cast<PyArrayObject *>(result);
+ auto *rawTargetData = PyArray_DATA(array);
+ auto *targetData = reinterpret_cast<Type *>(rawTargetData);
+ std::copy(data, data + size, targetData);
+ return result;
+}
+
+PyObject *createByteArray1(Py_ssize_t size, const uint8_t *data)
+{
+ return _createArray1(size, NPY_BYTE, data);
+}
+
+PyObject *createDoubleArray1(Py_ssize_t size, const double *data)
+{
+ return _createArray1(size, NPY_DOUBLE, data);
+}
+
+PyObject *createFloatArray1(Py_ssize_t size, const float *data)
+{
+ return _createArray1(size, NPY_FLOAT, data);
+}
+
+PyObject *createIntArray1(Py_ssize_t size, const int *data)
+{
+ return _createArray1(size, NPY_INT, data);
+}
+
+#else // HAVE_NUMPY
+
+PyObject *createByteArray1(Py_ssize_t, const uint8_t *)
+{
+ return Py_None;
+}
+
+PyObject *createDoubleArray1(Py_ssize_t, const double *)
+{
+ Py_RETURN_NONE;
+}
+
+PyObject *createFloatArray1(Py_ssize_t, const float *)
+{
+ Py_RETURN_NONE;
+}
+
+PyObject *createIntArray1(Py_ssize_t, const int *)
+{
+ Py_RETURN_NONE;
+}
+
+#endif // !HAVE_NUMPY
+
+} //namespace Shiboken::Numpy
diff --git a/sources/shiboken6/libshiboken/sbkcpptonumpy.h b/sources/shiboken6/libshiboken/sbkcpptonumpy.h
new file mode 100644
index 000000000..8b9b0cfd2
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkcpptonumpy.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKCPPTONUMPY_H
+#define SBKCPPTONUMPY_H
+
+#include <sbkpython.h>
+#include <shibokenmacros.h>
+
+#include <cstdint>
+
+namespace Shiboken::Numpy
+{
+
+/// Create a one-dimensional numpy array of type uint8/NPY_BYTE
+/// \param size Size
+/// \param data Data
+/// \return PyArrayObject
+LIBSHIBOKEN_API PyObject *createByteArray1(Py_ssize_t size, const uint8_t *data);
+
+/// Create a one-dimensional numpy array of type double/NPY_DOUBLE
+/// \param size Size
+/// \param data Data
+/// \return PyArrayObject
+LIBSHIBOKEN_API PyObject *createDoubleArray1(Py_ssize_t size, const double *data);
+
+/// Create a one-dimensional numpy array of type float/NPY_FLOAT
+/// \param size Size
+/// \param data Data
+/// \return PyArrayObject
+LIBSHIBOKEN_API PyObject *createFloatArray1(Py_ssize_t size, const float *data);
+
+/// Create a one-dimensional numpy array of type int/NPY_INT
+/// \param size Size
+/// \param data Data
+/// \return PyArrayObject
+LIBSHIBOKEN_API PyObject *createIntArray1(Py_ssize_t size, const int *data);
+
+} //namespace Shiboken::Numpy
+
+#endif // SBKCPPTONUMPY_H
diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp
new file mode 100644
index 000000000..2b083a91c
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkenum.cpp
@@ -0,0 +1,454 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkenum.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "sbkconverter.h"
+#include "basewrapper.h"
+#include "autodecref.h"
+#include "sbkpython.h"
+#include "signature.h"
+
+#include <cstring>
+#include <vector>
+#include <sstream>
+
+using namespace Shiboken;
+
+extern "C"
+{
+
+struct SbkEnumType
+{
+ PyTypeObject type;
+};
+
+// Initialization
+static bool _init_enum()
+{
+ AutoDecRef shibo(PyImport_ImportModule("shiboken6.Shiboken"));
+ return !shibo.isNull();
+}
+
+static PyObject *PyEnumModule{};
+static PyObject *PyEnumMeta{};
+static PyObject *PyEnum{};
+static PyObject *PyIntEnum{};
+static PyObject *PyFlag{};
+static PyObject *PyIntFlag{};
+static PyObject *PyFlag_KEEP{};
+
+bool PyEnumMeta_Check(PyObject *ob)
+{
+ return Py_TYPE(ob) == reinterpret_cast<PyTypeObject *>(PyEnumMeta);
+}
+
+PyTypeObject *getPyEnumMeta()
+{
+ if (PyEnumMeta)
+ return reinterpret_cast<PyTypeObject *>(PyEnumMeta);
+
+ static auto *mod = PyImport_ImportModule("enum");
+ if (mod) {
+ PyEnumModule = mod;
+ PyEnumMeta = PyObject_GetAttrString(mod, "EnumMeta");
+ if (PyEnumMeta && PyType_Check(PyEnumMeta))
+ PyEnum = PyObject_GetAttrString(mod, "Enum");
+ if (PyEnum && PyType_Check(PyEnum))
+ PyIntEnum = PyObject_GetAttrString(mod, "IntEnum");
+ if (PyIntEnum && PyType_Check(PyIntEnum))
+ PyFlag = PyObject_GetAttrString(mod, "Flag");
+ if (PyFlag && PyType_Check(PyFlag))
+ PyIntFlag = PyObject_GetAttrString(mod, "IntFlag");
+ if (PyIntFlag && PyType_Check(PyIntFlag)) {
+ // KEEP is defined from Python 3.11 on.
+ PyFlag_KEEP = PyObject_GetAttrString(mod, "KEEP");
+ PyErr_Clear();
+ return reinterpret_cast<PyTypeObject *>(PyEnumMeta);
+ }
+ }
+ Py_FatalError("Python module 'enum' not found");
+ return nullptr;
+}
+
+void init_enum()
+{
+ static bool isInitialized = false;
+ if (isInitialized)
+ return;
+ if (!(isInitialized || _init_enum()))
+ Py_FatalError("could not init enum");
+
+ // PYSIDE-1735: Determine whether we should use the old or the new enum implementation.
+ static PyObject *option = PySys_GetObject("pyside6_option_python_enum");
+ if (!option || !PyLong_Check(option)) {
+ PyErr_Clear();
+ option = PyLong_FromLong(1);
+ }
+ int ignoreOver{};
+ Enum::enumOption = PyLong_AsLongAndOverflow(option, &ignoreOver);
+ getPyEnumMeta();
+ isInitialized = true;
+}
+
+// PYSIDE-1735: Helper function supporting QEnum
+int enumIsFlag(PyObject *ob_type)
+{
+ init_enum();
+
+ auto *metatype = Py_TYPE(ob_type);
+ if (metatype != reinterpret_cast<PyTypeObject *>(PyEnumMeta))
+ return -1;
+ auto *mro = reinterpret_cast<PyTypeObject *>(ob_type)->tp_mro;
+ const Py_ssize_t n = PyTuple_GET_SIZE(mro);
+ for (Py_ssize_t idx = 0; idx < n; ++idx) {
+ auto *sub_type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ if (sub_type == reinterpret_cast<PyTypeObject *>(PyFlag))
+ return 1;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Support for Missing Values
+// ==========================
+//
+// Qt enums sometimes use undefined values in enums.
+// The enum module handles this by the option "KEEP" for Flag and
+// IntFlag. The handling of missing enum values is still strict.
+//
+// We changed that (also for compatibility with some competitor)
+// and provide a `_missing_` function that creates the missing value.
+//
+// The idea:
+// ---------
+// We cannot modify the already created class.
+// But we can create a one-element class with the new value and
+// pretend that this is the already existing class.
+//
+// We create each constant only once and keep the result in a dict
+// "_sbk_missing_". This is similar to a competitor's "_sip_missing_".
+//
+
+static PyObject *missing_func(PyObject * /* self */ , PyObject *args)
+{
+ // In order to relax matters to be more compatible with C++, we need
+ // to create a pseudo-member with that value.
+ static auto *const _sbk_missing = Shiboken::String::createStaticString("_sbk_missing_");
+ static auto *const _name = Shiboken::String::createStaticString("__name__");
+ static auto *const _mro = Shiboken::String::createStaticString("__mro__");
+ static auto *const _class = Shiboken::String::createStaticString("__class__");
+
+ PyObject *klass{}, *value{};
+ if (!PyArg_UnpackTuple(args, "missing", 2, 2, &klass, &value))
+ Py_RETURN_NONE;
+ if (!PyLong_Check(value))
+ Py_RETURN_NONE;
+ auto *type = reinterpret_cast<PyTypeObject *>(klass);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *sbk_missing = PyDict_GetItem(tpDict.object(), _sbk_missing);
+ if (!sbk_missing) {
+ sbk_missing = PyDict_New();
+ PyDict_SetItem(tpDict.object(), _sbk_missing, sbk_missing);
+ }
+ // See if the value is already in the dict.
+ AutoDecRef val_str(PyObject_CallMethod(value, "__str__", nullptr));
+ auto *ret = PyDict_GetItem(sbk_missing, val_str);
+ if (ret) {
+ Py_INCREF(ret);
+ return ret;
+ }
+ // No, we must create a new object and insert it into the dict.
+ AutoDecRef cls_name(PyObject_GetAttr(klass, _name));
+ AutoDecRef mro(PyObject_GetAttr(klass, _mro));
+ auto *baseClass(PyTuple_GetItem(mro, 1));
+ AutoDecRef param(PyDict_New());
+ PyDict_SetItem(param, val_str, value);
+ AutoDecRef fake(PyObject_CallFunctionObjArgs(baseClass, cls_name.object(), param.object(),
+ nullptr));
+ ret = PyObject_GetAttr(fake, val_str);
+ PyDict_SetItem(sbk_missing, val_str, ret);
+ // Now the real fake: Pretend that the type is our original type!
+ PyObject_SetAttr(ret, _class, klass);
+ return ret;
+}
+
+static struct PyMethodDef dummy_methods[] = {
+ {"_missing_", reinterpret_cast<PyCFunction>(missing_func), METH_VARARGS|METH_STATIC, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+static PyType_Slot dummy_slots[] = {
+ {Py_tp_base, reinterpret_cast<void *>(&PyType_Type)},
+ {Py_tp_methods, reinterpret_cast<void *>(dummy_methods)},
+ {0, nullptr}
+};
+
+static PyType_Spec dummy_spec = {
+ "1:builtins.EnumType",
+ 0,
+ 0,
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ dummy_slots,
+};
+
+static PyObject *create_missing_func(PyObject *klass)
+{
+ // When creating the class, memorize it in the missing function by
+ // a partial function argument.
+ static auto *const type = SbkType_FromSpec(&dummy_spec);
+ static auto *const obType = reinterpret_cast<PyObject *>(type);
+ static auto *const _missing = Shiboken::String::createStaticString("_missing_");
+ static auto *const func = PyObject_GetAttr(obType, _missing);
+ static auto *const partial = Pep_GetPartialFunction();
+ return PyObject_CallFunctionObjArgs(partial, func, klass, nullptr);
+}
+//
+////////////////////////////////////////////////////////////////////////
+
+} // extern "C"
+
+namespace Shiboken::Enum {
+
+int enumOption{};
+
+bool check(PyObject *pyObj)
+{
+ init_enum();
+
+ static PyTypeObject *meta = getPyEnumMeta();
+ return Py_TYPE(Py_TYPE(pyObj)) == reinterpret_cast<PyTypeObject *>(meta);
+}
+
+PyObject *getEnumItemFromValue(PyTypeObject *enumType, EnumValueType itemValue)
+{
+ init_enum();
+
+ auto *obEnumType = reinterpret_cast<PyObject *>(enumType);
+ AutoDecRef val2members(PyObject_GetAttrString(obEnumType, "_value2member_map_"));
+ if (val2members.isNull()) {
+ PyErr_Clear();
+ return nullptr;
+ }
+ AutoDecRef ob_value(PyLong_FromLongLong(itemValue));
+ auto *result = PyDict_GetItem(val2members, ob_value);
+ Py_XINCREF(result);
+ return result;
+}
+
+PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue,
+ const char *itemName)
+{
+ init_enum();
+
+ auto *obEnumType = reinterpret_cast<PyObject *>(enumType);
+ if (!itemName)
+ return PyObject_CallFunction(obEnumType, "L", itemValue);
+
+ static PyObject *const _member_map_ = String::createStaticString("_member_map_");
+ AutoDecRef tpDict(PepType_GetDict(enumType));
+ auto *member_map = PyDict_GetItem(tpDict.object(), _member_map_);
+ if (!(member_map && PyDict_Check(member_map)))
+ return nullptr;
+ auto *result = PyDict_GetItemString(member_map, itemName);
+ Py_XINCREF(result);
+ return result;
+}
+
+EnumValueType getValue(PyObject *enumItem)
+{
+ init_enum();
+
+ assert(Enum::check(enumItem));
+
+ AutoDecRef pyValue(PyObject_GetAttrString(enumItem, "value"));
+ return PyLong_AsLongLong(pyValue);
+}
+
+void setTypeConverter(PyTypeObject *type, SbkConverter *converter)
+{
+ auto *enumType = reinterpret_cast<SbkEnumType *>(type);
+ PepType_SETP(enumType)->converter = converter;
+}
+
+static PyTypeObject *createEnumForPython(PyObject *scopeOrModule,
+ const char *fullName,
+ PyObject *pyEnumItems)
+{
+ const char *colon = strchr(fullName, ':');
+ assert(colon);
+ int package_level = atoi(fullName);
+ const char *mod = colon + 1;
+
+ const char *qual = mod;
+ for (int idx = package_level; idx > 0; --idx) {
+ const char *dot = strchr(qual, '.');
+ if (!dot)
+ break;
+ qual = dot + 1;
+ }
+ int mlen = qual - mod - 1;
+ AutoDecRef module(Shiboken::String::fromCString(mod, mlen));
+ AutoDecRef qualname(Shiboken::String::fromCString(qual));
+ const char *dot = strrchr(qual, '.');
+ AutoDecRef name(Shiboken::String::fromCString(dot ? dot + 1 : qual));
+
+ static PyObject *enumName = String::createStaticString("IntEnum");
+ if (PyType_Check(scopeOrModule)) {
+ // For global objects, we have no good solution, yet where to put the int info.
+ auto type = reinterpret_cast<PyTypeObject *>(scopeOrModule);
+ auto *sotp = PepType_SOTP(type);
+ if (!sotp->enumFlagsDict)
+ initEnumFlagsDict(type);
+ 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);
+
+ // See if we should use the Int versions of the types, again
+ bool useIntInheritance = Enum::enumOption & Enum::ENOPT_INHERIT_INT;
+ if (useIntInheritance) {
+ auto *surrogate = PyObject_IsSubclass(PyEnumType, PyFlag) ? PyIntFlag : PyIntEnum;
+ Py_INCREF(surrogate);
+ PyEnumType.reset(surrogate);
+ }
+
+ // Walk the enumItemStrings and create a Python enum type.
+ auto *pyName = name.object();
+
+ // We now create the new type. Since Python 3.11, we need to pass in
+ // `boundary=KEEP` because the default STRICT crashes on us.
+ // See QDir.Filter.Drives | QDir.Filter.Files
+ AutoDecRef callArgs(Py_BuildValue("(OO)", pyName, pyEnumItems));
+ AutoDecRef callDict(PyDict_New());
+ static PyObject *boundary = String::createStaticString("boundary");
+ if (PyFlag_KEEP)
+ PyDict_SetItem(callDict, boundary, PyFlag_KEEP);
+ auto *obNewType = PyObject_Call(PyEnumType, callArgs, callDict);
+ if (!obNewType || PyObject_SetAttr(scopeOrModule, pyName, obNewType) < 0)
+ return nullptr;
+
+ // For compatibility with Qt enums, provide a permissive missing method for (Int)?Enum.
+ if (!isFlag) {
+ bool supportMissing = !(Enum::enumOption & Enum::ENOPT_NO_MISSING);
+ if (supportMissing) {
+ AutoDecRef enum_missing(create_missing_func(obNewType));
+ PyObject_SetAttrString(obNewType, "_missing_", enum_missing);
+ }
+ }
+
+ auto *newType = reinterpret_cast<PyTypeObject *>(obNewType);
+ PyObject_SetAttr(obNewType, PyMagicName::qualname(), qualname);
+ PyObject_SetAttr(obNewType, PyMagicName::module(), module);
+
+ // See if we should re-introduce shortcuts in the enclosing object.
+ const bool useGlobalShortcut = (Enum::enumOption & Enum::ENOPT_GLOBAL_SHORTCUT) != 0;
+ const bool useScopedShortcut = (Enum::enumOption & Enum::ENOPT_SCOPED_SHORTCUT) != 0;
+ if (useGlobalShortcut || useScopedShortcut) {
+ // We have to use the iterator protokol because the values dict is a mappingproxy.
+ AutoDecRef values(PyObject_GetAttr(obNewType, PyMagicName::members()));
+ AutoDecRef mapIterator(PyObject_GetIter(values));
+ AutoDecRef mapKey{};
+ bool isModule = PyModule_Check(scopeOrModule);
+ while ((mapKey.reset(PyIter_Next(mapIterator))), mapKey.object()) {
+ if ((useGlobalShortcut && isModule) || (useScopedShortcut && !isModule)) {
+ AutoDecRef value(PyObject_GetItem(values, mapKey));
+ if (PyObject_SetAttr(scopeOrModule, mapKey, value) < 0)
+ return nullptr;
+ }
+ }
+ }
+
+ return newType;
+}
+
+template <typename IntT>
+static PyObject *toPyObject(IntT v)
+{
+ if constexpr (sizeof(IntT) == 8) {
+ if constexpr (std::is_unsigned_v<IntT>)
+ return PyLong_FromUnsignedLongLong(v);
+ return PyLong_FromLongLong(v);
+ }
+ if constexpr (std::is_unsigned_v<IntT>)
+ return PyLong_FromUnsignedLong(v);
+ return PyLong_FromLong(v);
+}
+
+template <typename IntT>
+static PyTypeObject *createPythonEnumHelper(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const IntT enumValues[])
+{
+ AutoDecRef args(PyList_New(0));
+ auto *pyEnumItems = args.object();
+ for (size_t idx = 0; enumItemStrings[idx] != nullptr; ++idx) {
+ const char *kv = enumItemStrings[idx];
+ auto *key = PyUnicode_FromString(kv);
+ auto *value = toPyObject(enumValues[idx]);
+ auto *key_value = PyTuple_New(2);
+ PyTuple_SET_ITEM(key_value, 0, key);
+ PyTuple_SET_ITEM(key_value, 1, value);
+ PyList_Append(pyEnumItems, key_value);
+ }
+ return createEnumForPython(module, fullName, pyEnumItems);
+}
+
+// Now we have to concretize these functions explicitly,
+// otherwise templates will not work across modules.
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int64_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint64_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int32_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint32_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int16_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint16_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int8_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint8_t enumValues[])
+{
+ return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues);
+}
+
+} // namespace Shiboken::Enum
diff --git a/sources/shiboken6/libshiboken/sbkenum.h b/sources/shiboken6/libshiboken/sbkenum.h
new file mode 100644
index 000000000..e19ca4b4c
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkenum.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKENUM_H
+#define SBKENUM_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+extern "C"
+{
+
+LIBSHIBOKEN_API bool PyEnumMeta_Check(PyObject *ob);
+
+/// exposed for the signature module
+LIBSHIBOKEN_API void init_enum();
+
+struct SbkConverter;
+struct SbkEnumType;
+
+struct SbkEnumTypePrivate
+{
+ SbkConverter *converter;
+};
+
+/// PYSIDE-1735: Pass on the Python enum/flag information.
+LIBSHIBOKEN_API void initEnumFlagsDict(PyTypeObject *type);
+
+/// PYSIDE-1735: Make sure that we can import the Python enum implementation.
+LIBSHIBOKEN_API PyTypeObject *getPyEnumMeta();
+/// PYSIDE-1735: Helper function supporting QEnum
+LIBSHIBOKEN_API int enumIsFlag(PyObject *ob_enum);
+
+}
+
+namespace Shiboken::Enum {
+
+enum : int {
+ ENOPT_OLD_ENUM = 0x00, // PySide 6.6: no longer supported
+ ENOPT_NEW_ENUM = 0x01,
+ ENOPT_INHERIT_INT = 0x02,
+ ENOPT_GLOBAL_SHORTCUT = 0x04,
+ ENOPT_SCOPED_SHORTCUT = 0x08,
+ ENOPT_NO_FAKESHORTCUT = 0x10,
+ ENOPT_NO_FAKERENAMES = 0x20,
+ ENOPT_NO_ZERODEFAULT = 0x40,
+ ENOPT_NO_MISSING = 0x80,
+};
+
+LIBSHIBOKEN_API extern int enumOption;
+
+using EnumValueType = long long;
+
+LIBSHIBOKEN_API bool check(PyObject *obj);
+
+LIBSHIBOKEN_API PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue,
+ const char *itemName = nullptr);
+
+LIBSHIBOKEN_API EnumValueType getValue(PyObject *enumItem);
+LIBSHIBOKEN_API PyObject *getEnumItemFromValue(PyTypeObject *enumType,
+ EnumValueType itemValue);
+
+/// Sets the enum/flag's type converter.
+LIBSHIBOKEN_API void setTypeConverter(PyTypeObject *type, SbkConverter *converter);
+
+/// Creating Python enums for different types.
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int64_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint64_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int32_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint32_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int16_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint16_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const int8_t enumValues[]);
+
+LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module,
+ const char *fullName, const char *enumItemStrings[], const uint8_t enumValues[]);
+
+/// This template removes duplication by inlining necessary type casts.
+template <typename IntT>
+inline PyTypeObject *createPythonEnum(PyTypeObject *scope,
+ const char *fullName, const char *enumItemStrings[], const IntT enumValues[])
+{
+ auto *obScope = reinterpret_cast<PyObject *>(scope);
+ return createPythonEnum(obScope, fullName, enumItemStrings, enumValues);
+}
+
+} // namespace Shiboken::Enum
+
+#endif // SKB_PYENUM_H
diff --git a/sources/shiboken6/libshiboken/sbkerrors.cpp b/sources/shiboken6/libshiboken/sbkerrors.cpp
new file mode 100644
index 000000000..84c080f8d
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkerrors.cpp
@@ -0,0 +1,215 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkerrors.h"
+#include "sbkstring.h"
+#include "helper.h"
+#include "gilstate.h"
+
+#include <cstdio>
+#include <string>
+
+using namespace std::literals::string_literals;
+
+namespace Shiboken
+{
+
+// PYSIDE-2335: Track down if we can reach a Python error handler.
+// _pythonContextStack has always the current state of handler status
+// in its lowest bit.
+// Blocking calls like exec or run need to use `setBlocking`.
+static thread_local std::size_t _pythonContextStack{};
+
+PythonContextMarker::PythonContextMarker()
+{
+ // Shift history up and set lowest bit.
+ _pythonContextStack = (_pythonContextStack * 2) + 1;
+}
+
+PythonContextMarker::~PythonContextMarker()
+{
+ // Shift history down.
+ _pythonContextStack /= 2;
+}
+
+void PythonContextMarker::setBlocking()
+{
+ // Clear lowest bit.
+ _pythonContextStack = _pythonContextStack / 2 * 2;
+}
+
+namespace Errors
+{
+
+void setInstantiateAbstractClass(const char *name)
+{
+ PyErr_Format(PyExc_NotImplementedError,
+ "'%s' represents a C++ abstract class and cannot be instantiated", name);
+}
+
+void setInstantiateAbstractClassDisabledWrapper(const char *name)
+{
+ PyErr_Format(PyExc_NotImplementedError,
+ "Abstract class '%s' cannot be instantiated since the wrapper has been disabled.",
+ name);
+}
+
+void setInvalidTypeDeletion(const char *name)
+{
+ PyErr_Format(PyExc_TypeError, "'%s' may not be deleted", name);
+}
+
+void setOperatorNotImplemented()
+{
+ PyErr_SetString(PyExc_NotImplementedError, "operator not implemented.");
+}
+
+void setPureVirtualMethodError(const char *name)
+{
+ PyErr_Format(PyExc_NotImplementedError, "pure virtual method '%s' not implemented.", name);
+}
+
+void setPrivateMethod(const char *name)
+{
+ PyErr_Format(PyExc_TypeError, "%s is a private method.\", ", name);
+}
+
+void setReverseOperatorNotImplemented()
+{
+ PyErr_SetString(PyExc_NotImplementedError, "reverse operator not implemented.");
+}
+
+void setSequenceTypeError(const char *expectedType)
+{
+ PyErr_Format(PyExc_TypeError,
+ "attributed value with wrong type, '%s' or other convertible type expected",
+ expectedType);
+}
+
+void setSetterTypeError(const char *name, const char *expectedType)
+{
+ PyErr_Format(PyExc_TypeError,
+ "wrong type attributed to '%s', '%s' or convertible type expected",
+ name, expectedType);
+}
+
+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;
+ PyObject *traceback;
+};
+
+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 (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) {
+ PyErr_Restore(savedError.type, savedError.exc, savedError.traceback);
+ savedError.type = nullptr;
+ }
+ return PyErr_Occurred();
+}
+
+} // namespace Errors
+
+namespace Warnings
+{
+void warnInvalidReturnValue(const char *className, const char *functionName,
+ const char *expectedType, const char *actualType)
+{
+ Shiboken::warning(PyExc_RuntimeWarning, 2,
+ "Invalid return value in function '%s.%s', expected %s, got %s.",
+ className, functionName, expectedType, actualType);
+}
+
+void warnDeprecated(const char *functionName)
+{
+ Shiboken::warning(PyExc_DeprecationWarning, 1,
+ "Function: '%s' is marked as deprecated, please check "
+ "the documentation for more information.",
+ functionName);
+}
+
+void warnDeprecated(const char *className, const char *functionName)
+{
+ Shiboken::warning(PyExc_DeprecationWarning, 1,
+ "Function: '%s.%s' is marked as deprecated, please check "
+ "the documentation for more information.",
+ className, functionName);
+}
+
+void warnDeprecatedEnum(const char *enumName)
+{
+ Shiboken::warning(PyExc_DeprecationWarning, 1,
+ "Enum: '%s' is marked as deprecated, please check "
+ "the documentation for more information.",
+ enumName);
+}
+
+void warnDeprecatedEnumValue(const char *enumName, const char *valueName)
+{
+ Shiboken::warning(PyExc_DeprecationWarning, 1,
+ "Enum value '%s.%s' is marked as deprecated, please check "
+ "the documentation for more information.",
+ enumName, valueName);
+
+}
+
+} // namespace Warnings
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/sbkerrors.h b/sources/shiboken6/libshiboken/sbkerrors.h
new file mode 100644
index 000000000..18ce701e7
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkerrors.h
@@ -0,0 +1,78 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKERRORS_H
+#define SBKERRORS_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+/// Craving for C++20 and std::source_location::current()
+#if defined(_MSC_VER)
+# define SBK_FUNC_INFO __FUNCSIG__
+#elif defined(__GNUC__)
+# define SBK_FUNC_INFO __PRETTY_FUNCTION__
+#else
+# define SBK_FUNC_INFO __FUNCTION__
+#endif
+
+namespace Shiboken
+{
+
+struct LIBSHIBOKEN_API PythonContextMarker
+{
+public:
+ PythonContextMarker(const PythonContextMarker &) = delete;
+ PythonContextMarker(PythonContextMarker &&) = delete;
+ PythonContextMarker &operator=(const PythonContextMarker &) = delete;
+ PythonContextMarker &operator=(PythonContextMarker &&) = delete;
+
+ explicit PythonContextMarker();
+ ~PythonContextMarker();
+ void setBlocking();
+};
+
+namespace Errors
+{
+
+LIBSHIBOKEN_API void setInstantiateAbstractClass(const char *name);
+LIBSHIBOKEN_API void setInstantiateAbstractClassDisabledWrapper(const char *name);
+LIBSHIBOKEN_API void setInvalidTypeDeletion(const char *name);
+LIBSHIBOKEN_API void setOperatorNotImplemented();
+LIBSHIBOKEN_API void setPureVirtualMethodError(const char *name);
+LIBSHIBOKEN_API void setPrivateMethod(const char *name);
+LIBSHIBOKEN_API void setReverseOperatorNotImplemented();
+LIBSHIBOKEN_API void setSequenceTypeError(const char *expectedType);
+LIBSHIBOKEN_API void setSetterTypeError(const char *name, const char *expectedType);
+LIBSHIBOKEN_API void setWrongContainerType();
+
+/// Report an error ASAP: Instead of printing, store for later re-raise.
+/// 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.
+LIBSHIBOKEN_API PyObject *occurred();
+
+} // namespace Errors
+
+namespace Warnings
+{
+/// Warn about invalid return value of overwritten virtual
+LIBSHIBOKEN_API void warnInvalidReturnValue(const char *className, const char *functionName,
+ const char *expectedType, const char *actualType);
+LIBSHIBOKEN_API void warnDeprecated(const char *functionName);
+LIBSHIBOKEN_API void warnDeprecated(const char *className, const char *functionName);
+LIBSHIBOKEN_API void warnDeprecatedEnum(const char *enumName);
+LIBSHIBOKEN_API void warnDeprecatedEnumValue(const char *enumName, const char *valueName);
+} // namespace Warnings
+
+} // namespace Shiboken
+
+#endif // SBKERRORS_H
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
new file mode 100644
index 000000000..f31b8f4f7
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
@@ -0,0 +1,424 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+#include "autodecref.h"
+#include "pep384ext.h"
+#include "sbkenum.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "signature.h"
+#include "sbkfeature_base.h"
+#include "gilstate.h"
+
+#include <cctype>
+
+using namespace Shiboken;
+
+extern "C"
+{
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Minimal __feature__ support in Shiboken
+//
+int currentSelectId(PyTypeObject *type)
+{
+ AutoDecRef tpDict(PepType_GetDict(type));
+ PyObject *PyId = PyObject_GetAttr(tpDict.object(), PyName::select_id());
+ if (PyId == nullptr) {
+ PyErr_Clear();
+ return 0x00;
+ }
+ int sel = PyLong_AsLong(PyId);
+ Py_DECREF(PyId);
+ return sel;
+}
+
+static SelectableFeatureHook SelectFeatureSet = nullptr;
+static SelectableFeatureCallback featureCb = nullptr;
+
+void setSelectableFeatureCallback(SelectableFeatureCallback func)
+{
+ featureCb = func;
+}
+
+SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func)
+{
+ auto ret = SelectFeatureSet;
+ SelectFeatureSet = func;
+ if (featureCb)
+ featureCb(SelectFeatureSet != nullptr);
+ return ret;
+}
+//
+////////////////////////////////////////////////////////////////////////////
+
+// This useful function is for debugging
+void disassembleFrame(const char *marker)
+{
+ Shiboken::GilState gil;
+ PyObject *error_type, *error_value, *error_traceback;
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ static PyObject *dismodule = PyImport_ImportModule("dis");
+ static PyObject *disco = PyObject_GetAttrString(dismodule, "disco");
+ static PyObject *const _f_lasti = Shiboken::String::createStaticString("f_lasti");
+ static PyObject *const _f_lineno = Shiboken::String::createStaticString("f_lineno");
+ static PyObject *const _f_code = Shiboken::String::createStaticString("f_code");
+ static PyObject *const _co_filename = Shiboken::String::createStaticString("co_filename");
+ AutoDecRef ignore{};
+ auto *frame = reinterpret_cast<PyObject *>(PyEval_GetFrame());
+ if (frame == nullptr) {
+ fprintf(stdout, "\n%s BEGIN no frame END\n\n", marker);
+ } else {
+ AutoDecRef f_lasti(PyObject_GetAttr(frame, _f_lasti));
+ AutoDecRef f_lineno(PyObject_GetAttr(frame, _f_lineno));
+ AutoDecRef f_code(PyObject_GetAttr(frame, _f_code));
+ AutoDecRef co_filename(PyObject_GetAttr(f_code, _co_filename));
+ long line = PyLong_AsLong(f_lineno);
+ const char *fname = String::toCString(co_filename);
+ fprintf(stdout, "\n%s BEGIN line=%ld %s\n", marker, line, fname);
+ ignore.reset(PyObject_CallFunctionObjArgs(disco, f_code.object(), f_lasti.object(), nullptr));
+ fprintf(stdout, "%s END line=%ld %s\n\n", marker, line, fname);
+ }
+#if PY_VERSION_HEX >= 0x030C0000 && !Py_LIMITED_API
+ if (error_type)
+ PyErr_DisplayException(error_value);
+#endif
+ static PyObject *stdout_file = PySys_GetObject("stdout");
+ ignore.reset(PyObject_CallMethod(stdout_file, "flush", nullptr));
+ PyErr_Restore(error_type, error_value, error_traceback);
+}
+
+// python 3.12
+static int const CALL = 171;
+// Python 3.11
+static int const PRECALL = 166;
+// we have "big instructions" with gaps after them
+static int const LOAD_METHOD_GAP_311 = 10 * 2;
+static int const LOAD_ATTR_GAP_311 = 4 * 2;
+static int const LOAD_ATTR_GAP = 9 * 2;
+// Python 3.7 - 3.10
+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;
+// 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()
+{
+ // PYSIDE-2221: Special case for the NoGil version:
+ // Find out if we have such a version.
+ // We could also ask the variable `Py_NOGIL`.
+ static PyObject *flags = PySys_GetObject("flags");
+ static bool isNoGil = PyObject_HasAttrString(flags, "nogil");
+ // We look into the currently active operation if we are going to call
+ // a method with zero arguments.
+ auto *frame = PyEval_GetFrame();
+#if !Py_LIMITED_API && !defined(PYPY_VERSION)
+ auto *f_code = PyFrame_GetCode(frame);
+#else
+ static PyObject *const _f_code = Shiboken::String::createStaticString("f_code");
+ AutoDecRef dec_f_code(PyObject_GetAttr(reinterpret_cast<PyObject *>(frame), _f_code));
+ auto *f_code = dec_f_code.object();
+#endif
+#if PY_VERSION_HEX >= 0x030B0000 && !Py_LIMITED_API
+ AutoDecRef dec_co_code(PyCode_GetCode(f_code));
+ Py_ssize_t f_lasti = PyFrame_GetLasti(frame);
+#else
+ static PyObject *const _f_lasti = Shiboken::String::createStaticString("f_lasti");
+ static PyObject *const _co_code = Shiboken::String::createStaticString("co_code");
+ AutoDecRef dec_co_code(PyObject_GetAttr(reinterpret_cast<PyObject *>(f_code), _co_code));
+ AutoDecRef dec_f_lasti(PyObject_GetAttr(reinterpret_cast<PyObject *>(frame), _f_lasti));
+ Py_ssize_t f_lasti = PyLong_AsSsize_t(dec_f_lasti);
+#endif
+ Py_ssize_t code_len;
+ char *co_code{};
+ PyBytes_AsStringAndSize(dec_co_code, &co_code, &code_len);
+ uint8_t opcode1 = co_code[f_lasti];
+ if (isNoGil) {
+ uint8_t opcode2 = co_code[f_lasti + 4];
+ uint8_t oparg2 = co_code[f_lasti + 6];
+ return opcode1 == LOAD_METHOD_NOGIL && opcode2 == CALL_METHOD_NOGIL && oparg2 == 1;
+ }
+ 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;
+
+ if (number < 0x030C00) {
+ // With Python 3.11, the opcodes get bigger and change a bit.
+ // Note: The new adaptive opcodes are elegantly hidden and we
+ // don't need to take care of them.
+ if (opcode1 == LOAD_METHOD)
+ f_lasti += LOAD_METHOD_GAP_311;
+ else if (opcode1 == LOAD_ATTR)
+ f_lasti += LOAD_ATTR_GAP_311;
+ else
+ return false;
+
+ opcode2 = co_code[f_lasti + 2];
+ oparg2 = co_code[f_lasti + 3];
+
+ return opcode2 == PRECALL && oparg2 == 0;
+ }
+ // With Python 3.12, the opcodes get again bigger and change a bit.
+ // Note: The new adaptive opcodes are elegantly hidden and we
+ // don't need to take care of them.
+ if (opcode1 == LOAD_ATTR)
+ f_lasti += LOAD_ATTR_GAP;
+ else
+ return false;
+
+ opcode2 = co_code[f_lasti + 2];
+ oparg2 = co_code[f_lasti + 3];
+
+ return opcode2 == CALL && oparg2 == 0;
+}
+
+void initEnumFlagsDict(PyTypeObject *type)
+{
+ // We create a dict for all flag enums that holds the original C++ name
+ // and a dict that gives every enum/flag type name.
+ static PyObject *const split = Shiboken::String::createStaticString("split");
+ static PyObject *const colon = Shiboken::String::createStaticString(":");
+ auto sotp = PepType_SOTP(type);
+ auto **enumFlagInfo = sotp->enumFlagInfo;
+ auto *dict = PyDict_New();
+ auto *typeDict = PyDict_New();
+ for (; *enumFlagInfo; ++enumFlagInfo) {
+ AutoDecRef line(PyUnicode_FromString(*enumFlagInfo));
+ AutoDecRef parts(PyObject_CallMethodObjArgs(line, split, colon, nullptr));
+ auto *name = PyList_GetItem(parts, 0);
+ if (PyList_Size(parts) == 3) {
+ auto *key = PyList_GetItem(parts, 2);
+ auto *value = name;
+ PyDict_SetItem(dict, key, value);
+ }
+ auto *typeName = PyList_GetItem(parts, 1);
+ PyDict_SetItem(typeDict, name, typeName);
+ }
+ sotp->enumFlagsDict = dict;
+ sotp->enumTypeDict = typeDict;
+}
+
+static PyObject *replaceNoArgWithZero(PyObject *callable)
+{
+ static auto *partial = Pep_GetPartialFunction();
+ static auto *zero = PyLong_FromLong(0);
+ return PyObject_CallFunctionObjArgs(partial, callable, zero, nullptr);
+}
+
+static PyObject *lookupUnqualifiedOrOldEnum(PyTypeObject *type, PyObject *name)
+{
+ // MRO has been observed to be 0 in case of errors with QML decorators
+ if (type == nullptr || type->tp_mro == nullptr)
+ return nullptr;
+ // Quick Check: Avoid "__..", "_slots", etc.
+ if (std::isalpha(Shiboken::String::toCString(name)[0]) == 0)
+ return nullptr;
+ static PyTypeObject *const EnumMeta = getPyEnumMeta();
+ static PyObject *const _member_map_ = String::createStaticString("_member_map_");
+ // This is similar to `find_name_in_mro`, but instead of looking directly into
+ // tp_dict, we also search for the attribute in local classes of that dict (Part 2).
+ PyObject *mro = type->tp_mro;
+ PyObject *result{};
+ assert(PyTuple_Check(mro));
+ Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
+ for (idx = 0; idx < n; ++idx) {
+ auto *base = PyTuple_GET_ITEM(mro, idx);
+ auto *type_base = reinterpret_cast<PyTypeObject *>(base);
+ if (!SbkObjectType_Check(type_base))
+ continue;
+ auto sotp = PepType_SOTP(type_base);
+ // The EnumFlagInfo structure tells us if there are Enums at all.
+ const char **enumFlagInfo = sotp->enumFlagInfo;
+ if (!(enumFlagInfo))
+ continue;
+ if (!sotp->enumFlagsDict)
+ initEnumFlagsDict(type_base);
+ bool useFakeRenames = !(Enum::enumOption & Enum::ENOPT_NO_FAKERENAMES);
+ if (useFakeRenames) {
+ auto *rename = PyDict_GetItem(sotp->enumFlagsDict, name);
+ if (rename) {
+ /*
+ * Part 1: Look into the enumFlagsDict if we have an old flags name.
+ * -------------------------------------------------------------
+ * We need to replace the parameterless
+
+ QtCore.Qt.Alignment()
+
+ * by the one-parameter call
+
+ QtCore.Qt.AlignmentFlag(0)
+
+ * That means: We need to bind the zero as default into a wrapper and
+ * return that to be called.
+ *
+ * Addendum:
+ * ---------
+ * We first need to look into the current opcode of the bytecode to find
+ * out if we have a call like above or just a type lookup.
+ */
+ AutoDecRef tpDict(PepType_GetDict(type_base));
+ auto *flagType = PyDict_GetItem(tpDict.object(), rename);
+ if (currentOpcode_Is_CallMethNoArgs())
+ return replaceNoArgWithZero(flagType);
+ Py_INCREF(flagType);
+ return flagType;
+ }
+ }
+ bool useFakeShortcuts = !(Enum::enumOption & Enum::ENOPT_NO_FAKESHORTCUT);
+ if (useFakeShortcuts) {
+ AutoDecRef tpDict(PepType_GetDict(type_base));
+ auto *dict = tpDict.object();
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ /*
+ * Part 2: Check for a duplication into outer scope.
+ * -------------------------------------------------
+ * We need to replace the shortcut
+
+ QtCore.Qt.AlignLeft
+
+ * by the correct call
+
+ QtCore.Qt.AlignmentFlag.AlignLeft
+
+ * That means: We need to search all Enums of the class.
+ */
+ if (Py_TYPE(value) == EnumMeta) {
+ auto *valtype = reinterpret_cast<PyTypeObject *>(value);
+ AutoDecRef valtypeDict(PepType_GetDict(valtype));
+ auto *member_map = PyDict_GetItem(valtypeDict.object(), _member_map_);
+ if (member_map && PyDict_Check(member_map)) {
+ result = PyDict_GetItem(member_map, name);
+ Py_XINCREF(result);
+ if (result)
+ return result;
+ }
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name)
+{
+ /*
+ * Note: This `type_getattro` version is only the default that comes
+ * from `PyType_Type.tp_getattro`. This does *not* interfere in any way
+ * with the complex `tp_getattro` of `QObject` and other instances.
+ * What we change here is the meta class of `QObject`.
+ */
+ static getattrofunc const type_getattro = PepExt_Type_GetGetAttroSlot(&PyType_Type);
+ static PyObject *const ignAttr1 = PyName::qtStaticMetaObject();
+ static PyObject *const ignAttr2 = PyMagicName::get();
+ static PyTypeObject *const EnumMeta = getPyEnumMeta();
+
+ if (SelectFeatureSet != nullptr)
+ SelectFeatureSet(type);
+ auto *ret = type_getattro(reinterpret_cast<PyObject *>(type), name);
+
+ // PYSIDE-1735: Be forgiving with strict enums and fetch the enum, silently.
+ // The PYI files now look correct, but the old duplication is
+ // emulated here. This should be removed in Qt 7, see `parser.py`.
+ //
+ // FIXME PYSIDE7 should remove this forgiveness:
+ //
+ // The duplication of enum values into the enclosing scope, allowing to write
+ // Qt.AlignLeft instead of Qt.Alignment.AlignLeft, is still implemented but
+ // no longer advertized in PYI files or line completion.
+
+ if (ret && Py_TYPE(ret) == EnumMeta && currentOpcode_Is_CallMethNoArgs()) {
+ bool useZeroDefault = !(Enum::enumOption & Enum::ENOPT_NO_ZERODEFAULT);
+ if (useZeroDefault) {
+ // We provide a zero argument for compatibility if it is a call with no args.
+ auto *hold = replaceNoArgWithZero(ret);
+ Py_DECREF(ret);
+ ret = hold;
+ }
+ }
+
+ if (!ret && name != ignAttr1 && name != ignAttr2) {
+ PyObject *error_type{}, *error_value{}, *error_traceback{};
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ ret = lookupUnqualifiedOrOldEnum(type, name);
+ if (ret) {
+ Py_DECREF(error_type);
+ Py_XDECREF(error_value);
+ Py_XDECREF(error_traceback);
+ } else {
+ PyErr_Restore(error_type, error_value, error_traceback);
+ }
+ }
+ return ret;
+}
+
+PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void * /* context */)
+{
+ /*
+ * This is the override for getting a dict.
+ */
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *dict = tpDict.object();;
+ if (dict == nullptr)
+ Py_RETURN_NONE;
+ if (SelectFeatureSet != nullptr) {
+ SelectFeatureSet(type);
+ tpDict.reset(PepType_GetDict(type));
+ dict = tpDict.object();
+ }
+ return PyDictProxy_New(dict);
+}
+
+// These functions replace the standard PyObject_Generic(Get|Set)Attr functions.
+// They provide the default that "object" inherits.
+// Everything else is directly handled by cppgenerator that calls `Feature::Select`.
+PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name)
+{
+ auto type = Py_TYPE(obj);
+ if (SelectFeatureSet != nullptr)
+ SelectFeatureSet(type);
+ return PyObject_GenericGetAttr(obj, name);
+}
+
+int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
+{
+ auto type = Py_TYPE(obj);
+ if (SelectFeatureSet != nullptr)
+ SelectFeatureSet(type);
+ return PyObject_GenericSetAttr(obj, name, value);
+}
+
+const char **SbkObjectType_GetPropertyStrings(PyTypeObject *type)
+{
+ return PepType_SOTP(type)->propertyStrings;
+}
+
+void SbkObjectType_SetPropertyStrings(PyTypeObject *type, const char **strings)
+{
+ PepType_SOTP(type)->propertyStrings = strings;
+}
+
+void SbkObjectType_SetEnumFlagInfo(PyTypeObject *type, const char **strings)
+{
+ PepType_SOTP(type)->enumFlagInfo = strings;
+}
+
+// PYSIDE-1626: Enforcing a context switch without further action.
+void SbkObjectType_UpdateFeature(PyTypeObject *type)
+{
+ if (SelectFeatureSet != nullptr)
+ SelectFeatureSet(type);
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.h b/sources/shiboken6/libshiboken/sbkfeature_base.h
new file mode 100644
index 000000000..290884062
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKFEATURE_BASE_H
+#define SBKFEATURE_BASE_H
+
+extern "C"
+{
+
+LIBSHIBOKEN_API int currentSelectId(PyTypeObject *type);
+LIBSHIBOKEN_API PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name);
+LIBSHIBOKEN_API PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context);
+LIBSHIBOKEN_API PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name);
+LIBSHIBOKEN_API int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value);
+
+} // extern "C"
+
+#endif // SBKFEATURE_BASE_H
diff --git a/sources/shiboken6/libshiboken/sbkmodule.cpp b/sources/shiboken6/libshiboken/sbkmodule.cpp
new file mode 100644
index 000000000..6b080d5fb
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkmodule.cpp
@@ -0,0 +1,525 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkmodule.h"
+#include "autodecref.h"
+#include "basewrapper.h"
+#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 *> ;
+
+struct TypeCreationStruct
+{
+ Shiboken::Module::TypeCreationFunction func;
+ std::vector<std::string> subtypeNames;
+};
+
+/// 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> ;
+
+/// All types produced in imported modules are mapped here.
+static ModuleTypesMap moduleTypes;
+static ModuleConvertersMap moduleConverters;
+static ModuleToFuncsMap moduleToFuncs;
+
+namespace Shiboken
+{
+namespace Module
+{
+
+// PYSIDE-2404: Replacing the arguments generated by cpythonTypeNameExt
+// by a function call.
+LIBSHIBOKEN_API PyTypeObject *get(TypeInitStruct &typeStruct)
+{
+ if (typeStruct.type != nullptr)
+ return typeStruct.type;
+
+ static PyObject *sysModules = PyImport_GetModuleDict();
+
+ // The slow path for initialization.
+ // We get the type by following the chain from the module.
+ // As soon as types[index] gets filled, we can stop.
+
+ std::string_view names(typeStruct.fullName);
+ const bool usePySide = names.compare(0, 8, "PySide6.") == 0;
+ auto dotPos = usePySide ? names.find('.', 8) : names.find('.');
+ auto startPos = dotPos + 1;
+ AutoDecRef modName(String::fromCppStringView(names.substr(0, dotPos)));
+ auto *modOrType = PyDict_GetItem(sysModules, modName);
+ if (modOrType == nullptr) {
+ PyErr_Format(PyExc_SystemError, "Module \"%U\" should already be in sys.modules",
+ modName.object());
+ return nullptr;
+ }
+
+ do {
+ dotPos = names.find('.', startPos);
+ auto typeName = dotPos != std::string::npos
+ ? names.substr(startPos, dotPos - startPos)
+ : names.substr(startPos);
+ startPos = dotPos + 1;
+ AutoDecRef obTypeName(String::fromCppStringView(typeName));
+ modOrType = PyObject_GetAttr(modOrType, obTypeName);
+ } while (typeStruct.type == nullptr && dotPos != std::string::npos);
+
+ 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)
+{
+ // - locate the name and retrieve the generating function
+ auto funcIter = nameToFunc.find(name);
+ if (funcIter == nameToFunc.end()) {
+ // attribute does really not exist.
+ PyErr_SetNone(PyExc_AttributeError);
+ return nullptr;
+ }
+ // - call this function that returns a PyTypeObject
+ 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
+ auto *res = reinterpret_cast<PyObject *>(type);
+ Py_INCREF(res);
+ PyModule_AddObject(module, name, res); // steals reference
+ // - remove the entry, if not by something cleared.
+ if (!nameToFunc.empty())
+ nameToFunc.erase(funcIter);
+ // - return the PyTypeObject.
+ return type;
+}
+
+// PYSIDE-2404: Make sure that the mentioned classes really exist.
+// Used in `Pyside::typeName`. Because the result will be cached by
+// the creation of the type(s), this is efficient.
+void loadLazyClassesWithName(const char *name)
+{
+ for (auto const & tableIter : moduleToFuncs) {
+ auto nameToFunc = tableIter.second;
+ auto funcIter = nameToFunc.find(name);
+ if (funcIter != nameToFunc.end()) {
+ // attribute exists in the lazy types.
+ auto *module = tableIter.first;
+ incarnateType(module, name, nameToFunc);
+ }
+ }
+}
+
+// PYSIDE-2404: Completely load all not yet loaded classes.
+// This is needed to resolve a star import.
+void resolveLazyClasses(PyObject *module)
+{
+ // - locate the module in the moduleTofuncs mapping
+ auto tableIter = moduleToFuncs.find(module);
+ if (tableIter == moduleToFuncs.end())
+ return;
+
+ // - see if there are still unloaded elements
+ auto &nameToFunc = tableIter->second;
+
+ // - incarnate all types.
+ while (!nameToFunc.empty()) {
+ auto it = nameToFunc.begin();
+ auto attrNameStr = it->first;
+ incarnateType(module, attrNameStr.c_str(), nameToFunc);
+ }
+}
+
+// PYSIDE-2404: Override the gettattr function of modules.
+static getattrofunc origModuleGetattro{};
+
+// PYSIDE-2404: Use the patched module getattr to do on-demand initialization.
+// This modifies _all_ modules but should have no impact.
+static PyObject *PyModule_lazyGetAttro(PyObject *module, PyObject *name)
+{
+ // - check if the attribute is present and return it.
+ auto *attr = PyObject_GenericGetAttr(module, name);
+ // - we handle AttributeError, only.
+ if (!(attr == nullptr && PyErr_ExceptionMatches(PyExc_AttributeError)))
+ return attr;
+
+ PyErr_Clear();
+ // - locate the module in the moduleTofuncs mapping
+ auto tableIter = moduleToFuncs.find(module);
+ // - if this is not our module, use the original
+ if (tableIter == moduleToFuncs.end())
+ return origModuleGetattro(module, name);
+
+ // - locate the name and retrieve the generating function
+ const char *attrNameStr = Shiboken::String::toCString(name);
+ auto &nameToFunc = tableIter->second;
+ // - 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
+ if (ret == nullptr && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ return origModuleGetattro(module, name);
+ }
+ return ret;
+}
+
+// PYSIDE-2404: Supply a new module dir for not yet visible entries.
+// This modification is only for "our" modules.
+static PyObject *_module_dir_template(PyObject * /* self */, PyObject *args)
+{
+ static PyObject *const _dict = Shiboken::String::createStaticString("__dict__");
+ // The dir function must replace all of the builtin function.
+ PyObject *module{};
+ if (!PyArg_ParseTuple(args, "O", &module))
+ return nullptr;
+
+ auto tableIter = moduleToFuncs.find(module);
+ assert(tableIter != moduleToFuncs.end());
+ Shiboken::AutoDecRef dict(PyObject_GetAttr(module, _dict));
+ auto *ret = PyDict_Keys(dict);
+ // Now add all elements that were not yet in the dict.
+ auto &nameToFunc = tableIter->second;
+ for (const auto &funcIter : nameToFunc) {
+ const char *name = funcIter.first.c_str();
+ Shiboken::AutoDecRef pyName(PyUnicode_FromString(name));
+ PyList_Append(ret, pyName);
+ }
+ return ret;
+}
+
+static PyMethodDef module_methods[] = {
+ {"__dir__", (PyCFunction)_module_dir_template, METH_VARARGS, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+// Python 3.8 - 3.12
+static int const LOAD_CONST_312 = 100;
+static int const IMPORT_NAME_312 = 108;
+
+static bool isImportStar(PyObject *module)
+{
+ // Find out whether we have a star import. This must work even
+ // when we have no import support from feature.
+ static PyObject *const _f_code = Shiboken::String::createStaticString("f_code");
+ static PyObject *const _f_lasti = Shiboken::String::createStaticString("f_lasti");
+ static PyObject *const _f_back = Shiboken::String::createStaticString("f_back");
+ static PyObject *const _co_code = Shiboken::String::createStaticString("co_code");
+ static PyObject *const _co_consts = Shiboken::String::createStaticString("co_consts");
+ static PyObject *const _co_names = Shiboken::String::createStaticString("co_names");
+
+ auto *obFrame = reinterpret_cast<PyObject *>(PyEval_GetFrame());
+ if (obFrame == nullptr)
+ return true; // better assume worst-case.
+
+ Py_INCREF(obFrame);
+ AutoDecRef dec_frame(obFrame);
+
+ // Calculate the offset of the running import_name opcode on the stack.
+ // Right before that there must be a load_const with the tuple `("*",)`.
+ while (dec_frame.object() != Py_None) {
+ AutoDecRef dec_f_code(PyObject_GetAttr(dec_frame, _f_code));
+ AutoDecRef dec_co_code(PyObject_GetAttr(dec_f_code, _co_code));
+ AutoDecRef dec_f_lasti(PyObject_GetAttr(dec_frame, _f_lasti));
+ Py_ssize_t f_lasti = PyLong_AsSsize_t(dec_f_lasti);
+ Py_ssize_t code_len;
+ char *co_code{};
+ 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) {
+ 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));
+ auto *fromlist = PyTuple_GetItem(dec_co_consts, oparg1);
+ if (PyTuple_Check(fromlist) && PyTuple_Size(fromlist) == 1
+ && Shiboken::String::toCString(PyTuple_GetItem(fromlist, 0))[0] == '*') {
+ AutoDecRef dec_co_names(PyObject_GetAttr(dec_f_code, _co_names));
+ const char *name = String::toCString(PyTuple_GetItem(dec_co_names, oparg2));
+ const char *modName = PyModule_GetName(module);
+ if (std::strcmp(name, modName) == 0)
+ return true;
+ }
+ }
+ dec_frame.reset(PyObject_GetAttr(dec_frame, _f_back));
+ }
+ return false;
+}
+
+// PYSIDE-2404: These modules produce ambiguous names which we cannot handle, yet.
+static std::unordered_set<std::string> dontLazyLoad{
+ "testbinding"
+};
+
+static const std::unordered_set<std::string> knownModules{
+ "shiboken6.Shiboken",
+ "minimal",
+ "other",
+ "sample",
+ "smart",
+ "scriptableapplication",
+ "testbinding"
+};
+
+static bool canNotLazyLoad(PyObject *module)
+{
+ const char *modName = PyModule_GetName(module);
+
+ // There are no more things that must be disabled :-D
+ return dontLazyLoad.find(modName) != dontLazyLoad.end();
+}
+
+static bool shouldLazyLoad(PyObject *module)
+{
+ const char *modName = PyModule_GetName(module);
+
+ if (knownModules.find(modName) != knownModules.end())
+ return true;
+ return std::strncmp(modName, "PySide6.", 8) == 0;
+}
+
+static int lazyLoadDefault()
+{
+#ifndef PYPY_VERSION
+ int result = 1;
+#else
+ int result = 0;
+#endif
+ if (auto *flag = getenv("PYSIDE6_OPTION_LAZY"))
+ result = std::atoi(flag);
+ return result;
+}
+
+void checkIfShouldLoadImmediately(PyObject *module, const std::string &name,
+ const NameToTypeFunctionMap &nameToFunc)
+{
+ static const int value = lazyLoadDefault();
+
+ // PYSIDE-2404: Lazy Loading
+ //
+ // Options:
+ // 0 - switch lazy loading off.
+ // 1 - lazy loading for all known modules.
+ // 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
+ ) {
+ incarnateHelper(module, name, nameToFunc);
+ }
+}
+
+void AddTypeCreationFunction(PyObject *module,
+ const char *name,
+ TypeCreationFunction func)
+{
+ // - 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;
+
+ checkIfShouldLoadImmediately(module, name, nameToFunc);
+}
+
+void AddTypeCreationFunction(PyObject *module,
+ const char *containerName,
+ TypeCreationFunction func,
+ const char *namePath)
+{
+ // - 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)
+{
+ PyObject *sysModules = PyImport_GetModuleDict();
+ PyObject *module = PyDict_GetItemString(sysModules, moduleName);
+ if (module != nullptr)
+ Py_INCREF(module);
+ else
+ module = PyImport_ImportModule(moduleName);
+
+ if (module == nullptr)
+ PyErr_Format(PyExc_ImportError, "could not import module '%s'", moduleName);
+
+ return module;
+}
+
+// PYSIDE-2404: Redirecting import for "import *" support.
+//
+// The first import will be handled by the isImportStar function.
+// But the same module might be imported twice, which would give no
+// introspection due to module caching.
+
+static PyObject *origImportFunc{};
+
+static PyObject *lazy_import(PyObject * /* self */, PyObject *args, PyObject *kwds)
+{
+ auto *ret = PyObject_Call(origImportFunc, args, kwds);
+ if (ret != nullptr) {
+ // PYSIDE-2404: Support star import when lazy loading.
+ if (PyTuple_Size(args) >= 4) {
+ auto *fromlist = PyTuple_GetItem(args, 3);
+ if (PyTuple_Check(fromlist) && PyTuple_Size(fromlist) == 1
+ && Shiboken::String::toCString(PyTuple_GetItem(fromlist, 0))[0] == '*')
+ Shiboken::Module::resolveLazyClasses(ret);
+ }
+ }
+ return ret;
+}
+
+static PyMethodDef lazy_methods[] = {
+ {"__lazy_import__", (PyCFunction)lazy_import, METH_VARARGS | METH_KEYWORDS, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+PyObject *create(const char * /* modName */, void *moduleData)
+{
+ static auto *sysModules = PyImport_GetModuleDict();
+ static auto *builtins = PyEval_GetBuiltins();
+ static auto *partial = Pep_GetPartialFunction();
+ static bool lazy_init{};
+
+ Shiboken::init();
+ auto *module = PyModule_Create(reinterpret_cast<PyModuleDef *>(moduleData));
+
+ // Setup of a dir function for "missing" classes.
+ auto *moduleDirTemplate = PyCFunction_NewEx(module_methods, nullptr, nullptr);
+ // Turn this function into a bound object, so we have access to the module.
+ auto *moduleDir = PyObject_CallFunctionObjArgs(partial, moduleDirTemplate, module, nullptr);
+ PyModule_AddObject(module, module_methods->ml_name, moduleDir); // steals reference
+ // Insert an initial empty table for the module.
+ NameToTypeFunctionMap empty;
+ moduleToFuncs.insert(std::make_pair(module, empty));
+
+ // A star import must be done unconditionally. Use the complete name.
+ if (isImportStar(module))
+ dontLazyLoad.insert(PyModule_GetName(module));
+
+ if (!lazy_init) {
+ // Install the getattr patch.
+ origModuleGetattro = PyModule_Type.tp_getattro;
+ PyModule_Type.tp_getattro = PyModule_lazyGetAttro;
+ // Add the lazy import redirection.
+ origImportFunc = PyDict_GetItemString(builtins, "__import__");
+ auto *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
+ // in an invisible virtual module (i.e. `QtCore-postLoad`)
+ // that gets imported before the running import can call
+ // `_PyImport_FixupExtensionObject` which does the insertion
+ // 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;
+}
+
+void registerTypes(PyObject *module, TypeInitStruct *types)
+{
+ auto iter = moduleTypes.find(module);
+ if (iter == moduleTypes.end())
+ moduleTypes.insert(std::make_pair(module, types));
+}
+
+TypeInitStruct *getTypes(PyObject *module)
+{
+ auto iter = moduleTypes.find(module);
+ return (iter == moduleTypes.end()) ? 0 : iter->second;
+}
+
+void registerTypeConverters(PyObject *module, SbkConverter **converters)
+{
+ auto iter = moduleConverters.find(module);
+ if (iter == moduleConverters.end())
+ moduleConverters.insert(std::make_pair(module, converters));
+}
+
+SbkConverter **getTypeConverters(PyObject *module)
+{
+ auto iter = moduleConverters.find(module);
+ return (iter == moduleConverters.end()) ? 0 : iter->second;
+}
+
+} } // namespace Shiboken::Module
diff --git a/sources/shiboken6/libshiboken/sbkmodule.h b/sources/shiboken6/libshiboken/sbkmodule.h
new file mode 100644
index 000000000..2c407e09d
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkmodule.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_MODULE_H
+#define SBK_MODULE_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+extern "C"
+{
+struct SbkConverter;
+}
+
+namespace Shiboken::Module {
+
+struct TypeInitStruct
+{
+ PyTypeObject *type;
+ const char *fullName;
+};
+
+/// PYSIDE-2404: Replacing the arguments in cpythonTypeNameExt by a function.
+LIBSHIBOKEN_API PyTypeObject *get(TypeInitStruct &typeStruct);
+
+/// PYSIDE-2404: Make sure that mentioned classes really exist.
+LIBSHIBOKEN_API void loadLazyClassesWithName(const char *name);
+
+/// PYSIDE-2404: incarnate all classes for star imports.
+LIBSHIBOKEN_API void resolveLazyClasses(PyObject *module);
+
+/**
+ * Imports and returns the module named \p moduleName, or a NULL pointer in case of failure.
+ * If the module is already imported, it increments its reference count before returning it.
+ * \returns the module specified in \p moduleName or NULL if an error occurs.
+ */
+LIBSHIBOKEN_API PyObject *import(const char *moduleName);
+
+/**
+ * Creates a new Python module named \p moduleName using the information passed in \p moduleData.
+ * In fact, \p moduleData expects a "PyMethodDef *" object, but that's for Python 2. A "void*"
+ * was preferred to make this work with future Python 3 support.
+ * \returns a newly created module.
+ */
+LIBSHIBOKEN_API PyObject *create(const char *moduleName, void *moduleData);
+
+using TypeCreationFunction = PyTypeObject *(*)(PyObject *module);
+
+/// Adds a type creation function to the module.
+LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
+ const char *name,
+ TypeCreationFunction func);
+
+LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
+ const char *name,
+ TypeCreationFunction func,
+ const char *containerName);
+
+/**
+ * Registers the list of types created by \p module.
+ * \param module Module where the types were created.
+ * \param types Array of PyTypeObject *objects representing the types created on \p module.
+ */
+LIBSHIBOKEN_API void registerTypes(PyObject *module, TypeInitStruct *types);
+
+/**
+ * Retrieves the array of types.
+ * \param module Module where the types were created.
+ * \returns A pointer to the PyTypeObject *array of types.
+ */
+LIBSHIBOKEN_API TypeInitStruct *getTypes(PyObject *module);
+
+/**
+ * Registers the list of converters created by \p module for non-wrapper types.
+ * \param module Module where the converters were created.
+ * \param converters Array of SbkConverter *objects representing the converters created on \p module.
+ */
+LIBSHIBOKEN_API void registerTypeConverters(PyObject *module, SbkConverter **converters);
+
+/**
+ * Retrieves the array of converters.
+ * \param module Module where the converters were created.
+ * \returns A pointer to the SbkConverter *array of converters.
+ */
+LIBSHIBOKEN_API SbkConverter **getTypeConverters(PyObject *module);
+
+} // namespace Shiboken::Module
+
+#endif // SBK_MODULE_H
diff --git a/sources/shiboken6/libshiboken/sbknumpy.cpp b/sources/shiboken6/libshiboken/sbknumpy.cpp
new file mode 100644
index 000000000..b6422e73f
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpy.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+
+#ifdef HAVE_NUMPY
+// Include numpy first to get the proper PyArray_Check
+# include <numpy/arrayobject.h>
+#endif
+
+#include "helper.h"
+#include "sbknumpycheck.h"
+#include "sbkcpptonumpy.h"
+#include "sbknumpyview.h"
+
+#include <algorithm>
+
+namespace Shiboken::Numpy
+{
+
+#ifdef HAVE_NUMPY
+static void initNumPy()
+{
+ // PYSIDE-2404: Delay-initialize numpy from check() as it causes a
+ // significant startup delay (~770 allocations in memray)
+ static bool initialized = false;
+ if (initialized)
+ return;
+ initialized = true;
+ // 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)
+ PyErr_Print();
+}
+#endif // HAVE_NUMPY
+
+bool check(PyObject *pyIn)
+{
+#ifdef HAVE_NUMPY
+ initNumPy();
+ return PyArray_Check(pyIn);
+#else
+ SBK_UNUSED(pyIn);
+ return false;
+#endif
+}
+
+} //namespace Shiboken::Numpy
+
+// Include all sources files using numpy so that they are in the same
+// translation unit (see comment at initNumPyArrayConverters()).
+
+#include "sbknumpyview.cpp"
+#include "sbkcpptonumpy.cpp"
+#ifdef HAVE_NUMPY
+# include "sbknumpyarrayconverter.cpp"
+#endif
diff --git a/sources/shiboken6/libshiboken/sbknumpyarrayconverter.cpp b/sources/shiboken6/libshiboken/sbknumpyarrayconverter.cpp
new file mode 100644
index 000000000..835a97524
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpyarrayconverter.cpp
@@ -0,0 +1,270 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// included by sbknumpy.cpp
+
+#include "sbkarrayconverter.h"
+#include "helper.h"
+#include "sbkconverter.h"
+#include "sbkconverter_p.h"
+#include "sbkarrayconverter_p.h"
+
+#include <algorithm>
+#include <iostream>
+#include <cstdint>
+
+enum { debugNumPy = 0 };
+
+struct TypeCharMapping
+{
+ NPY_TYPES type;
+ const char *name;
+};
+
+static const TypeCharMapping typeCharMappings[] = {
+{NPY_BYTE, "NPY_BYTE"},
+{NPY_UBYTE, "NPY_UBYTE"},
+{NPY_SHORT, "NPY_SHORT"},
+{NPY_USHORT, "NPY_USHORT"},
+{NPY_INT, "NPY_INT"},
+{NPY_UINT, "NPY_UINT"},
+{NPY_LONG, "NPY_LONG"},
+{NPY_ULONG, "NPY_ULONG"},
+{NPY_LONGLONG, "NPY_LONGLONG"},
+{NPY_ULONGLONG, "NPY_ULONGLONG"},
+{NPY_FLOAT, "NPY_FLOAT"},
+{NPY_DOUBLE, "NPY_DOUBLE"}
+};
+
+const char *npTypeName(npy_intp t)
+{
+ const TypeCharMapping *end = typeCharMappings + sizeof(typeCharMappings) / sizeof(typeCharMappings[0]);
+ const TypeCharMapping *result =
+ std::find_if(typeCharMappings, end,
+ [t] (const TypeCharMapping &m) { return m.type == t; });
+ return result != end ? result->name : nullptr;
+}
+
+std::ostream &operator<<(std::ostream &str, PyArrayObject *o)
+{
+ str << "PyArrayObject(";
+ if (o) {
+ const npy_intp npType = PyArray_TYPE(o);
+ if (const char *name = npTypeName(npType))
+ str << name;
+ else
+ str << "type=" << npType;
+ const int nDim = PyArray_NDIM(o);
+ const npy_intp *dims = PyArray_DIMS(o);
+ for (int d = 0; d < nDim; ++d)
+ str << '[' << dims[d] << ']';
+ str << ", ";
+ const int flags = PyArray_FLAGS(o);
+ if ((flags & NPY_ARRAY_C_CONTIGUOUS) != 0)
+ str << " NPY_ARRAY_C_CONTIGUOUS";
+ if ((flags & NPY_ARRAY_F_CONTIGUOUS) != 0)
+ str << " NPY_ARRAY_F_CONTIGUOUS";
+ if ((flags & NPY_ARRAY_OWNDATA) != 0)
+ str << " NPY_ARRAY_OWNDATA";
+ if ((flags & NPY_ARRAY_FORCECAST) != 0)
+ str << " NPY_ARRAY_FORCECAST";
+ if ((flags & NPY_ARRAY_ENSURECOPY) != 0)
+ str << " NPY_ARRAY_ENSURECOPY";
+ if ((flags & NPY_ARRAY_ENSUREARRAY) != 0)
+ str << " NPY_ARRAY_ENSUREARRAY";
+ if ((flags & NPY_ARRAY_ELEMENTSTRIDES) != 0)
+ str << " NPY_ARRAY_ELEMENTSTRIDES";
+ if ((flags & NPY_ARRAY_ALIGNED) != 0)
+ str << " NPY_ARRAY_ALIGNED";
+ if ((flags & NPY_ARRAY_NOTSWAPPED) != 0)
+ str << " NPY_ARRAY_NOTSWAPPED";
+ if ((flags & NPY_ARRAY_WRITEABLE) != 0)
+ str << " NPY_ARRAY_WRITEABLE";
+#if NPY_VERSION >= 0x00000010 // NPY_1_23_API_VERSION
+ if ((flags & NPY_ARRAY_WRITEBACKIFCOPY) != 0)
+ str << " NPY_ARRAY_WRITEBACKIFCOPY";
+#else
+ if ((flags & NPY_ARRAY_UPDATEIFCOPY) != 0)
+ str << " NPY_ARRAY_UPDATEIFCOPY";
+#endif
+ } else {
+ str << '0';
+ }
+ str << ')';
+ return str;
+}
+
+namespace Shiboken::Conversions {
+
+// Internals from sbkarrayconverter.cpp
+SbkArrayConverter *createArrayConverter(IsArrayConvertibleToCppFunc toCppCheckFunc);
+void setArrayTypeConverter(int index, int dimension, SbkArrayConverter *c);
+SbkArrayConverter *unimplementedArrayConverter();
+
+template <int dimension>
+static bool isPrimitiveArray(PyObject *pyIn, int expectedNpType)
+{
+ Shiboken::Numpy::initNumPy();
+ if (!PyArray_Check(pyIn))
+ return false;
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ if (debugNumPy) {
+ std::cerr << __FUNCTION__ << "(expectedNpType=" << expectedNpType;
+ if (const char *name = npTypeName(expectedNpType))
+ std::cerr << " (" << name << ')';
+ std::cerr << ' ' << pya << '\n';
+ }
+
+ const int dim = PyArray_NDIM(pya);
+ if (dim != dimension) {
+ warning(PyExc_RuntimeWarning, 0,
+ "%d dimensional numpy array passed to a function expecting a %d dimensional array.",
+ dim, dimension);
+ return false;
+ }
+ if ((PyArray_FLAGS(pya) & NPY_ARRAY_C_CONTIGUOUS) == 0) {
+ warning(PyExc_RuntimeWarning, 0,
+ "Cannot handle numpy arrays that do not have NPY_ARRAY_C_CONTIGUOUS set.");
+ return false;
+ }
+ const int actualNpType = PyArray_TYPE(pya);
+ if (actualNpType != expectedNpType) {
+ const char *actualName = npTypeName(actualNpType);
+ const char *expectedName = npTypeName(expectedNpType);
+ warning(PyExc_RuntimeWarning, 0,
+ "A numpy array of type %d (%s) was passed to a function expecting type %d (%s).",
+ actualNpType, actualName ? actualName : "",
+ expectedNpType, expectedName ? expectedName : "");
+ return false;
+ }
+ return true;
+}
+
+static inline bool primitiveArrayCheck1(PyObject *pyIn, int expectedNpType, int expectedSize)
+{
+ if (!isPrimitiveArray<1>(pyIn, expectedNpType))
+ return false;
+ if (expectedSize >= 0) {
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ const int size = int(PyArray_DIMS(pya)[0]);
+ if (size < expectedSize) {
+ warning(PyExc_RuntimeWarning, 0, "A numpy array of size %d was passed to a function expects %d.",
+ size, expectedSize);
+ return false;
+ }
+ }
+ return true;
+}
+
+// Convert one-dimensional array
+template <class T>
+static void convertArray1(PyObject *pyIn, void *cppOut)
+{
+ auto *handle = reinterpret_cast<ArrayHandle<T> *>(cppOut);
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ const npy_intp size = PyArray_DIMS(pya)[0];
+ if (debugNumPy)
+ std::cerr << __FUNCTION__ << ' ' << size << '\n';
+ handle->setData(reinterpret_cast<T *>(PyArray_DATA(pya)), size_t(size));
+}
+
+// Convert 2 dimensional array
+template <class T>
+static void convertArray2(PyObject *pyIn, void *cppOut)
+{
+ typedef typename Array2Handle<T, 1>::RowType RowType;
+ auto *handle = reinterpret_cast<Array2Handle<T, 1> *>(cppOut);
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ handle->setData(reinterpret_cast<RowType *>(PyArray_DATA(pya)));
+}
+
+template <class T, int NumPyType>
+static PythonToCppFunc checkArray1(PyObject *pyIn, int dim1, int /* dim2 */)
+{
+ return primitiveArrayCheck1(pyIn, NumPyType, dim1) ? convertArray1<T> : nullptr;
+}
+
+static inline bool primitiveArrayCheck2(PyObject *pyIn, int expectedNpType, int expectedDim1, int expectedDim2)
+{
+ if (!isPrimitiveArray<2>(pyIn, expectedNpType))
+ return false;
+ if (expectedDim2 >= 0) {
+ auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
+ const int dim1 = int(PyArray_DIMS(pya)[0]);
+ const int dim2 = int(PyArray_DIMS(pya)[1]);
+ if (dim1 != expectedDim1 || dim2 != expectedDim2) {
+ warning(PyExc_RuntimeWarning, 0, "A numpy array of size %dx%d was passed to a function that expects %dx%d.",
+ dim1, dim2, expectedDim1, expectedDim2);
+ return false;
+ }
+ }
+ return true;
+}
+
+template <class T, int NumPyType>
+static PythonToCppFunc checkArray2(PyObject *pyIn, int dim1, int dim2)
+{
+ return primitiveArrayCheck2(pyIn, NumPyType, dim1, dim2) ? convertArray2<T> : nullptr;
+}
+
+template <class T>
+static void setOrExtendArrayConverter(int dimension, IsArrayConvertibleToCppFunc toCppCheckFunc)
+{
+ // PYSIDE-2404/FIXME: When adding a C++ -> Python conversion, be sure
+ // to delay-initialize numpy in the converter (similar to the
+ // initialization in check() for the Python -> C++ conversion).
+ SbkArrayConverter *arrayConverter = ArrayTypeConverter<T>(dimension);
+ if (arrayConverter == unimplementedArrayConverter()) {
+ arrayConverter = createArrayConverter(toCppCheckFunc);
+ setArrayTypeConverter(ArrayTypeIndex<T>::index, dimension, arrayConverter);
+ } else {
+ arrayConverter->toCppConversions.push_back(toCppCheckFunc);
+ }
+}
+
+// Extend the converters for primitive type one-dimensional arrays by NumPy ones.
+template <class T, int NumPyType>
+static inline void extendArrayConverter1()
+{
+ setOrExtendArrayConverter<T>(1, checkArray1<T, NumPyType>);
+}
+
+// Extend the converters for primitive type one-dimensional arrays by NumPy ones.
+template <class T, int NumPyType>
+static inline void extendArrayConverter2()
+{
+ setOrExtendArrayConverter<T>(2, checkArray2<T, NumPyType>);
+}
+
+void initNumPyArrayConverters()
+{
+ // Extend the converters for primitive types by NumPy ones.
+ extendArrayConverter1<short, NPY_SHORT>();
+ extendArrayConverter2<short, NPY_SHORT>();
+ extendArrayConverter1<unsigned short, NPY_SHORT>();
+ extendArrayConverter2<unsigned short, NPY_SHORT>();
+ extendArrayConverter1<int, NPY_INT>();
+ extendArrayConverter2<int, NPY_INT>();
+ extendArrayConverter1<unsigned int, NPY_UINT>();
+ extendArrayConverter2<unsigned int, NPY_UINT>();
+ extendArrayConverter1<long long, NPY_LONGLONG>();
+ extendArrayConverter2<long long, NPY_LONGLONG>();
+ extendArrayConverter1<unsigned long long, NPY_ULONGLONG>();
+ if (sizeof(long) == 8) { // UNIX/LP64: ints typically come as long
+ extendArrayConverter1<long long, NPY_LONG>();
+ extendArrayConverter2<long long, NPY_LONG>();
+ extendArrayConverter1<unsigned long long, NPY_ULONG>();
+ extendArrayConverter2<unsigned long long, NPY_ULONG>();
+ } else if (sizeof(long) == sizeof(int)) {
+ extendArrayConverter1<int, NPY_LONG>();
+ extendArrayConverter1<unsigned, NPY_ULONG>();
+ extendArrayConverter2<int, NPY_LONG>();
+ extendArrayConverter2<unsigned, NPY_ULONG>();
+ }
+ extendArrayConverter1<float, NPY_FLOAT>();
+ extendArrayConverter2<float, NPY_FLOAT>();
+ extendArrayConverter1<double, NPY_DOUBLE>();
+ extendArrayConverter2<double, NPY_DOUBLE>();
+}
+
+} // namespace Shiboken::Conversions
diff --git a/sources/shiboken6/libshiboken/sbknumpycheck.h b/sources/shiboken6/libshiboken/sbknumpycheck.h
new file mode 100644
index 000000000..cfe65372c
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpycheck.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKNUMPYCHECK_H
+#define SBKNUMPYCHECK_H
+
+#include <sbkpython.h>
+#include <shibokenmacros.h>
+
+
+// This header provides a PyArray_Check() definition that can be used to avoid
+// having to include the numpy headers. When using numpy headers, make sure
+// to include this header after them to skip the definition. Also remember
+// that import_array() must then be called to initialize numpy.
+
+namespace Shiboken::Numpy
+{
+
+/// Check whether the object is a PyArrayObject
+/// \param pyIn object
+/// \return Whether it is a PyArrayObject
+LIBSHIBOKEN_API bool check(PyObject *pyIn);
+
+} //namespace Shiboken::Numpy
+
+#ifndef PyArray_Check
+# define PyArray_Check(op) Shiboken::Numpy::check(op)
+#endif
+
+#endif // SBKNUMPYCHECK_H
diff --git a/sources/shiboken6/libshiboken/sbknumpyview.cpp b/sources/shiboken6/libshiboken/sbknumpyview.cpp
new file mode 100644
index 000000000..bafbf8038
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpyview.cpp
@@ -0,0 +1,265 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// included by sbknumpy.cpp
+
+#include "helper.h"
+#include <iostream>
+#include <iomanip>
+#include <optional>
+
+#ifdef HAVE_NUMPY
+
+namespace Shiboken {
+namespace Numpy {
+
+static std::optional<View::Type> viewTypeFromNumPy(int npt)
+{
+ switch (npt) {
+ case NPY_SHORT:
+ return View::Int16;
+ case NPY_USHORT:
+ return View::Unsigned16;
+ case NPY_INT:
+ return View::Int;
+ case NPY_UINT:
+ return View::Unsigned;
+ case NPY_LONG:
+ if constexpr (sizeof(long) == sizeof(int))
+ return View::Int;
+ if constexpr (sizeof(long) == sizeof(int64_t))
+ return View::Int64;
+ break;
+ case NPY_ULONG:
+ if constexpr (sizeof(long) == sizeof(int))
+ return View::Unsigned;
+ if constexpr (sizeof(long) == sizeof(int64_t))
+ return View::Unsigned64;
+ break;
+ case NPY_LONGLONG:
+ if constexpr (sizeof(long long) == 8)
+ return View::Int64;
+ break;
+ case NPY_ULONGLONG:
+ if constexpr (sizeof(long long) == 8)
+ return View::Unsigned64;
+ break;
+ case NPY_FLOAT:
+ return View::Float;
+ case NPY_DOUBLE:
+ return View::Double;
+ default:
+ break;
+ }
+ return {};
+}
+
+View View::fromPyObject(PyObject *pyIn)
+{
+ if (pyIn == nullptr || PyArray_Check(pyIn) == 0)
+ return {};
+ auto *ar = reinterpret_cast<PyArrayObject *>(pyIn);
+ if ((PyArray_FLAGS(ar) & NPY_ARRAY_C_CONTIGUOUS) == 0)
+ return {};
+ const int ndim = PyArray_NDIM(ar);
+ if (ndim > 2)
+ return {};
+
+ const auto typeO = viewTypeFromNumPy(PyArray_TYPE(ar));
+ if (!typeO.has_value())
+ return {};
+
+ View result;
+ result.ndim = ndim;
+ result.type = typeO.value();
+ result.data = PyArray_DATA(ar);
+ result.dimensions[0] = PyArray_DIMS(ar)[0];
+ result.stride[0] = PyArray_STRIDES(ar)[0];
+ if (ndim > 1) {
+ result.dimensions[1] = PyArray_DIMS(ar)[1];
+ result.stride[1] = PyArray_STRIDES(ar)[1];
+ } else {
+ result.dimensions[1] = result.stride[1] = 0;
+ }
+ return result;
+}
+
+} // namespace Numpy
+
+template <class T>
+static void debugArray(std::ostream &str, const T *data, int n)
+{
+ static const int maxData = 10;
+ str << " = ";
+ auto *end = data + std::min(n, maxData);
+ for (auto *d = data; d != end; ++d) {
+ if (d != data)
+ str << ", ";
+ str << *d;
+ }
+ if (n > maxData)
+ str << "...";
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyArrayObject &a)
+{
+ str << "PyArrayObject(";
+ if (a.m_object == nullptr) {
+ str << '0';
+ } else if (PyArray_Check(a.m_object) != 0) {
+ auto *ar = reinterpret_cast<PyArrayObject *>(a.m_object);
+ const int ndim = PyArray_NDIM(ar);
+ const int type = PyArray_TYPE(ar);
+ const int flags = PyArray_FLAGS(ar);
+ str << "ndim=" << ndim << " [";
+ for (int d = 0; d < ndim; ++d) {
+ if (d)
+ str << ", ";
+ str << PyArray_DIMS(ar)[d];
+ }
+ str << "], type=";
+ switch (type) {
+ case NPY_SHORT:
+ str << "short";
+ break;
+ case NPY_USHORT:
+ str << "ushort";
+ break;
+ case NPY_INT:
+ str << "int32";
+ break;
+ case NPY_UINT:
+ str << "uint32";
+ break;
+ case NPY_LONG:
+ str << "long";
+ break;
+ case NPY_ULONG:
+ str << "ulong";
+ break;
+ case NPY_LONGLONG:
+ str << "long long";
+ break;
+ case NPY_ULONGLONG:
+ str << "ulong long";
+ break;
+ case NPY_FLOAT:
+ str << "float";
+ break;
+ case NPY_DOUBLE:
+ str << "double";
+ break;
+ default:
+ str << '(' << type << ')';
+ break;
+ }
+ str << ", flags=0x" << std::hex << flags << std::dec;
+ if ((flags & NPY_ARRAY_C_CONTIGUOUS) != 0)
+ str << " [C-contiguous]";
+ if ((flags & NPY_ARRAY_F_CONTIGUOUS) != 0)
+ str << " [Fortran-contiguous]";
+ if ((flags & NPY_ARRAY_ALIGNED) != 0)
+ str << " [aligned]";
+ if ((flags & NPY_ARRAY_OWNDATA) != 0)
+ str << " [owndata]";
+ if ((flags & NPY_ARRAY_WRITEABLE) != 0)
+ str << " [writeable]";
+
+ if (const int dim0 = PyArray_DIMS(ar)[0]) {
+ auto *data = PyArray_DATA(ar);
+ switch (type) {
+ case NPY_SHORT:
+ debugArray(str, reinterpret_cast<const short *>(data), dim0);
+ break;
+ case NPY_USHORT:
+ debugArray(str, reinterpret_cast<const unsigned short *>(data), dim0);
+ break;
+ case NPY_INT:
+ debugArray(str, reinterpret_cast<const int *>(data), dim0);
+ break;
+ case NPY_UINT:
+ debugArray(str, reinterpret_cast<const unsigned *>(data), dim0);
+ break;
+ case NPY_LONG:
+ debugArray(str, reinterpret_cast<const long *>(data), dim0);
+ break;
+ case NPY_ULONG:
+ debugArray(str, reinterpret_cast<const unsigned long*>(data), dim0);
+ break;
+ case NPY_LONGLONG:
+ debugArray(str, reinterpret_cast<const long long *>(data), dim0);
+ break;
+ case NPY_ULONGLONG:
+ debugArray(str, reinterpret_cast<const unsigned long long *>(data), dim0);
+ break;
+ case NPY_FLOAT:
+ debugArray(str, reinterpret_cast<const float *>(data), dim0);
+ break;
+ case NPY_DOUBLE:
+ debugArray(str, reinterpret_cast<const double *>(data), dim0);
+ break;
+ }
+ }
+ } else {
+ str << "Invalid";
+ }
+ str << ')';
+ return str;
+}
+
+} //namespace Shiboken
+
+#else // HAVE_NUMPY
+
+namespace Shiboken::Numpy
+{
+
+View View::fromPyObject(PyObject *)
+{
+ return {};
+}
+
+std::ostream &operator<<(std::ostream &str, const debugPyArrayObject &)
+{
+ str << "Unimplemented function " << __FUNCTION__ << ", (numpy was not found).";
+ return str;
+}
+
+} //namespace Shiboken::Numpy
+
+#endif // !HAVE_NUMPY
+
+namespace Shiboken::Numpy
+{
+
+bool View::sameLayout(const View &rhs) const
+{
+ return rhs && *this && ndim == rhs.ndim && type == rhs.type;
+}
+
+bool View::sameSize(const View &rhs) const
+{
+ return sameLayout(rhs)
+ && dimensions[0] == rhs.dimensions[0] && dimensions[1] == rhs.dimensions[1];
+}
+
+std::ostream &operator<<(std::ostream &str, const View &v)
+{
+ str << "Shiboken::Numpy::View(";
+ if (v) {
+ str << "type=" << v.type << ", ndim=" << v.ndim << " ["
+ << v.dimensions[0];
+ if (v.ndim > 1)
+ str << ", " << v.dimensions[1];
+ str << "], stride=[" << v.stride[0];
+ if (v.ndim > 1)
+ str << ", " << v.stride[1];
+ str << "], data=" << v.data;
+ } else {
+ str << "invalid";
+ }
+ str << ')';
+ return str;
+}
+
+} //namespace Shiboken::Numpy
diff --git a/sources/shiboken6/libshiboken/sbknumpyview.h b/sources/shiboken6/libshiboken/sbknumpyview.h
new file mode 100644
index 000000000..918913b78
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbknumpyview.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKNUMPYVIEW_H
+#define SBKNUMPYVIEW_H
+
+#include <sbkpython.h>
+#include <shibokenmacros.h>
+
+#include <iosfwd>
+
+namespace Shiboken::Numpy
+{
+
+/// Check whether the object is a PyArrayObject
+/// \param pyIn object
+/// \return Whether it is a PyArrayObject
+LIBSHIBOKEN_API bool check(PyObject *pyIn);
+
+/// A simple view of an up to 2 dimensional, C-contiguous array of a standard
+/// type. It can be passed to compilation units that do not include the
+/// numpy headers.
+struct LIBSHIBOKEN_API View
+{
+ enum Type { Int, Unsigned, Float, Double, Int16, Unsigned16, Int64, Unsigned64 };
+
+ static View fromPyObject(PyObject *pyIn);
+
+ operator bool() const { return ndim > 0; }
+
+ /// Return whether rhs is of the same type and dimensionality
+ bool sameLayout(const View &rhs) const;
+ /// Return whether rhs is of the same type dimensionality and size
+ bool sameSize(const View &rhs) const;
+
+ int ndim = 0;
+ Py_ssize_t dimensions[2];
+ Py_ssize_t stride[2];
+ void *data = nullptr;
+ Type type = Int;
+};
+
+LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &, const View &v);
+
+} //namespace Shiboken::Numpy
+
+#endif // SBKNUMPYVIEW_H
diff --git a/sources/shiboken6/libshiboken/sbkpython.h b/sources/shiboken6/libshiboken/sbkpython.h
new file mode 100644
index 000000000..e62fa13ae
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkpython.h
@@ -0,0 +1,75 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKPYTHON_H
+#define SBKPYTHON_H
+
+#include "sbkversion.h"
+
+// Qt's "slots" macro collides with the "slots" member variables
+// used in some Python structs. For compilers that support push_macro,
+// temporarily undefine it.
+#if defined(slots) && (defined(__GNUC__) || defined(_MSC_VER) || defined(__clang__))
+# pragma push_macro("slots")
+# undef slots
+/*
+ * Python 2 has function _Py_Mangle directly in Python.h .
+ * This creates wrong language binding unless we define 'extern "C"' here.
+ */
+extern "C" {
+/*
+ * Python 2 uses the "register" keyword, which is deprecated in C++ 11
+ * and forbidden in C++17.
+ */
+# if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-register"
+# endif
+
+# include <Python.h>
+
+# if defined(__clang__)
+# pragma clang diagnostic pop
+# endif
+}
+# include <structmember.h>
+// Now we have the usual variables from Python.h .
+# include "shibokenmacros.h"
+// "pep384impl.h" may nowhere be included but in this file.
+# include "pep384impl.h"
+# pragma pop_macro("slots")
+
+#else
+
+extern "C" {
+/*
+ * Python 2 uses the "register" keyword, which is deprecated in C++ 11
+ * and forbidden in C++17.
+ */
+# if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-register"
+# endif
+
+# include <Python.h>
+
+# if defined(__clang__)
+# pragma clang diagnostic pop
+# endif
+}
+# include <structmember.h>
+// Now we have the usual variables from Python.h .
+# include "shibokenmacros.h"
+// "pep384impl.h" may nowhere be included but in this file.
+# include "pep384impl.h"
+#endif
+
+// In Python 3, Py_TPFLAGS_DEFAULT contains Py_TPFLAGS_HAVE_VERSION_TAG,
+// which will trigger the attribute cache, which is not intended in Qt for Python.
+// Use a customized Py_TPFLAGS_DEFAULT by defining Py_TPFLAGS_HAVE_VERSION_TAG = 0.
+#undef Py_TPFLAGS_HAVE_VERSION_TAG
+#define Py_TPFLAGS_HAVE_VERSION_TAG (0)
+
+using SbkObjectType [[deprecated]] = PyTypeObject; // FIXME PYSIDE 7 remove
+
+#endif
diff --git a/sources/shiboken6/libshiboken/sbksmartpointer.cpp b/sources/shiboken6/libshiboken/sbksmartpointer.cpp
new file mode 100644
index 000000000..ee28f7db8
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbksmartpointer.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbksmartpointer.h"
+#include "sbkstring.h"
+#include "autodecref.h"
+
+#include <unordered_set>
+
+namespace Shiboken::SmartPointer
+{
+
+PyObject *repr(PyObject *pointer, PyObject *pointee)
+{
+ Shiboken::AutoDecRef pointerRepr(Shiboken::String::repr(pointer));
+ if (pointer == nullptr)
+ return pointerRepr.release();
+
+ Shiboken::AutoDecRef pointeeRepr(pointee != nullptr
+ ? PyObject_Repr(pointee)
+ : Shiboken::String::repr(pointee));
+
+ return PyUnicode_FromFormat("%U (%U)", pointerRepr.object(), pointeeRepr.object());
+}
+
+// __dir__ for a smart pointer. Add the __dir__ entries of the pointee to the list.
+PyObject *dir(PyObject *pointer, PyObject *pointee)
+{
+ if (pointer == nullptr)
+ return PyList_New(0);
+ // Get the pointer's dir entries. Note: PyObject_Dir() cannot be called on
+ // self, will crash. Work around by using the type dict keys.
+ AutoDecRef tpDict(PepType_GetDict(Py_TYPE(pointer)));
+ auto *result = PyMapping_Keys(tpDict);
+
+ if (pointee != nullptr && pointee != Py_None) {
+ // Add the entries of the pointee that do not exist in the pointer's list.
+ // Since Python internally caches strings; we can use a set of PyObject *.
+ std::unordered_set<PyObject *> knownStrings;
+ for (Py_ssize_t i = 0, size = PySequence_Size(result); i < size; ++i) {
+ Shiboken::AutoDecRef item(PySequence_GetItem(result, i));
+ knownStrings.insert(item.object());
+ }
+ const auto knownEnd = knownStrings.end();
+
+ Shiboken::AutoDecRef pointeeDir(PyObject_Dir(pointee));
+ for (Py_ssize_t i = 0, size = PySequence_Size(pointeeDir.object()); i < size; ++i) {
+ Shiboken::AutoDecRef item(PySequence_GetItem(pointeeDir, i));
+ if (knownStrings.find(item.object()) == knownEnd)
+ PyList_Append(result, item.object());
+ }
+ }
+
+ PyList_Sort(result);
+ return result;
+}
+
+} // namespace Shiboken::SmartPointer
diff --git a/sources/shiboken6/libshiboken/sbksmartpointer.h b/sources/shiboken6/libshiboken/sbksmartpointer.h
new file mode 100644
index 000000000..5e2022722
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbksmartpointer.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_SBKSMARTPOINTER_H
+#define SBK_SBKSMARTPOINTER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken::SmartPointer
+{
+
+LIBSHIBOKEN_API PyObject *repr(PyObject *pointer, PyObject *pointee);
+LIBSHIBOKEN_API PyObject *dir(PyObject *pointer, PyObject *pointee);
+
+} // namespace Shiboken::SmartPointer
+
+#endif // SBK_SBKSMARTPOINTER_H
diff --git a/sources/shiboken6/libshiboken/sbkstaticstrings.cpp b/sources/shiboken6/libshiboken/sbkstaticstrings.cpp
new file mode 100644
index 000000000..023de0ea4
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstaticstrings.cpp
@@ -0,0 +1,88 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "sbkstring.h"
+
+#define STATIC_STRING_IMPL(funcName, value) \
+PyObject *funcName() \
+{ \
+ static PyObject *const s = Shiboken::String::createStaticString(value); \
+ return s; \
+}
+
+namespace Shiboken
+{
+namespace PyName {
+// exported:
+STATIC_STRING_IMPL(dumps, "dumps")
+STATIC_STRING_IMPL(fget, "fget")
+STATIC_STRING_IMPL(fset, "fset")
+STATIC_STRING_IMPL(im_func, "im_func")
+STATIC_STRING_IMPL(im_self, "im_self")
+STATIC_STRING_IMPL(loads, "loads")
+STATIC_STRING_IMPL(multi, "multi")
+STATIC_STRING_IMPL(name, "name")
+STATIC_STRING_IMPL(orig_dict, "orig_dict")
+STATIC_STRING_IMPL(qApp, "qApp")
+STATIC_STRING_IMPL(result, "result")
+STATIC_STRING_IMPL(select_id, "select_id")
+STATIC_STRING_IMPL(value, "value")
+STATIC_STRING_IMPL(values, "values")
+STATIC_STRING_IMPL(qtStaticMetaObject, "staticMetaObject")
+
+// Internal:
+STATIC_STRING_IMPL(classmethod, "classmethod")
+STATIC_STRING_IMPL(co_name, "co_name")
+STATIC_STRING_IMPL(compile, "compile");
+STATIC_STRING_IMPL(f_code, "f_code")
+STATIC_STRING_IMPL(f_lineno, "f_lineno")
+STATIC_STRING_IMPL(function, "function")
+STATIC_STRING_IMPL(marshal, "marshal")
+STATIC_STRING_IMPL(method, "method")
+STATIC_STRING_IMPL(mro, "mro")
+STATIC_STRING_IMPL(overload, "overload")
+STATIC_STRING_IMPL(staticmethod, "staticmethod")
+} // namespace PyName
+
+namespace PyMagicName {
+// exported:
+STATIC_STRING_IMPL(class_, "__class__")
+STATIC_STRING_IMPL(dict, "__dict__")
+STATIC_STRING_IMPL(doc, "__doc__")
+STATIC_STRING_IMPL(ecf, "__ecf__")
+STATIC_STRING_IMPL(file, "__file__")
+STATIC_STRING_IMPL(get, "__get__")
+STATIC_STRING_IMPL(members, "__members__")
+STATIC_STRING_IMPL(module, "__module__")
+STATIC_STRING_IMPL(name, "__name__")
+STATIC_STRING_IMPL(property_methods, "__property_methods__")
+STATIC_STRING_IMPL(qualname, "__qualname__")
+STATIC_STRING_IMPL(self, "__self__")
+STATIC_STRING_IMPL(select_i, "__self__")
+STATIC_STRING_IMPL(code, "__code__")
+STATIC_STRING_IMPL(rlshift, "__rlshift__")
+STATIC_STRING_IMPL(rrshift, "__rrshift__")
+
+// Internal:
+STATIC_STRING_IMPL(base, "__base__")
+STATIC_STRING_IMPL(bases, "__bases__")
+STATIC_STRING_IMPL(builtins, "__builtins__")
+STATIC_STRING_IMPL(dictoffset, "__dictoffset__")
+STATIC_STRING_IMPL(func, "__func__")
+STATIC_STRING_IMPL(func_kind, "__func_kind__")
+STATIC_STRING_IMPL(iter, "__iter__")
+STATIC_STRING_IMPL(mro, "__mro__")
+STATIC_STRING_IMPL(new_, "__new__")
+STATIC_STRING_IMPL(objclass, "__objclass__")
+STATIC_STRING_IMPL(weakrefoffset, "__weakrefoffset__")
+STATIC_STRING_IMPL(opaque_container, "__opaque_container__")
+} // namespace PyMagicName
+
+namespace Messages
+{
+STATIC_STRING_IMPL(unknownException, "An unknown exception was caught")
+}
+
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/sbkstaticstrings.h b/sources/shiboken6/libshiboken/sbkstaticstrings.h
new file mode 100644
index 000000000..017790ee3
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstaticstrings.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKSTATICSTRINGS_H
+#define SBKSTATICSTRINGS_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+// Some often-used strings
+namespace PyName
+{
+LIBSHIBOKEN_API PyObject *co_name();
+LIBSHIBOKEN_API PyObject *dumps();
+LIBSHIBOKEN_API PyObject *fget();
+LIBSHIBOKEN_API PyObject *fset();
+LIBSHIBOKEN_API PyObject *f_code();
+LIBSHIBOKEN_API PyObject *f_lineno();
+LIBSHIBOKEN_API PyObject *im_func();
+LIBSHIBOKEN_API PyObject *im_self();
+LIBSHIBOKEN_API PyObject *loads();
+LIBSHIBOKEN_API PyObject *multi();
+LIBSHIBOKEN_API PyObject *name();
+LIBSHIBOKEN_API PyObject *orig_dict();
+LIBSHIBOKEN_API PyObject *result();
+LIBSHIBOKEN_API PyObject *select_id();
+LIBSHIBOKEN_API PyObject *value();
+LIBSHIBOKEN_API PyObject *values();
+LIBSHIBOKEN_API PyObject *qtStaticMetaObject();
+} // namespace PyName
+
+namespace PyMagicName
+{
+LIBSHIBOKEN_API PyObject *class_();
+LIBSHIBOKEN_API PyObject *dict();
+LIBSHIBOKEN_API PyObject *doc();
+LIBSHIBOKEN_API PyObject *ecf();
+LIBSHIBOKEN_API PyObject *file();
+LIBSHIBOKEN_API PyObject *func();
+LIBSHIBOKEN_API PyObject *get();
+LIBSHIBOKEN_API PyObject *members();
+LIBSHIBOKEN_API PyObject *module();
+LIBSHIBOKEN_API PyObject *name();
+LIBSHIBOKEN_API PyObject *property_methods();
+LIBSHIBOKEN_API PyObject *qualname();
+LIBSHIBOKEN_API PyObject *self();
+LIBSHIBOKEN_API PyObject *opaque_container();
+LIBSHIBOKEN_API PyObject *code();
+LIBSHIBOKEN_API PyObject *rlshift();
+LIBSHIBOKEN_API PyObject *rrshift();
+} // namespace PyMagicName
+
+namespace Messages
+{
+LIBSHIBOKEN_API PyObject *unknownException();
+} // Messages
+} // namespace Shiboken
+
+#endif // SBKSTATICSTRINGS_H
diff --git a/sources/shiboken6/libshiboken/sbkstaticstrings_p.h b/sources/shiboken6/libshiboken/sbkstaticstrings_p.h
new file mode 100644
index 000000000..2a337bf7e
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstaticstrings_p.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+namespace PyName
+{
+PyObject *classmethod();
+PyObject *compile();
+PyObject *function();
+PyObject *marshal();
+PyObject *method();
+PyObject *mro();
+PyObject *overload();
+PyObject *qApp();
+PyObject *staticmethod();
+} // namespace PyName
+namespace PyMagicName
+{
+PyObject *base();
+PyObject *bases();
+PyObject *builtins();
+PyObject *code();
+PyObject *dictoffset();
+PyObject *func_kind();
+PyObject *iter();
+PyObject *module();
+PyObject *mro();
+PyObject *new_();
+PyObject *objclass();
+PyObject *signature();
+PyObject *weakrefoffset();
+} // namespace PyMagicName
+} // namespace Shiboken
diff --git a/sources/shiboken6/libshiboken/sbkstring.cpp b/sources/shiboken6/libshiboken/sbkstring.cpp
new file mode 100644
index 000000000..b5e87ca5a
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstring.cpp
@@ -0,0 +1,254 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// 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"
+
+namespace Shiboken::String
+{
+
+// PYSIDE-795: Redirecting PySequence to Iterable
+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{};
+ auto osmodule = PyImport_ImportModule("os");
+ if (osmodule == nullptr
+ || (PathLike = PyObject_GetAttrString(osmodule, "PathLike")) == nullptr) {
+ PyErr_Print();
+ Py_FatalError("cannot import os.PathLike");
+ }
+ return PathLike;
+}
+
+// PYSIDE-1499: Migrate to pathlib.Path and support __fspath__ in PySide
+bool checkPath(PyObject *path)
+{
+ // Let normal strings through, unchanged.
+ if (PyUnicode_Check(path) || PyBytes_Check(path))
+ return true;
+ // Without the Limited API, we could look up an `__fspath__` class attribute.
+ // But we use `isinstance(os.PathLike)`, instead.
+ static PyObject *PathLike = initPathLike();
+ return PyObject_IsInstance(path, PathLike);
+}
+
+bool checkType(PyTypeObject *type)
+{
+ return type == &PyUnicode_Type;
+}
+
+bool check(PyObject *obj)
+{
+ return obj == Py_None || PyUnicode_Check(obj);
+}
+
+bool checkChar(PyObject *pyobj)
+{
+ return check(pyobj) && (len(pyobj) == 1);
+}
+
+bool isConvertible(PyObject *obj)
+{
+ return check(obj);
+}
+
+PyObject *fromCString(const char *value)
+{
+ return PyUnicode_FromString(value);
+}
+
+PyObject *fromCString(const char *value, int len)
+{
+ return PyUnicode_FromStringAndSize(value, len);
+}
+
+const char *toCString(PyObject *str)
+{
+ if (str == Py_None)
+ return nullptr;
+ if (PyUnicode_Check(str))
+ return _PepUnicode_AsString(str);
+ if (PyBytes_Check(str))
+ return PyBytes_AS_STRING(str);
+ return nullptr;
+}
+
+const char *toCString(PyObject *str, Py_ssize_t *len)
+{
+ if (str == Py_None) {
+ *len = 0;
+ return nullptr;
+ }
+ if (PyUnicode_Check(str)) {
+ // We need to encode the unicode string into utf8 to know the size of returned char *.
+ Shiboken::AutoDecRef uniStr(PyUnicode_AsUTF8String(str));
+ *len = PyBytes_GET_SIZE(uniStr.object());
+ // Return unicode from str instead of uniStr, because the lifetime of the returned pointer
+ // depends on the lifetime of str.
+ return _PepUnicode_AsString(str);
+ }
+ if (PyBytes_Check(str)) {
+ *len = PyBytes_GET_SIZE(str);
+ return PyBytes_AS_STRING(str);
+ }
+ return nullptr;
+}
+
+bool concat(PyObject **val1, PyObject *val2)
+{
+ if (PyUnicode_Check(*val1) && PyUnicode_Check(val2)) {
+ PyObject *result = PyUnicode_Concat(*val1, val2);
+ Py_DECREF(*val1);
+ *val1 = result;
+ return true;
+ }
+
+ if (PyBytes_Check(*val1) && PyBytes_Check(val2)) {
+ PyBytes_Concat(val1, val2);
+ return true;
+ }
+
+ return false;
+}
+
+PyObject *fromFormat(const char *format, ...)
+{
+ va_list argp;
+ va_start(argp, format);
+ PyObject *result = nullptr;
+ result = PyUnicode_FromFormatV(format, argp);
+ va_end(argp);
+ return result;
+}
+
+PyObject *fromStringAndSize(const char *str, Py_ssize_t size)
+{
+ return PyUnicode_FromStringAndSize(str, size);
+}
+
+int compare(PyObject *val1, const char *val2)
+{
+ if (PyUnicode_Check(val1))
+ return PyUnicode_CompareWithASCIIString(val1, val2);
+ return 0;
+
+}
+
+Py_ssize_t len(PyObject *str)
+{
+ if (str == Py_None)
+ return 0;
+
+ if (PyUnicode_Check(str))
+ return PepUnicode_GetLength(str);
+
+ if (PyBytes_Check(str))
+ return PyBytes_GET_SIZE(str);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Implementation of efficient Python strings
+// ------------------------------------------
+//
+// Instead of repetitively executing
+//
+// PyObject *attr = PyObject_GetAttrString(obj, "__name__");
+//
+// a helper of the form
+//
+// PyObject *name()
+// {
+// static PyObject *const s = Shiboken::String::createStaticString("__name__");
+// return result;
+// }
+//
+// can now be implemented, which registers the string into a static set avoiding
+// repetitive string creation. The resulting code looks like:
+//
+// PyObject *attr = PyObject_GetAttr(obj, name());
+//
+
+PyObject *createStaticString(const char *str)
+{
+ return PyUnicode_InternFromString(str);
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// PYSIDE-1019: Helper function for snake_case vs. camelCase names
+// ---------------------------------------------------------------
+//
+// When renaming dict entries, `BindingManager::getOverride` must
+// use adapted names.
+//
+// This might become more complex when we need to register
+// exceptions from this rule.
+//
+
+PyObject *getSnakeCaseName(const char *name, bool lower)
+{
+ /*
+ * Convert `camelCase` to `snake_case`.
+ * Gives up when there are two consecutive upper chars.
+ *
+ * Also functions beginning with `gl` followed by upper case stay
+ * unchanged since that are the special OpenGL functions.
+ */
+ if (!lower
+ || strlen(name) < 3
+ || (name[0] == 'g' && name[1] == 'l' && isupper(name[2])))
+ return createStaticString(name);
+
+ char new_name[200 + 1] = {};
+ const char *p = name;
+ char *q = new_name;
+ for (; *p && q - new_name < 200; ++p, ++q) {
+ if (isupper(*p)) {
+ if (p != name && isupper(*(p - 1)))
+ return createStaticString(name);
+ *q = '_';
+ ++q;
+ *q = tolower(*p);
+ }
+ else {
+ *q = *p;
+ }
+ }
+ return createStaticString(new_name);
+}
+
+PyObject *getSnakeCaseName(PyObject *name, bool lower)
+{
+ // This is all static strings, not refcounted.
+ if (lower)
+ return getSnakeCaseName(toCString(name), lower);
+ return name;
+}
+
+// Return a generic representation of a PyObject as does PyObject_Repr().
+// Note: PyObject_Repr() may not be called on self from __repr__() as this
+// causes a recursion.
+PyObject *repr(PyObject *o)
+{
+ if (o == nullptr)
+ return PyUnicode_FromString("<NULL>");
+ if (o == Py_None)
+ return PyUnicode_FromString("None");
+ return PyUnicode_FromFormat("<%s object at %p>", Py_TYPE(o)->tp_name, o);
+}
+
+} // namespace Shiboken::String
diff --git a/sources/shiboken6/libshiboken/sbkstring.h b/sources/shiboken6/libshiboken/sbkstring.h
new file mode 100644
index 000000000..ebc5428c7
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkstring.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKSTRING_H
+#define SBKSTRING_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+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);
+ LIBSHIBOKEN_API bool isConvertible(PyObject *obj);
+ LIBSHIBOKEN_API PyObject *fromCString(const char *value);
+ LIBSHIBOKEN_API PyObject *fromCString(const char *value, int len);
+ LIBSHIBOKEN_API const char *toCString(PyObject *str);
+ LIBSHIBOKEN_API const char *toCString(PyObject *str, Py_ssize_t *len);
+ LIBSHIBOKEN_API bool concat(PyObject **val1, PyObject *val2);
+ LIBSHIBOKEN_API PyObject *fromFormat(const char *format, ...);
+ LIBSHIBOKEN_API PyObject *fromStringAndSize(const char *str, Py_ssize_t size);
+ LIBSHIBOKEN_API int compare(PyObject *val1, const char *val2);
+ LIBSHIBOKEN_API Py_ssize_t len(PyObject *str);
+ LIBSHIBOKEN_API PyObject *createStaticString(const char *str);
+ LIBSHIBOKEN_API PyObject *getSnakeCaseName(const char *name, bool lower);
+ LIBSHIBOKEN_API PyObject *getSnakeCaseName(PyObject *name, bool lower);
+ LIBSHIBOKEN_API PyObject *repr(PyObject *o);
+
+} // namespace String
+} // namespace Shiboken
+
+
+#endif
+
+
diff --git a/sources/shiboken6/libshiboken/sbktypefactory.cpp b/sources/shiboken6/libshiboken/sbktypefactory.cpp
new file mode 100644
index 000000000..079548eed
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbktypefactory.cpp
@@ -0,0 +1,407 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "sbktypefactory.h"
+#include "shiboken.h"
+
+extern "C"
+{
+
+using Shiboken::AutoDecRef;
+
+PyTypeObject *SbkType_FromSpec(PyType_Spec *spec)
+{
+ return SbkType_FromSpec_BMDWB(spec, nullptr, nullptr, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpecWithMeta(PyType_Spec *spec, PyTypeObject *meta)
+{
+ return SbkType_FromSpec_BMDWB(spec, nullptr, meta, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
+{
+ return SbkType_FromSpec_BMDWB(spec, bases, nullptr, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpecBasesMeta(PyType_Spec *spec, PyObject *bases, PyTypeObject *meta)
+{
+ return SbkType_FromSpec_BMDWB(spec, bases, meta, 0, 0, nullptr);
+}
+
+#ifdef PYPY_VERSION
+
+static PyObject *_PyType_FromSpecWithBases(PyType_Spec *, PyObject *);
+
+#else
+
+#define _PyType_FromSpecWithBases PyType_FromSpecWithBases
+
+#endif // PYPY_VERSION
+
+// PYSIDE-2230: Not so temporary fix for Python 3.12.
+// A tp_new is no longer allowed in a meta class.
+// Hopefully, the Python devs will supply the missing support.
+// It turned out that they will not fix that, as expected.
+// Note: Python 3.12 is the first version that grabs the metaclass from base classes.
+static PyObject *_PyType_FromSpecWithBasesHack(PyType_Spec *spec,
+ PyObject *bases,
+ PyTypeObject *meta)
+{
+ PyTypeObject *keepMeta{};
+ newfunc keepNew{};
+ AutoDecRef basesPatch{};
+
+ if (bases) {
+ if (bases == Py_None) {
+ // PYSIDE-2230: This is the SbkObject entry which has no base to provide
+ // the metaclass. We patch it in by modifying `object`s class.
+ assert(meta);
+ auto *base = reinterpret_cast<PyObject *>(&PyBaseObject_Type);
+ base->ob_type = meta;
+ basesPatch.reset(Py_BuildValue("(O)", &PyBaseObject_Type));
+ bases = basesPatch.object();
+ }
+
+ Py_ssize_t n = PyTuple_GET_SIZE(bases);
+ for (auto idx = 0; idx < n; ++idx) {
+ PyTypeObject *base = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(bases, idx));
+ PyTypeObject *meta = Py_TYPE(base);
+ if (meta->tp_new != PyType_Type.tp_new) {
+ // make sure there is no second meta class
+ assert(keepMeta == nullptr);
+ keepMeta = meta;
+ keepNew = meta->tp_new;
+ meta->tp_new = PyType_Type.tp_new;
+ }
+ }
+ }
+
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+ auto *ret = PyType_FromMetaclass(meta, nullptr /*module*/, spec, bases);
+#else
+ auto *ret = _PyType_FromSpecWithBases(spec, bases);
+#endif
+
+ if (keepMeta)
+ keepMeta->tp_new = keepNew;
+ if (basesPatch.object()) {
+ // undo the metaclass patch.
+ auto *base = PyTuple_GET_ITEM(basesPatch.object(), 0);
+ base->ob_type = &PyType_Type;
+ }
+ return ret;
+}
+
+PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
+ PyObject *bases,
+ PyTypeObject *meta,
+ int dictoffset,
+ int weaklistoffset,
+ PyBufferProcs *bufferprocs)
+{
+ // PYSIDE-1286: Generate correct __module__ and __qualname__
+ // The name field can now be extended by an "n:" prefix which is
+ // the number of modules in the name. The default is 1.
+ //
+ // Example:
+ // "2:mainmod.submod.mainclass.subclass"
+ // results in
+ // __module__ : "mainmod.submod"
+ // __qualname__ : "mainclass.subclass"
+ // __name__ : "subclass"
+
+ PyType_Spec new_spec = *spec;
+ const char *colon = strchr(spec->name, ':');
+ assert(colon);
+ int package_level = atoi(spec->name);
+ const char *mod = new_spec.name = colon + 1;
+
+ PyObject *obType = _PyType_FromSpecWithBasesHack(&new_spec, bases, meta);
+ if (obType == nullptr)
+ return nullptr;
+
+ const char *qual = mod;
+ for (int idx = package_level; idx > 0; --idx) {
+ const char *dot = strchr(qual, '.');
+ if (!dot)
+ break;
+ qual = dot + 1;
+ }
+ int mlen = qual - mod - 1;
+ AutoDecRef module(Shiboken::String::fromCString(mod, mlen));
+ AutoDecRef qualname(Shiboken::String::fromCString(qual));
+
+ auto *type = reinterpret_cast<PyTypeObject *>(obType);
+
+ if (meta) {
+ PyTypeObject *hold = Py_TYPE(type);
+ obType->ob_type = meta;
+ Py_INCREF(Py_TYPE(type));
+ if (hold->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ Py_DECREF(hold);
+ }
+
+ if (dictoffset)
+ type->tp_dictoffset = dictoffset;
+ if (weaklistoffset)
+ type->tp_weaklistoffset = weaklistoffset;
+ if (bufferprocs)
+ PepType_AS_BUFFER(type) = bufferprocs;
+
+#ifdef PYPY_VERSION
+ // PYSIDE-535: Careful: Using PyObject_SetAttr would have the side-effect of calling
+ // PyType_Ready too early. (at least in PyPy, which caused pretty long debugging.)
+ auto *ht = reinterpret_cast<PyHeapTypeObject *>(type);
+ ht->ht_qualname = qualname;
+ AutoDecRef tpDict(PepType_GetDict(type));
+ if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::qualname(), qualname))
+ return nullptr;
+ if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::module(), module))
+ return nullptr;
+ PyType_Ready(type);
+#else
+ if (PyObject_SetAttr(obType, Shiboken::PyMagicName::module(), module) < 0)
+ return nullptr;
+ if (PyObject_SetAttr(obType, Shiboken::PyMagicName::qualname(), qualname) < 0)
+ return nullptr;
+ PyType_Modified(type);
+#endif
+ return type;
+}
+
+#ifdef PYPY_VERSION
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Reimplementation of `PyType_FromSpecWithBases`
+//
+// This is almost the original code from Python 3.7 with a few changes.
+// Especially the call to `PyType_Ready` is deferred until the needed
+// post-actions are carried out in `SbkType_FromSpec_BMDWBD`.
+//
+// FIXME remove ASAP.
+// Version is not clear, yet. Current version == 7.3.6
+//
+
+static const short slotoffsets[] = {
+ -1, /* invalid slot */
+/* Generated by typeslots.py */
+0,
+0,
+offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript),
+offsetof(PyHeapTypeObject, as_mapping.mp_length),
+offsetof(PyHeapTypeObject, as_mapping.mp_subscript),
+offsetof(PyHeapTypeObject, as_number.nb_absolute),
+offsetof(PyHeapTypeObject, as_number.nb_add),
+offsetof(PyHeapTypeObject, as_number.nb_and),
+offsetof(PyHeapTypeObject, as_number.nb_bool),
+offsetof(PyHeapTypeObject, as_number.nb_divmod),
+offsetof(PyHeapTypeObject, as_number.nb_float),
+offsetof(PyHeapTypeObject, as_number.nb_floor_divide),
+offsetof(PyHeapTypeObject, as_number.nb_index),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_add),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_and),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_floor_divide),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_lshift),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_multiply),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_or),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_power),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_remainder),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_rshift),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_subtract),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_true_divide),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_xor),
+offsetof(PyHeapTypeObject, as_number.nb_int),
+offsetof(PyHeapTypeObject, as_number.nb_invert),
+offsetof(PyHeapTypeObject, as_number.nb_lshift),
+offsetof(PyHeapTypeObject, as_number.nb_multiply),
+offsetof(PyHeapTypeObject, as_number.nb_negative),
+offsetof(PyHeapTypeObject, as_number.nb_or),
+offsetof(PyHeapTypeObject, as_number.nb_positive),
+offsetof(PyHeapTypeObject, as_number.nb_power),
+offsetof(PyHeapTypeObject, as_number.nb_remainder),
+offsetof(PyHeapTypeObject, as_number.nb_rshift),
+offsetof(PyHeapTypeObject, as_number.nb_subtract),
+offsetof(PyHeapTypeObject, as_number.nb_true_divide),
+offsetof(PyHeapTypeObject, as_number.nb_xor),
+offsetof(PyHeapTypeObject, as_sequence.sq_ass_item),
+offsetof(PyHeapTypeObject, as_sequence.sq_concat),
+offsetof(PyHeapTypeObject, as_sequence.sq_contains),
+offsetof(PyHeapTypeObject, as_sequence.sq_inplace_concat),
+offsetof(PyHeapTypeObject, as_sequence.sq_inplace_repeat),
+offsetof(PyHeapTypeObject, as_sequence.sq_item),
+offsetof(PyHeapTypeObject, as_sequence.sq_length),
+offsetof(PyHeapTypeObject, as_sequence.sq_repeat),
+offsetof(PyHeapTypeObject, ht_type.tp_alloc),
+offsetof(PyHeapTypeObject, ht_type.tp_base),
+offsetof(PyHeapTypeObject, ht_type.tp_bases),
+offsetof(PyHeapTypeObject, ht_type.tp_call),
+offsetof(PyHeapTypeObject, ht_type.tp_clear),
+offsetof(PyHeapTypeObject, ht_type.tp_dealloc),
+offsetof(PyHeapTypeObject, ht_type.tp_del),
+offsetof(PyHeapTypeObject, ht_type.tp_descr_get),
+offsetof(PyHeapTypeObject, ht_type.tp_descr_set),
+offsetof(PyHeapTypeObject, ht_type.tp_doc),
+offsetof(PyHeapTypeObject, ht_type.tp_getattr),
+offsetof(PyHeapTypeObject, ht_type.tp_getattro),
+offsetof(PyHeapTypeObject, ht_type.tp_hash),
+offsetof(PyHeapTypeObject, ht_type.tp_init),
+offsetof(PyHeapTypeObject, ht_type.tp_is_gc),
+offsetof(PyHeapTypeObject, ht_type.tp_iter),
+offsetof(PyHeapTypeObject, ht_type.tp_iternext),
+offsetof(PyHeapTypeObject, ht_type.tp_methods),
+offsetof(PyHeapTypeObject, ht_type.tp_new),
+offsetof(PyHeapTypeObject, ht_type.tp_repr),
+offsetof(PyHeapTypeObject, ht_type.tp_richcompare),
+offsetof(PyHeapTypeObject, ht_type.tp_setattr),
+offsetof(PyHeapTypeObject, ht_type.tp_setattro),
+offsetof(PyHeapTypeObject, ht_type.tp_str),
+offsetof(PyHeapTypeObject, ht_type.tp_traverse),
+offsetof(PyHeapTypeObject, ht_type.tp_members),
+offsetof(PyHeapTypeObject, ht_type.tp_getset),
+offsetof(PyHeapTypeObject, ht_type.tp_free),
+offsetof(PyHeapTypeObject, as_number.nb_matrix_multiply),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_matrix_multiply),
+offsetof(PyHeapTypeObject, as_async.am_await),
+offsetof(PyHeapTypeObject, as_async.am_aiter),
+offsetof(PyHeapTypeObject, as_async.am_anext),
+offsetof(PyHeapTypeObject, ht_type.tp_finalize),
+};
+
+static PyTypeObject *
+best_base(PyObject *bases)
+{
+ // We always have only one base
+ return reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(bases, 0));
+}
+
+static PyObject *
+_PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
+{
+ PyHeapTypeObject *res = reinterpret_cast<PyHeapTypeObject *>(
+ PyType_GenericAlloc(&PyType_Type, 0));
+ PyTypeObject *type, *base;
+ PyObject *modname;
+ char *s;
+ char *res_start = reinterpret_cast<char *>(res);
+ PyType_Slot *slot;
+
+ if (res == nullptr)
+ return nullptr;
+
+ if (spec->name == nullptr) {
+ PyErr_SetString(PyExc_SystemError,
+ "Type spec does not define the name field.");
+ goto fail;
+ }
+
+ /* Set the type name and qualname */
+ s = strrchr(const_cast<char *>(spec->name), '.');
+ if (s == nullptr)
+ s = (char*)spec->name;
+ else
+ s++;
+
+ type = &res->ht_type;
+ /* The flags must be initialized early, before the GC traverses us */
+ type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE;
+ res->ht_name = PyUnicode_FromString(s);
+ if (!res->ht_name)
+ goto fail;
+ res->ht_qualname = res->ht_name;
+ Py_INCREF(res->ht_qualname);
+ type->tp_name = spec->name;
+
+ /* Adjust for empty tuple bases */
+ if (!bases) {
+ base = &PyBaseObject_Type;
+ /* See whether Py_tp_base(s) was specified */
+ for (slot = spec->slots; slot->slot; slot++) {
+ if (slot->slot == Py_tp_base)
+ base = reinterpret_cast<PyTypeObject *>(slot->pfunc);
+ else if (slot->slot == Py_tp_bases) {
+ bases = reinterpret_cast<PyObject *>(slot->pfunc);
+ Py_INCREF(bases);
+ }
+ }
+ if (!bases)
+ bases = PyTuple_Pack(1, base);
+ if (!bases)
+ goto fail;
+ }
+ else
+ Py_INCREF(bases);
+
+ /* Calculate best base, and check that all bases are type objects */
+ base = best_base(bases);
+ if (base == nullptr) {
+ goto fail;
+ }
+
+ /* Initialize essential fields */
+ type->tp_as_async = &res->as_async;
+ type->tp_as_number = &res->as_number;
+ type->tp_as_sequence = &res->as_sequence;
+ type->tp_as_mapping = &res->as_mapping;
+ type->tp_as_buffer = &res->as_buffer;
+ /* Set tp_base and tp_bases */
+ type->tp_bases = bases;
+ bases = nullptr;
+ Py_INCREF(base);
+ type->tp_base = base;
+
+ type->tp_basicsize = spec->basicsize;
+ type->tp_itemsize = spec->itemsize;
+
+ for (slot = spec->slots; slot->slot; slot++) {
+ if (slot->slot == Py_tp_base || slot->slot == Py_tp_bases)
+ /* Processed above */
+ continue;
+ *reinterpret_cast<void **>(res_start + slotoffsets[slot->slot]) = slot->pfunc;
+
+ /* need to make a copy of the docstring slot, which usually
+ points to a static string literal */
+ if (slot->slot == Py_tp_doc) {
+ const char *old_doc = reinterpret_cast<char *>(slot->pfunc);
+ //_PyType_DocWithoutSignature(type->tp_name, slot->pfunc);
+ size_t len = strlen(old_doc)+1;
+ char *tp_doc = reinterpret_cast<char *>(PyObject_MALLOC(len));
+ if (tp_doc == nullptr) {
+ type->tp_doc = nullptr;
+ PyErr_NoMemory();
+ goto fail;
+ }
+ memcpy(tp_doc, old_doc, len);
+ type->tp_doc = tp_doc;
+ }
+ }
+ if (type->tp_dealloc == nullptr) {
+ /* It's a heap type, so needs the heap types' dealloc.
+ subtype_dealloc will call the base type's tp_dealloc, if
+ necessary. */
+ type->tp_dealloc = _PyPy_subtype_dealloc;
+ }
+
+ /// Here is the only change needed: Do not finalize type creation.
+ // if (PyType_Ready(type) < 0)
+ // goto fail;
+ PepType_SetDict(type, PyDict_New());
+ /// This is not found in PyPy:
+ // if (type->tp_dictoffset) {
+ // res->ht_cached_keys = _PyDict_NewKeysForClass();
+ // }
+
+ /* Set type.__module__ */
+ /// Removed __module__ handling, already implemented.
+
+ return (PyObject*)res;
+
+ fail:
+ Py_DECREF(res);
+ return nullptr;
+}
+
+#endif // PYPY_VERSION
+
+} //extern "C"
diff --git a/sources/shiboken6/libshiboken/sbktypefactory.h b/sources/shiboken6/libshiboken/sbktypefactory.h
new file mode 100644
index 000000000..81cb32d41
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbktypefactory.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKTYPEFACTORY_H
+#define SBKTYPEFACTORY_H
+
+#include "sbkpython.h"
+
+extern "C"
+{
+
+// PYSIDE-535: Encapsulation of PyType_FromSpec special-cased for PyPy
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpec(PyType_Spec *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecWithMeta(PyType_Spec *, PyTypeObject *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecWithBases(PyType_Spec *, PyObject *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecBasesMeta(PyType_Spec *, PyObject *, PyTypeObject *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
+ PyObject *bases,
+ PyTypeObject *meta,
+ int dictoffset,
+ int weaklistoffset,
+ PyBufferProcs *bufferprocs);
+
+} //extern "C"
+
+#endif // SBKTYPEFACTORY_H
diff --git a/sources/shiboken6/libshiboken/sbkversion.h.in b/sources/shiboken6/libshiboken/sbkversion.h.in
new file mode 100644
index 000000000..5c0b38fdb
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkversion.h.in
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKVERSION_H
+#define SBKVERSION_H
+
+#define SHIBOKEN_VERSION "@shiboken_MAJOR_VERSION@.@shiboken_MINOR_VERSION@.@shiboken_MICRO_VERSION@"
+#define SHIBOKEN_MAJOR_VERSION @shiboken_MAJOR_VERSION@
+#define SHIBOKEN_MINOR_VERSION @shiboken_MINOR_VERSION@
+#define SHIBOKEN_MICRO_VERSION @shiboken_MICRO_VERSION@
+#define SHIBOKEN_RELEASE_LEVEL "final"
+#define SHIBOKEN_SERIAL 0
+#define PYTHON_VERSION_MAJOR @Python_VERSION_MAJOR@
+#define PYTHON_VERSION_MINOR @Python_VERSION_MINOR@
+#define PYTHON_VERSION_PATCH @Python_VERSION_PATCH@
+
+#endif
diff --git a/sources/shiboken6/libshiboken/sbkwindows.h b/sources/shiboken6/libshiboken/sbkwindows.h
new file mode 100644
index 000000000..9e753fa5e
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkwindows.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBKWINDOWS_H
+#define SBKWINDOWS_H
+
+#ifdef _WIN32
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+#endif
+
+#endif // SBKWINDOWS_H
diff --git a/sources/shiboken6/libshiboken/shiboken.h b/sources/shiboken6/libshiboken/shiboken.h
new file mode 100644
index 000000000..fcf777ae0
--- /dev/null
+++ b/sources/shiboken6/libshiboken/shiboken.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SHIBOKEN_H
+#define SHIBOKEN_H
+
+#include "sbkpython.h"
+#include "autodecref.h"
+#include "basewrapper.h"
+#include "bindingmanager.h"
+#include "gilstate.h"
+#include "threadstatesaver.h"
+#include "helper.h"
+#include "pyobjectholder.h"
+#include "sbkarrayconverter.h"
+#include "sbkconverter.h"
+#include "sbkenum.h"
+#include "sbkerrors.h"
+#include "sbkmodule.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "shibokenmacros.h"
+#include "shibokenbuffer.h"
+#include "signature.h"
+
+#endif // SHIBOKEN_H
+
diff --git a/sources/shiboken6/libshiboken/shibokenbuffer.cpp b/sources/shiboken6/libshiboken/shibokenbuffer.cpp
new file mode 100644
index 000000000..d04613895
--- /dev/null
+++ b/sources/shiboken6/libshiboken/shibokenbuffer.cpp
@@ -0,0 +1,70 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "shibokenbuffer.h"
+#include <cstdlib>
+#include <cstring>
+
+bool Shiboken::Buffer::checkType(PyObject *pyObj)
+{
+ return PyObject_CheckBuffer(pyObj) != 0;
+}
+
+void *Shiboken::Buffer::getPointer(PyObject *pyObj, Py_ssize_t *size)
+{
+ Py_buffer view;
+ if (PyObject_GetBuffer(pyObj, &view, PyBUF_ND) == 0) {
+ if (size)
+ *size = view.len;
+ PyBuffer_Release(&view);
+ return view.buf;
+ }
+ return nullptr;
+}
+
+void *Shiboken::Buffer::copyData(PyObject *pyObj, Py_ssize_t *sizeIn)
+{
+ void *result = nullptr;
+ Py_ssize_t size = 0;
+
+ Py_buffer view;
+ if (PyObject_GetBuffer(pyObj, &view, PyBUF_ND) == 0) {
+ size = view.len;
+ if (size) {
+ result = std::malloc(size);
+ if (result != nullptr)
+ std::memcpy(result, view.buf, size);
+ else
+ size = 0;
+ }
+ PyBuffer_Release(&view);
+ }
+
+ if (sizeIn != nullptr)
+ *sizeIn = size;
+ return result;
+}
+
+PyObject *Shiboken::Buffer::newObject(void *memory, Py_ssize_t size, Type type)
+{
+ if (size == 0)
+ Py_RETURN_NONE;
+ Py_buffer view;
+ memset(&view, 0, sizeof(Py_buffer));
+ view.buf = memory;
+ view.len = size;
+ view.readonly = type == Shiboken::Buffer::ReadOnly;
+ view.ndim = 1;
+ view.itemsize = sizeof(char);
+ Py_ssize_t shape[] = { size };
+ view.shape = shape;
+ // Pep384: This is way too complicated and impossible with the limited api:
+ //return PyMemoryView_FromBuffer(&view);
+ return PyMemoryView_FromMemory(reinterpret_cast<char *>(view.buf),
+ size, type == ReadOnly ? PyBUF_READ : PyBUF_WRITE);
+}
+
+PyObject *Shiboken::Buffer::newObject(const void *memory, Py_ssize_t size)
+{
+ return newObject(const_cast<void *>(memory), size, ReadOnly);
+}
diff --git a/sources/shiboken6/libshiboken/shibokenbuffer.h b/sources/shiboken6/libshiboken/shibokenbuffer.h
new file mode 100644
index 000000000..6b17eb6eb
--- /dev/null
+++ b/sources/shiboken6/libshiboken/shibokenbuffer.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SHIBOKEN_BUFFER_H
+#define SHIBOKEN_BUFFER_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+
+namespace Shiboken
+{
+
+namespace Buffer
+{
+ enum Type {
+ ReadOnly,
+ WriteOnly,
+ ReadWrite
+ };
+
+ /**
+ * Creates a new Python buffer pointing to a contiguous memory block at
+ * \p memory of size \p size.
+ */
+ LIBSHIBOKEN_API PyObject *newObject(void *memory, Py_ssize_t size, Type type);
+
+ /**
+ * Creates a new <b>read only</b> Python buffer pointing to a contiguous memory block at
+ * \p memory of size \p size.
+ */
+ LIBSHIBOKEN_API PyObject *newObject(const void *memory, Py_ssize_t size);
+
+ /**
+ * Check if is ok to use \p pyObj as argument in all function under Shiboken::Buffer namespace.
+ */
+ LIBSHIBOKEN_API bool checkType(PyObject *pyObj);
+
+ /**
+ * Returns a pointer to the memory pointed by the buffer \p pyObj, \p size is filled with the buffer
+ * size if not null.
+ *
+ * If the \p pyObj is a non-contiguous buffer a Python error is set.
+ */
+ LIBSHIBOKEN_API void *getPointer(PyObject *pyObj, Py_ssize_t *size = nullptr);
+
+ /**
+ * Returns a copy of the buffer data which should be free'd.
+ *
+ * If the \p pyObj is a non-contiguous buffer a Python error is set.
+ * nullptr is returned for empty buffers.
+ */
+ LIBSHIBOKEN_API void *copyData(PyObject *pyObj, Py_ssize_t *size = nullptr);
+
+} // namespace Buffer
+} // namespace Shiboken
+
+#endif
diff --git a/sources/shiboken6/libshiboken/shibokenmacros.h b/sources/shiboken6/libshiboken/shibokenmacros.h
new file mode 100644
index 000000000..3c083c5bb
--- /dev/null
+++ b/sources/shiboken6/libshiboken/shibokenmacros.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SHIBOKENMACROS_H
+#define SHIBOKENMACROS_H
+
+// LIBSHIBOKEN_API macro is used for the public API symbols.
+#if defined _WIN32
+# define LIBSHIBOKEN_EXPORT __declspec(dllexport)
+# ifdef _MSC_VER
+# define LIBSHIBOKEN_IMPORT __declspec(dllimport)
+# else
+# define LIBSHIBOKEN_IMPORT
+# endif
+#else
+# define LIBSHIBOKEN_EXPORT __attribute__ ((visibility("default")))
+# define LIBSHIBOKEN_IMPORT
+#endif
+
+#ifdef BUILD_LIBSHIBOKEN
+# define LIBSHIBOKEN_API LIBSHIBOKEN_EXPORT
+#else
+# define LIBSHIBOKEN_API LIBSHIBOKEN_IMPORT
+#endif
+
+#endif // SHIBOKENMACROS_H
diff --git a/sources/shiboken6/libshiboken/signature.h b/sources/shiboken6/libshiboken/signature.h
new file mode 100644
index 000000000..e0130b5a6
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SIGNATURE_H
+#define SIGNATURE_H
+
+#include "shibokenmacros.h"
+#include "sbkpython.h"
+
+extern "C"
+{
+
+LIBSHIBOKEN_API int InitSignatureStrings(PyTypeObject *, const char *[]);
+LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *[]);
+LIBSHIBOKEN_API void SetError_Argument(PyObject *, const char *, PyObject *);
+LIBSHIBOKEN_API PyObject *Sbk_TypeGet___doc__(PyObject *);
+LIBSHIBOKEN_API PyObject *GetFeatureDict();
+
+} // extern "C"
+
+#endif // SIGNATURE_H
diff --git a/sources/shiboken6/libshiboken/signature/signature.cpp b/sources/shiboken6/libshiboken/signature/signature.cpp
new file mode 100644
index 000000000..3255cb56d
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature/signature.cpp
@@ -0,0 +1,640 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature.cpp
+// -------------
+//
+// This is the main file of the signature module.
+// It contains the most important functions and avoids confusion
+// by moving many helper functions elsewhere.
+//
+// General documentation can be found in `signature_doc.rst`.
+//
+
+#include "signature.h"
+#include "signature_p.h"
+
+#include "basewrapper.h"
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "sbkfeature_base.h"
+
+#include <structmember.h>
+
+using namespace Shiboken;
+
+extern "C"
+{
+
+static PyObject *CreateSignature(PyObject *props, PyObject *key)
+{
+ /*
+ * Here is the new function to create all signatures. It simply calls
+ * into Python and creates a signature object directly.
+ * This is so much simpler than using all the attributes explicitly
+ * to support '_signature_is_functionlike()'.
+ */
+ return PyObject_CallFunction(pyside_globals->create_signature_func,
+ "(OO)", props, key);
+}
+
+PyObject *GetClassOrModOf(PyObject *ob)
+{
+ /*
+ * Return the type or module of a function or type.
+ * The purpose is finally to use the name of the object.
+ */
+ if (PyType_Check(ob)) {
+ // PySide-928: The type case must do refcounting like the others as well.
+ Py_INCREF(ob);
+ return ob;
+ }
+#ifdef PYPY_VERSION
+ // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
+ if (Py_TYPE(ob) == PepBuiltinMethod_TypePtr)
+ return _get_class_of_bm(ob);
+#endif
+ if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type))
+ return _get_class_of_cf(ob);
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ return _get_class_of_sm(ob);
+ if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
+ return _get_class_of_descr(ob);
+ if (Py_TYPE(ob) == &PyWrapperDescr_Type)
+ return _get_class_of_descr(ob);
+ Py_FatalError("unexpected type in GetClassOrModOf");
+ return nullptr;
+}
+
+PyObject *GetTypeKey(PyObject *ob)
+{
+ assert(PyType_Check(ob) || PyModule_Check(ob));
+ /*
+ * Obtain a unique key using the module name and the type name.
+ *
+ * PYSIDE-1286: We use correct __module__ and __qualname__, now.
+ */
+ AutoDecRef module_name(PyObject_GetAttr(ob, PyMagicName::module()));
+ if (module_name.isNull()) {
+ // We have no module_name because this is a module ;-)
+ PyErr_Clear();
+ module_name.reset(PyObject_GetAttr(ob, PyMagicName::name()));
+ return Py_BuildValue("O", module_name.object());
+ }
+ AutoDecRef class_name(PyObject_GetAttr(ob, PyMagicName::qualname()));
+ if (class_name.isNull()) {
+ Py_FatalError("Signature: missing class name in GetTypeKey");
+ return nullptr;
+ }
+ return Py_BuildValue("(OO)", module_name.object(), class_name.object());
+}
+
+static PyObject *empty_dict = nullptr;
+
+PyObject *TypeKey_to_PropsDict(PyObject *type_key)
+{
+ PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, type_key);
+ if (dict == nullptr) {
+ if (empty_dict == nullptr)
+ empty_dict = PyDict_New();
+ dict = empty_dict;
+ }
+ if (!PyDict_Check(dict))
+ dict = PySide_BuildSignatureProps(type_key);
+ return dict;
+}
+
+static PyObject *_GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier)
+{
+ // Special case: We want to know the func_kind.
+ if (modifier) {
+ PyUnicode_InternInPlace(&modifier);
+ if (modifier == PyMagicName::func_kind())
+ return Py_BuildValue("O", func_kind);
+ }
+
+ AutoDecRef key(modifier == nullptr ? Py_BuildValue("O", func_kind)
+ : Py_BuildValue("(OO)", func_kind, modifier));
+ PyObject *value = PyDict_GetItem(props, key);
+ if (value == nullptr) {
+ // we need to compute a signature object
+ value = CreateSignature(props, key);
+ if (value != nullptr) {
+ if (PyDict_SetItem(props, key, value) < 0)
+ // this is an error
+ return nullptr;
+ }
+ else {
+ // key not found
+ Py_RETURN_NONE;
+ }
+ }
+ return Py_INCREF(value), value;
+}
+
+#ifdef PYPY_VERSION
+PyObject *GetSignature_Method(PyObject *obfunc, PyObject *modifier)
+{
+ AutoDecRef obtype_mod(GetClassOrModOf(obfunc));
+ AutoDecRef type_key(GetTypeKey(obtype_mod));
+ if (type_key.isNull())
+ Py_RETURN_NONE;
+ PyObject *dict = TypeKey_to_PropsDict(type_key);
+ if (dict == nullptr)
+ return nullptr;
+ AutoDecRef func_name(PyObject_GetAttr(obfunc, PyMagicName::name()));
+ PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr;
+ if (props == nullptr)
+ Py_RETURN_NONE;
+ return _GetSignature_Cached(props, PyName::method(), modifier);
+}
+#endif
+
+PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier)
+{
+ // make sure that we look into PyCFunction, only...
+ if (Py_TYPE(obfunc) == PepFunction_TypePtr)
+ Py_RETURN_NONE;
+ AutoDecRef obtype_mod(GetClassOrModOf(obfunc));
+ AutoDecRef type_key(GetTypeKey(obtype_mod));
+ if (type_key.isNull())
+ Py_RETURN_NONE;
+ PyObject *dict = TypeKey_to_PropsDict(type_key);
+ if (dict == nullptr)
+ return nullptr;
+ AutoDecRef func_name(PyObject_GetAttr(obfunc, PyMagicName::name()));
+ PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr;
+ if (props == nullptr)
+ Py_RETURN_NONE;
+
+ int flags = PyCFunction_GET_FLAGS(obfunc);
+ PyObject *func_kind;
+ if (PyModule_Check(obtype_mod.object()))
+ func_kind = PyName::function();
+ else if (flags & METH_CLASS)
+ func_kind = PyName::classmethod();
+ else if (flags & METH_STATIC)
+ func_kind = PyName::staticmethod();
+ else
+ func_kind = PyName::method();
+ return _GetSignature_Cached(props, func_kind, modifier);
+}
+
+PyObject *GetSignature_Wrapper(PyObject *ob, PyObject *modifier)
+{
+ AutoDecRef func_name(PyObject_GetAttr(ob, PyMagicName::name()));
+ AutoDecRef objclass(PyObject_GetAttr(ob, PyMagicName::objclass()));
+ AutoDecRef class_key(GetTypeKey(objclass));
+ if (func_name.isNull() || objclass.isNull() || class_key.isNull())
+ return nullptr;
+ PyObject *dict = TypeKey_to_PropsDict(class_key);
+ if (dict == nullptr)
+ return nullptr;
+ PyObject *props = PyDict_GetItem(dict, func_name);
+ if (props == nullptr) {
+ // handle `__init__` like the class itself
+ if (PyUnicode_CompareWithASCIIString(func_name, "__init__") == 0)
+ return GetSignature_TypeMod(objclass, modifier);
+ Py_RETURN_NONE;
+ }
+ return _GetSignature_Cached(props, PyName::method(), modifier);
+}
+
+PyObject *GetSignature_TypeMod(PyObject *ob, PyObject *modifier)
+{
+ AutoDecRef ob_name(PyObject_GetAttr(ob, PyMagicName::name()));
+ AutoDecRef ob_key(GetTypeKey(ob));
+
+ PyObject *dict = TypeKey_to_PropsDict(ob_key);
+ if (dict == nullptr)
+ return nullptr;
+ PyObject *props = PyDict_GetItem(dict, ob_name);
+ if (props == nullptr)
+ Py_RETURN_NONE;
+ return _GetSignature_Cached(props, PyName::method(), modifier);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// get_signature -- providing a superior interface
+//
+// Additional to the interface via `__signature__`, we also provide
+// a general function, which allows for different signature layouts.
+// The `modifier` argument is a string that is passed in from `loader.py`.
+// Configuration what the modifiers mean is completely in Python.
+//
+// PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter.
+//
+
+PyObject *get_signature_intern(PyObject *ob, PyObject *modifier)
+{
+#ifdef PYPY_VERSION
+ // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
+ if (Py_TYPE(ob) == PepBuiltinMethod_TypePtr) {
+ return pyside_bm_get___signature__(ob, modifier);
+ }
+#endif
+ if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type))
+ return pyside_cf_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ return pyside_sm_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
+ return pyside_md_get___signature__(ob, modifier);
+ if (PyType_Check(ob))
+ return pyside_tp_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == &PyWrapperDescr_Type)
+ return pyside_wd_get___signature__(ob, modifier);
+ // For classmethods we use the simple wrapper description implementation.
+ if (Py_TYPE(ob) == &PyClassMethodDescr_Type)
+ return pyside_wd_get___signature__(ob, modifier);
+ return nullptr;
+}
+
+static PyObject *get_signature(PyObject * /* self */, PyObject *args)
+{
+ PyObject *ob;
+ PyObject *modifier = nullptr;
+
+ if (!PyArg_ParseTuple(args, "O|O", &ob, &modifier))
+ return nullptr;
+ if (Py_TYPE(ob) == PepFunction_TypePtr)
+ Py_RETURN_NONE;
+ PyObject *ret = get_signature_intern(ob, modifier);
+ if (ret != nullptr)
+ return ret;
+ Py_RETURN_NONE;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// feature_import -- special handling for `from __feature__ import ...`
+//
+// The actual function is implemented in Python.
+// When no features are involved, we redirect to the original import.
+// This avoids an extra function level in tracebacks that is irritating.
+//
+
+static PyObject *feature_import(PyObject * /* self */, PyObject *args, PyObject *kwds)
+{
+ PyObject *ret = PyObject_Call(pyside_globals->feature_import_func, args, kwds);
+ if (ret != Py_None)
+ return ret;
+ // feature_import did not handle it, so call the normal import.
+ Py_DECREF(ret);
+ static PyObject *builtins = PyEval_GetBuiltins();
+ PyObject *import_func = PyDict_GetItemString(builtins, "__orig_import__");
+ if (import_func == nullptr) {
+ Py_FatalError("builtins has no \"__orig_import__\" function");
+ }
+ ret = PyObject_Call(import_func, args, kwds);
+ if (ret) {
+ // PYSIDE-2029: Intercept after the import to search for PySide usage.
+ PyObject *post = PyObject_CallFunctionObjArgs(pyside_globals->feature_imported_func,
+ ret, nullptr);
+ Py_XDECREF(post);
+ if (post == nullptr) {
+ Py_DECREF(ret);
+ return nullptr;
+ }
+ }
+ return ret;
+}
+
+PyMethodDef signature_methods[] = {
+ {"__feature_import__", (PyCFunction)feature_import, METH_VARARGS | METH_KEYWORDS, nullptr},
+ {"get_signature", (PyCFunction)get_signature, METH_VARARGS,
+ "get the signature, passing an optional string parameter"},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Argument Handling
+// -----------------
+//
+// * PySide_BuildSignatureArgs
+//
+// Called during class or module initialization.
+// The signature strings from the C modules are stored in a dict for
+// later use.
+//
+// * PySide_BuildSignatureProps
+//
+// Called on demand during signature retieval. This function calls all the way
+// through `parser.py` and prepares all properties for the functions of the class.
+// The parsed properties can then be used to create signature objects.
+//
+
+static int PySide_BuildSignatureArgs(PyObject *obtype_mod, const char *signatures[])
+{
+ AutoDecRef type_key(GetTypeKey(obtype_mod));
+ /*
+ * PYSIDE-996: Avoid string overflow in MSVC, which has a limit of
+ * 2**15 unicode characters (64 K memory).
+ * Instead of one huge string, we take a ssize_t that is the
+ * address of a string array. It will not be turned into a real
+ * string list until really used by Python. This is quite optimal.
+ */
+ AutoDecRef numkey(Py_BuildValue("n", signatures));
+ if (type_key.isNull() || numkey.isNull()
+ || PyDict_SetItem(pyside_globals->arg_dict, type_key, numkey) < 0)
+ return -1;
+ /*
+ * We record also a mapping from type key to type/module. This helps to
+ * lazily initialize the Py_LIMITED_API in name_key_to_func().
+ */
+ return PyDict_SetItem(pyside_globals->map_dict, type_key, obtype_mod) == 0 ? 0 : -1;
+}
+
+PyObject *PySide_BuildSignatureProps(PyObject *type_key)
+{
+ /*
+ * Here is the second part of the function.
+ * This part will be called on-demand when needed by some attribute.
+ * We simply pick up the arguments that we stored here and replace
+ * them by the function result.
+ */
+ if (type_key == nullptr)
+ return nullptr;
+ PyObject *numkey = PyDict_GetItem(pyside_globals->arg_dict, type_key);
+ AutoDecRef strings(_address_to_stringlist(numkey));
+ if (strings.isNull())
+ return nullptr;
+ AutoDecRef arg_tup(Py_BuildValue("(OO)", type_key, strings.object()));
+ if (arg_tup.isNull())
+ return nullptr;
+ PyObject *dict = PyObject_CallObject(pyside_globals->pyside_type_init_func, arg_tup);
+ if (dict == nullptr) {
+ if (PyErr_Occurred())
+ return nullptr;
+ // No error: return an empty dict.
+ if (empty_dict == nullptr)
+ empty_dict = PyDict_New();
+ return empty_dict;
+ }
+ // PYSIDE-1019: Build snake case versions of the functions.
+ if (insert_snake_case_variants(dict) < 0)
+ return nullptr;
+ // We replace the arguments by the result dict.
+ if (PyDict_SetItem(pyside_globals->arg_dict, type_key, dict) < 0)
+ return nullptr;
+ return dict;
+}
+//
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef PYPY_VERSION
+static bool get_lldebug_flag()
+{
+ auto *dic = PySys_GetObject("pypy_translation_info");
+ int lldebug = PyObject_IsTrue(PyDict_GetItemString(dic, "translation.lldebug"));
+ int lldebug0 = PyObject_IsTrue(PyDict_GetItemString(dic, "translation.lldebug0"));
+ return lldebug || lldebug0;
+}
+
+#endif
+
+static int PySide_FinishSignatures(PyObject *module, const char *signatures[])
+{
+#ifdef PYPY_VERSION
+ static const bool have_problem = get_lldebug_flag();
+ if (have_problem)
+ return 0; // crash with lldebug at `PyDict_Next`
+#endif
+ /*
+ * Initialization of module functions and resolving of static methods.
+ */
+ const char *name = PyModule_GetName(module);
+ if (name == nullptr)
+ return -1;
+
+ // we abuse the call for types, since they both have a __name__ attribute.
+ if (PySide_BuildSignatureArgs(module, signatures) < 0)
+ return -1;
+
+ /*
+ * Note: This function crashed when called from PySide_BuildSignatureArgs.
+ * Probably this was an import timing problem.
+ *
+ * Pep384: We need to switch this always on since we have no access
+ * to the PyCFunction attributes. Therefore I simplified things
+ * and always use our own mapping.
+ */
+ PyObject *key, *func, *obdict = PyModule_GetDict(module);
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(obdict, &pos, &key, &func))
+ if (PyCFunction_Check(func))
+ if (PyDict_SetItem(pyside_globals->map_dict, func, module) < 0)
+ return -1;
+ // The finish_import function will not work the first time since phase 2
+ // was not yet run. But that is ok, because the first import is always for
+ // the shiboken module (or a test module).
+ if (pyside_globals->finish_import_func == nullptr) {
+ assert(strncmp(name, "PySide6.", 8) != 0);
+ return 0;
+ }
+ AutoDecRef ret(PyObject_CallFunction(
+ pyside_globals->finish_import_func, "(O)", module));
+ return ret.isNull() ? -1 : 0;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// External functions interface
+//
+// These are exactly the supported functions from `signature.h`.
+//
+
+int InitSignatureStrings(PyTypeObject *type, const char *signatures[])
+{
+ // PYSIDE-2404: This function now also builds the mapping for static methods.
+ // It was one missing spot to let Lazy import work.
+ init_shibokensupport_module();
+ auto *ob_type = reinterpret_cast<PyObject *>(type);
+ int ret = PySide_BuildSignatureArgs(ob_type, signatures);
+ if (ret < 0 || _build_func_to_type(ob_type) < 0) {
+ PyErr_Print();
+ PyErr_SetNone(PyExc_ImportError);
+ }
+ return ret;
+}
+
+void FinishSignatureInitialization(PyObject *module, const char *signatures[])
+{
+ /*
+ * This function is called at the very end of a module initialization.
+ * We now patch certain types to support the __signature__ attribute,
+ * initialize module functions and resolve static methods.
+ *
+ * Still, it is not possible to call init phase 2 from here,
+ * because the import is still running. Do it from Python!
+ */
+ init_shibokensupport_module();
+
+#ifndef PYPY_VERSION
+ static const bool patch_types = true;
+#else
+ // PYSIDE-535: On PyPy we cannot patch builtin types. This can be
+ // re-implemented later. For now, we use `get_signature`, instead.
+ static const bool patch_types = false;
+#endif
+
+ if ((patch_types && PySide_PatchTypes() < 0)
+ || PySide_FinishSignatures(module, signatures) < 0) {
+ PyErr_Print();
+ PyErr_SetNone(PyExc_ImportError);
+ }
+}
+
+static PyObject *adjustFuncName(const char *func_name)
+{
+ /*
+ * PYSIDE-1019: Modify the function name expression according to feature.
+ *
+ * - snake_case
+ * The function name must be converted.
+ * - full_property
+ * The property name must be used and "fset" appended.
+ *
+ * modname.subname.classsname.propname.fset
+ *
+ * Class properties must use the expression
+ *
+ * modname.subname.classsname.__dict__['propname'].fset
+ *
+ * Note that fget is impossible because there are no parameters.
+ */
+ static const char mapping_name[] = "shibokensupport.signature.mapping";
+ static PyObject *sys_modules = PySys_GetObject("modules");
+ static PyObject *mapping = PyDict_GetItemString(sys_modules, mapping_name);
+ static PyObject *ns = PyModule_GetDict(mapping);
+
+ char _path[200 + 1] = {};
+ const char *_name = strrchr(func_name, '.');
+ strncat(_path, func_name, _name - func_name);
+ ++_name;
+
+ // This is a very cheap call into `mapping.py`.
+ PyObject *update_mapping = PyDict_GetItemString(ns, "update_mapping");
+ AutoDecRef res(PyObject_CallFunctionObjArgs(update_mapping, nullptr));
+ if (res.isNull())
+ return nullptr;
+
+ // Run `eval` on the type string to get the object.
+ // PYSIDE-1710: If the eval does not work, return the given string.
+ AutoDecRef obtype(PyRun_String(_path, Py_eval_input, ns, ns));
+ if (obtype.isNull())
+ return String::fromCString(func_name);
+
+ if (PyModule_Check(obtype.object())) {
+ // This is a plain function. Return the unmangled name.
+ return String::fromCString(func_name);
+ }
+ assert(PyType_Check(obtype)); // This was not true for __init__!
+
+ // Find the feature flags
+ auto type = reinterpret_cast<PyTypeObject *>(obtype.object());
+ AutoDecRef dict(PepType_GetDict(type));
+ int id = currentSelectId(type);
+ id = id < 0 ? 0 : id; // if undefined, set to zero
+ auto lower = id & 0x01;
+ auto is_prop = id & 0x02;
+ bool is_class_prop = false;
+
+ // Compute all needed info.
+ PyObject *name = String::getSnakeCaseName(_name, lower);
+ PyObject *prop_name{};
+ if (is_prop) {
+ PyObject *prop_methods = PyDict_GetItem(dict, PyMagicName::property_methods());
+ prop_name = PyDict_GetItem(prop_methods, name);
+ if (prop_name != nullptr) {
+ PyObject *prop = PyDict_GetItem(dict, prop_name);
+ is_class_prop = Py_TYPE(prop) != &PyProperty_Type;
+ }
+ }
+
+ // Finally, generate the correct path expression.
+ char _buf[250 + 1] = {};
+ if (prop_name) {
+ auto _prop_name = String::toCString(prop_name);
+ if (is_class_prop)
+ snprintf(_buf, sizeof(_buf), "%s.__dict__['%s'].fset", _path, _prop_name);
+ else
+ snprintf(_buf, sizeof(_buf), "%s.%s.fset", _path, _prop_name);
+ }
+ else {
+ auto _name = String::toCString(name);
+ snprintf(_buf, sizeof(_buf), "%s.%s", _path, _name);
+ }
+ return String::fromCString(_buf);
+}
+
+void SetError_Argument(PyObject *args, const char *func_name, PyObject *info)
+{
+ init_shibokensupport_module();
+ /*
+ * This function replaces the type error construction with extra
+ * overloads parameter in favor of using the signature module.
+ * Error messages are rare, so we do it completely in Python.
+ */
+
+ // PYSIDE-1305: Handle errors set by fillQtProperties.
+ if (PyErr_Occurred()) {
+ PyObject *e, *v, *t;
+ // Note: These references are all borrowed.
+ PyErr_Fetch(&e, &v, &t);
+ Py_DECREF(e);
+ info = v;
+ Py_XDECREF(t);
+ }
+ // PYSIDE-1019: Modify the function name expression according to feature.
+ AutoDecRef new_func_name(adjustFuncName(func_name));
+ if (new_func_name.isNull()) {
+ PyErr_Print();
+ Py_FatalError("seterror_argument failed to call update_mapping");
+ }
+ if (info == nullptr)
+ info = Py_None;
+ AutoDecRef res(PyObject_CallFunctionObjArgs(pyside_globals->seterror_argument_func,
+ args, new_func_name.object(), info, nullptr));
+ if (res.isNull()) {
+ PyErr_Print();
+ Py_FatalError("seterror_argument did not receive a result");
+ }
+ PyObject *err, *msg;
+ if (!PyArg_UnpackTuple(res, func_name, 2, 2, &err, &msg)) {
+ PyErr_Print();
+ Py_FatalError("unexpected failure in seterror_argument");
+ }
+ PyErr_SetObject(err, msg);
+}
+
+/*
+ * Support for the metatype SbkObjectType_Type's tp_getset.
+ *
+ * This was not necessary for __signature__, because PyType_Type inherited it.
+ * But the __doc__ attribute existed already by inheritance, and calling
+ * PyType_Modified() is not supported. So we added the getsets explicitly
+ * to the metatype.
+ *
+ * PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter.
+ */
+
+PyObject *Sbk_TypeGet___doc__(PyObject *ob)
+{
+ init_shibokensupport_module();
+ return pyside_tp_get___doc__(ob);
+}
+
+PyObject *GetFeatureDict()
+{
+ init_shibokensupport_module();
+ return pyside_globals->feature_dict;
+}
+
+} //extern "C"
diff --git a/sources/shiboken6/libshiboken/signature/signature_extend.cpp b/sources/shiboken6/libshiboken/signature/signature_extend.cpp
new file mode 100644
index 000000000..7292f8216
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature/signature_extend.cpp
@@ -0,0 +1,230 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature_extend.cpp
+// --------------------
+//
+// This file contains the additions and changes to the following
+// Python types:
+//
+// PyMethodDescr_Type
+// PyCFunction_Type
+// PyStaticMethod_Type
+// (*) PyType_Type
+// PyWrapperDescr_Type
+//
+// Their `tp_getset` fields are modified to support the `__signature__`
+// attribute and additions to the `__doc__` attribute.
+//
+// PYSIDE-535: PyType_Type patching is removed,
+// Shiboken.ObjectType and Shiboken.EnumMeta have new getsets, instead.
+
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+
+#include "signature_p.h"
+
+using namespace Shiboken;
+
+extern "C" {
+
+using signaturefunc = PyObject *(*)(PyObject *, PyObject *);
+
+static PyObject *_get_written_signature(signaturefunc sf, PyObject *ob, PyObject *modifier)
+{
+ /*
+ * Be a writable Attribute, but have a computed value.
+ *
+ * If a signature has not been written, call the signature function.
+ * If it has been written, return the written value.
+ * After __del__ was called, the function value re-appears.
+ *
+ * Note: This serves also for the new version that does not allow any
+ * assignment if we have a computed value. We only need to check if
+ * a computed value exists and then forbid writing.
+ * See pyside_set___signature
+ */
+ PyObject *ret = PyDict_GetItem(pyside_globals->value_dict, ob);
+ if (ret == nullptr)
+ return ob == nullptr ? nullptr : sf(ob, modifier);
+ Py_INCREF(ret);
+ return ret;
+}
+
+#ifdef PYPY_VERSION
+PyObject *pyside_bm_get___signature__(PyObject *func, PyObject *modifier)
+{
+ return _get_written_signature(GetSignature_Method, func, modifier);
+}
+#endif
+
+PyObject *pyside_cf_get___signature__(PyObject *func, PyObject *modifier)
+{
+ return _get_written_signature(GetSignature_Function, func, modifier);
+}
+
+PyObject *pyside_sm_get___signature__(PyObject *sm, PyObject *modifier)
+{
+ AutoDecRef func(PyObject_GetAttr(sm, PyMagicName::func()));
+ return _get_written_signature(GetSignature_Function, func, modifier);
+}
+
+PyObject *pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier)
+{
+ AutoDecRef func(name_key_to_func(ob_md));
+ if (func.object() == Py_None)
+ Py_RETURN_NONE;
+ if (func.isNull())
+ Py_FatalError("missing mapping in MethodDescriptor");
+ return pyside_cf_get___signature__(func, modifier);
+}
+
+PyObject *pyside_wd_get___signature__(PyObject *ob, PyObject *modifier)
+{
+ return _get_written_signature(GetSignature_Wrapper, ob, modifier);
+}
+
+PyObject *pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier)
+{
+ return _get_written_signature(GetSignature_TypeMod, obtype_mod, modifier);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Augmenting builtin types with a __signature__ attribute.
+//
+// This is a harmless change to Python, similar like __text_signature__.
+// We could avoid it, but then we would need to copy quite some module
+// initialization functions which are pretty version- and word size
+// dependent. I think this little patch is the lesser of the two evils.
+//
+// Please note that in fact we are modifying 'type', the metaclass of all
+// objects, because we add new functionality.
+//
+// Addendum 2019-01-12: We now also compute a docstring from the signature.
+//
+
+// keep the original __doc__ functions
+static PyObject *old_cf_doc_descr = nullptr;
+static PyObject *old_sm_doc_descr = nullptr;
+static PyObject *old_md_doc_descr = nullptr;
+static PyObject *old_tp_doc_descr = nullptr;
+static PyObject *old_wd_doc_descr = nullptr;
+
+static int handle_doc_in_progress = 0;
+
+static PyObject *handle_doc(PyObject *ob, PyObject *old_descr)
+{
+ AutoDecRef ob_type_mod(GetClassOrModOf(ob));
+ const char *name;
+ bool isModule = PyModule_Check(ob_type_mod.object());
+ if (isModule)
+ name = PyModule_GetName(ob_type_mod.object());
+ else
+ name = reinterpret_cast<PyTypeObject *>(ob_type_mod.object())->tp_name;
+ PyObject *res{};
+
+ if (handle_doc_in_progress || name == nullptr
+ || (isModule && strncmp(name, "PySide6.", 8) != 0)) {
+ res = PyObject_CallMethodObjArgs(old_descr, PyMagicName::get(), ob, nullptr);
+ } else {
+ handle_doc_in_progress++;
+ res = PyObject_CallFunction(pyside_globals->make_helptext_func, "(O)", ob);
+ handle_doc_in_progress--;
+ }
+
+ if (res)
+ return res;
+
+ PyErr_Clear();
+ Py_RETURN_NONE;
+}
+
+static PyObject *pyside_cf_get___doc__(PyObject *cf)
+{
+ return handle_doc(cf, old_cf_doc_descr);
+}
+
+static PyObject *pyside_sm_get___doc__(PyObject *sm)
+{
+ return handle_doc(sm, old_sm_doc_descr);
+}
+
+static PyObject *pyside_md_get___doc__(PyObject *md)
+{
+ return handle_doc(md, old_md_doc_descr);
+}
+
+PyObject *pyside_tp_get___doc__(PyObject *tp)
+{
+ return handle_doc(tp, old_tp_doc_descr);
+}
+
+static PyObject *pyside_wd_get___doc__(PyObject *wd)
+{
+ return handle_doc(wd, old_wd_doc_descr);
+}
+
+// PYSIDE-535: We cannot patch types easily in PyPy.
+// Let's use the `get_signature` function, instead.
+static PyGetSetDef new_PyCFunction_getsets[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(pyside_cf_get___doc__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+static PyGetSetDef new_PyStaticMethod_getsets[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(pyside_sm_get___doc__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+static PyGetSetDef new_PyMethodDescr_getsets[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(pyside_md_get___doc__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+static PyGetSetDef new_PyWrapperDescr_getsets[] = {
+ {const_cast<char *>("__doc__"), reinterpret_cast<getter>(pyside_wd_get___doc__),
+ nullptr, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+};
+
+int PySide_PatchTypes(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ AutoDecRef meth_descr(PyObject_GetAttrString(
+ reinterpret_cast<PyObject *>(&PyUnicode_Type), "split"));
+ AutoDecRef wrap_descr(PyObject_GetAttrString(
+ reinterpret_cast<PyObject *>(Py_TYPE(Py_True)), "__add__"));
+ // abbreviations for readability
+ auto md_gs = new_PyMethodDescr_getsets;
+ auto md_doc = &old_md_doc_descr;
+ auto cf_gs = new_PyCFunction_getsets;
+ auto cf_doc = &old_cf_doc_descr;
+ auto sm_gs = new_PyStaticMethod_getsets;
+ auto sm_doc = &old_sm_doc_descr;
+ auto wd_gs = new_PyWrapperDescr_getsets;
+ auto wd_doc = &old_wd_doc_descr;
+
+ if (meth_descr.isNull() || wrap_descr.isNull()
+ || PyType_Ready(Py_TYPE(meth_descr)) < 0
+ || add_more_getsets(PepMethodDescr_TypePtr, md_gs, md_doc) < 0
+ || add_more_getsets(&PyCFunction_Type, cf_gs, cf_doc) < 0
+ || add_more_getsets(PepStaticMethod_TypePtr, sm_gs, sm_doc) < 0
+ || add_more_getsets(Py_TYPE(wrap_descr), wd_gs, wd_doc) < 0
+ )
+ return -1;
+ init_done = 1;
+ }
+ return 0;
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/signature/signature_globals.cpp b/sources/shiboken6/libshiboken/signature/signature_globals.cpp
new file mode 100644
index 000000000..3a79a12d5
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature/signature_globals.cpp
@@ -0,0 +1,264 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature_global.cpp
+//
+// This file contains the global data structures and init code.
+//
+
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "sbkenum.h"
+
+#include "signature_p.h"
+
+using namespace Shiboken;
+
+extern "C" {
+
+static const char *PySide_CompressedSignaturePackage[] = {
+#include "embed/signature_inc.h"
+ };
+
+static const unsigned char PySide_SignatureLoader[] = {
+#include "embed/signature_bootstrap_inc.h"
+ };
+
+static safe_globals_struc *init_phase_1()
+{
+ do {
+ auto *p = reinterpret_cast<safe_globals_struc *>
+ (malloc(sizeof(safe_globals_struc)));
+ if (p == nullptr)
+ break;
+ /*
+ * Initializing module signature_bootstrap.
+ * Since we now have an embedding script, we can do this without any
+ * Python strings in the C code.
+ */
+#if defined(Py_LIMITED_API) || defined(SHIBOKEN_NO_EMBEDDING_PYC)
+ // We must work for multiple versions or we are cross-building for a different
+ // Python version interpreter, so use source code.
+#else
+ AutoDecRef marshal_module(PyImport_Import(PyName::marshal())); // builtin
+ AutoDecRef loads(PyObject_GetAttr(marshal_module, PyName::loads()));
+ if (loads.isNull())
+ break;
+#endif
+ char *bytes_cast = reinterpret_cast<char *>(
+ const_cast<unsigned char *>(PySide_SignatureLoader));
+ AutoDecRef bytes(PyBytes_FromStringAndSize(bytes_cast, sizeof(PySide_SignatureLoader)));
+ if (bytes.isNull())
+ break;
+#if defined(Py_LIMITED_API) || defined(SHIBOKEN_NO_EMBEDDING_PYC)
+ PyObject *builtins = PyEval_GetBuiltins();
+ PyObject *compile = PyDict_GetItem(builtins, PyName::compile());
+ if (compile == nullptr)
+ break;
+ AutoDecRef code_obj(PyObject_CallFunction(compile, "Oss",
+ bytes.object(), "signature_bootstrap.py", "exec"));
+#else
+ AutoDecRef code_obj(PyObject_CallFunctionObjArgs(
+ loads, bytes.object(), nullptr));
+#endif
+ if (code_obj.isNull())
+ break;
+ p->helper_module = PyImport_ExecCodeModule("signature_bootstrap", code_obj);
+ if (p->helper_module == nullptr)
+ break;
+ // Initialize the module
+ PyObject *mdict = PyModule_GetDict(p->helper_module);
+ if (PyDict_SetItem(mdict, PyMagicName::builtins(), PyEval_GetBuiltins()) < 0)
+ break;
+
+ /*********************************************************************
+ *
+ * Attention!
+ * ----------
+ *
+ * We are unpacking an embedded ZIP file with more signature modules.
+ * They will be loaded later with the zipimporter.
+ * The file `signature_bootstrap.py` does the unpacking and starts the
+ * loader. See `init_phase_2`.
+ *
+ * Due to MSVC's limitation to 64k strings, we needed to assemble pieces.
+ */
+ auto **block_ptr = reinterpret_cast<const char **>(PySide_CompressedSignaturePackage);
+ PyObject *piece{};
+ AutoDecRef zipped_string_sequence(PyList_New(0));
+ for (; **block_ptr != 0; ++block_ptr) {
+ // we avoid the string/unicode dilemma by not using PyString_XXX:
+ piece = Py_BuildValue("s", *block_ptr);
+ if (piece == nullptr || PyList_Append(zipped_string_sequence, piece) < 0)
+ break;
+ }
+ if (PyDict_SetItemString(mdict, "zipstring_sequence", zipped_string_sequence) < 0)
+ break;
+
+ // build a dict for diverse mappings
+ p->map_dict = PyDict_New();
+
+ // build a dict for the prepared arguments
+ p->arg_dict = PyDict_New();
+ if (PyObject_SetAttrString(p->helper_module, "pyside_arg_dict", p->arg_dict) < 0)
+ break;
+
+ // build a dict for assigned signature values
+ p->value_dict = PyDict_New();
+
+ // PYSIDE-1019: build a __feature__ dict
+ p->feature_dict = PyDict_New();
+ if (PyObject_SetAttrString(p->helper_module, "pyside_feature_dict", p->feature_dict) < 0)
+ break;
+
+ // This function will be disabled until phase 2 is done.
+ p->finish_import_func = nullptr;
+
+ return p;
+
+ } while (0);
+
+ PyErr_Print();
+ Py_FatalError("could not initialize part 1");
+ return nullptr;
+}
+
+static int init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
+{
+ do {
+ PyMethodDef *ml;
+
+ // The single function to be called, but maybe more to come.
+ for (ml = methods; ml->ml_name != nullptr; ml++) {
+ PyObject *v = PyCFunction_NewEx(ml, nullptr, nullptr);
+ if (v == nullptr
+ || PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0)
+ break;
+ Py_DECREF(v);
+ }
+ // The first entry is __feature_import__, add documentation.
+ PyObject *builtins = PyEval_GetBuiltins();
+ PyObject *imp_func = PyDict_GetItemString(builtins, "__import__");
+ PyObject *imp_doc = PyObject_GetAttrString(imp_func, "__doc__");
+ signature_methods[0].ml_doc = String::toCString(imp_doc);
+
+ PyObject *bootstrap_func = PyObject_GetAttrString(p->helper_module, "bootstrap");
+ if (bootstrap_func == nullptr)
+ break;
+
+ /*********************************************************************
+ *
+ * Attention!
+ * ----------
+ *
+ * This is the entry point where everything in folder
+ * `shibokensupport` becomes initialized. It starts with
+ * `signature_bootstrap.py` and continues from there to `loader.py`.
+ *
+ * The return value of the bootstrap function is the loader module.
+ */
+ PyObject *loader = PyObject_CallFunctionObjArgs(bootstrap_func, nullptr);
+ if (loader == nullptr)
+ break;
+
+ // now the loader should be initialized
+ p->pyside_type_init_func = PyObject_GetAttrString(loader, "pyside_type_init");
+ if (p->pyside_type_init_func == nullptr)
+ break;
+ p->create_signature_func = PyObject_GetAttrString(loader, "create_signature");
+ if (p->create_signature_func == nullptr)
+ break;
+ p->seterror_argument_func = PyObject_GetAttrString(loader, "seterror_argument");
+ if (p->seterror_argument_func == nullptr)
+ break;
+ p->make_helptext_func = PyObject_GetAttrString(loader, "make_helptext");
+ if (p->make_helptext_func == nullptr)
+ break;
+ p->finish_import_func = PyObject_GetAttrString(loader, "finish_import");
+ if (p->finish_import_func == nullptr)
+ break;
+ p->feature_import_func = PyObject_GetAttrString(loader, "feature_import");
+ if (p->feature_import_func == nullptr)
+ break;
+ p->feature_imported_func = PyObject_GetAttrString(loader, "feature_imported");
+ if (p->feature_imported_func == nullptr)
+ break;
+
+ // We call stuff like the feature initialization late,
+ // after all the function pointers are in place.
+ PyObject *post_init_func = PyObject_GetAttrString(loader, "post_init");
+ if (post_init_func == nullptr)
+ break;
+ PyObject *ret = PyObject_CallFunctionObjArgs(post_init_func, nullptr);
+ if (ret == nullptr)
+ break;
+
+ return 0;
+
+ } while (0);
+
+ PyErr_Print();
+ Py_FatalError("could not initialize part 2");
+ return -1;
+}
+
+#ifndef _WIN32
+////////////////////////////////////////////////////////////////////////////
+// a stack trace for linux-like platforms
+#include <cstdio>
+#if defined(__GLIBC__)
+# include <execinfo.h>
+#endif
+#include <signal.h>
+#include <cstdlib>
+#include <unistd.h>
+
+static void handler(int sig) {
+#if defined(__GLIBC__)
+ void *array[30];
+ size_t size;
+
+ // get void *'s for all entries on the stack
+ size = backtrace(array, 30);
+
+ // print out all the frames to stderr
+#endif
+ std::fprintf(stderr, "Error: signal %d:\n", sig);
+#if defined(__GLIBC__)
+ backtrace_symbols_fd(array, size, STDERR_FILENO);
+#endif
+ exit(1);
+}
+
+////////////////////////////////////////////////////////////////////////////
+#endif // _WIN32
+
+safe_globals_struc *pyside_globals = nullptr;
+
+void init_shibokensupport_module(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ pyside_globals = init_phase_1();
+ if (pyside_globals != nullptr)
+ init_done = 1;
+
+#ifndef _WIN32
+ // We enable the stack trace in CI, only.
+ const char *testEnv = getenv("QTEST_ENVIRONMENT");
+ if (testEnv && strstr(testEnv, "ci"))
+ signal(SIGSEGV, handler); // install our handler
+#endif // _WIN32
+
+ init_phase_2(pyside_globals, signature_methods);
+ // Enum must be initialized when signatures exist, not earlier.
+ init_enum();
+ }
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/signature/signature_helper.cpp b/sources/shiboken6/libshiboken/signature/signature_helper.cpp
new file mode 100644
index 000000000..cf84cfa13
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature/signature_helper.cpp
@@ -0,0 +1,389 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+////////////////////////////////////////////////////////////////////////////
+//
+// signature_helper.cpp
+// --------------------
+//
+// This file contains assoerted helper functions that are needed,
+// but it is not helpful to see them all the time.
+//
+
+#include "autodecref.h"
+#include "sbkstring.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+
+#include "signature_p.h"
+
+using namespace Shiboken;
+
+extern "C" {
+
+static int _fixup_getset(PyTypeObject *type, const char *name, PyGetSetDef *new_gsp)
+{
+ /*
+ * This function pre-fills all fields of the new gsp. We then
+ * insert the changed values.
+ */
+ PyGetSetDef *gsp = type->tp_getset;
+ if (gsp != nullptr) {
+ for (; gsp->name != nullptr; gsp++) {
+ if (strcmp(gsp->name, name) == 0) {
+ new_gsp->set = gsp->set;
+ new_gsp->doc = gsp->doc;
+ new_gsp->closure = gsp->closure;
+ return 1; // success
+ }
+ }
+ }
+ PyMemberDef *md = type->tp_members;
+ if (md != nullptr)
+ for (; md->name != nullptr; md++)
+ if (strcmp(md->name, name) == 0)
+ return 1;
+ return 0;
+}
+
+int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr)
+{
+ /*
+ * This function is used to assign a new `__signature__` attribute,
+ * and also to override a `__doc__` or `__name__` attribute.
+ *
+ * PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter.
+ */
+ assert(PyType_Check(type));
+ PyType_Ready(type);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *dict = tpDict.object();
+ for (; gsp->name != nullptr; gsp++) {
+ PyObject *have_descr = PyDict_GetItemString(dict, gsp->name);
+ if (have_descr != nullptr) {
+ Py_INCREF(have_descr);
+ if (strcmp(gsp->name, "__doc__") == 0)
+ *doc_descr = have_descr;
+ else
+ assert(false);
+ if (!_fixup_getset(type, gsp->name, gsp))
+ continue;
+ }
+ AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
+ if (descr.isNull())
+ return -1;
+ // PYSIDE-535: We cannot set the attribute. For simplicity, we use
+ // get_signature in PyPy, instead. This can be re-implemented
+ // later by deriving extra heap types.
+ if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
+ return -1;
+ }
+ PyType_Modified(type);
+ return 0;
+}
+
+static PyObject *get_funcname(PyObject *ob)
+{
+ PyObject *func = ob;
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ func = PyObject_GetAttr(ob, PyMagicName::func());
+ else
+ Py_INCREF(func);
+ PyObject *func_name = PyObject_GetAttr(func, PyMagicName::name());
+ Py_DECREF(func);
+ if (func_name == nullptr)
+ Py_FatalError("unexpected name problem in compute_name_key");
+ return func_name;
+}
+
+static PyObject *compute_name_key(PyObject *ob)
+{
+ if (PyType_Check(ob))
+ return GetTypeKey(ob);
+ AutoDecRef func_name(get_funcname(ob));
+ AutoDecRef type_key(GetTypeKey(GetClassOrModOf(ob)));
+ return Py_BuildValue("(OO)", type_key.object(), func_name.object());
+}
+
+static PyObject *_func_with_new_name(PyTypeObject *type,
+ PyMethodDef *meth,
+ const char *new_name)
+{
+ /*
+ * Create a function with a lower case name.
+ * Note: This is similar to feature_select's methodWithNewName,
+ * but does not create a descriptor.
+ * XXX Maybe we can get rid of this, completely?
+ */
+ auto obtype = reinterpret_cast<PyObject *>(type);
+ int len = strlen(new_name);
+ auto name = new char[len + 1];
+ strcpy(name, new_name);
+ auto new_meth = new PyMethodDef;
+ new_meth->ml_name = name;
+ new_meth->ml_meth = meth->ml_meth;
+ new_meth->ml_flags = meth->ml_flags;
+ new_meth->ml_doc = meth->ml_doc;
+ return PyCFunction_NewEx(new_meth, obtype, nullptr);
+}
+
+static int build_name_key_to_func(PyObject *obtype)
+{
+ auto *type = reinterpret_cast<PyTypeObject *>(obtype);
+ PyMethodDef *meth = type->tp_methods;
+
+ if (meth == nullptr)
+ return 0;
+
+ AutoDecRef type_key(GetTypeKey(obtype));
+ for (; meth->ml_name != nullptr; meth++) {
+ AutoDecRef func(PyCFunction_NewEx(meth, obtype, nullptr));
+ AutoDecRef func_name(get_funcname(func));
+ AutoDecRef name_key(Py_BuildValue("(OO)", type_key.object(), func_name.object()));
+ if (func.isNull() || name_key.isNull()
+ || PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
+ return -1;
+ }
+ // PYSIDE-1019: Now we repeat the same for snake case names.
+ meth = type->tp_methods;
+ for (; meth->ml_name != nullptr; meth++) {
+ const char *name = String::toCString(String::getSnakeCaseName(meth->ml_name, true));
+ AutoDecRef func(_func_with_new_name(type, meth, name));
+ AutoDecRef func_name(get_funcname(func));
+ AutoDecRef name_key(Py_BuildValue("(OO)", type_key.object(), func_name.object()));
+ if (func.isNull() || name_key.isNull()
+ || PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+PyObject *name_key_to_func(PyObject *ob)
+{
+ /*
+ * We build a mapping from name_key to function.
+ * This could also be computed directly, but the Limited API
+ * makes this impossible. So we always build our own mapping.
+ */
+ AutoDecRef name_key(compute_name_key(ob));
+ if (name_key.isNull())
+ Py_RETURN_NONE;
+
+ PyObject *ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
+ if (ret == nullptr) {
+ // do a lazy initialization
+ AutoDecRef type_key(GetTypeKey(GetClassOrModOf(ob)));
+ PyObject *type = PyDict_GetItem(pyside_globals->map_dict,
+ type_key);
+ if (type == nullptr)
+ Py_RETURN_NONE;
+ assert(PyType_Check(type));
+ if (build_name_key_to_func(type) < 0)
+ return nullptr;
+ ret = PyDict_GetItem(pyside_globals->map_dict, name_key);
+ }
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *_build_new_entry(PyObject *new_name, PyObject *value)
+{
+ PyObject *new_value = PyDict_Copy(value);
+ PyObject *multi = PyDict_GetItem(value, PyName::multi());
+ if (multi != nullptr && Py_TYPE(multi) == &PyList_Type) {
+ Py_ssize_t len = PyList_Size(multi);
+ AutoDecRef list(PyList_New(len));
+ if (list.isNull())
+ return nullptr;
+ for (int idx = 0; idx < len; ++idx) {
+ auto multi_entry = PyList_GetItem(multi, idx);
+ auto dup = PyDict_Copy(multi_entry);
+ if (PyDict_SetItem(dup, PyName::name(), new_name) < 0)
+ return nullptr;
+ if (PyList_SetItem(list, idx, dup) < 0)
+ return nullptr;
+ }
+ if (PyDict_SetItem(new_value, PyName::multi(), list) < 0)
+ return nullptr;
+ } else {
+ if (PyDict_SetItem(new_value, PyName::name(), new_name) < 0)
+ return nullptr;
+ }
+ return new_value;
+}
+
+int insert_snake_case_variants(PyObject *dict)
+{
+ AutoDecRef snake_dict(PyDict_New());
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ AutoDecRef name(String::getSnakeCaseName(key, true));
+ AutoDecRef new_value(_build_new_entry(name, value));
+ if (PyDict_SetItem(snake_dict, name, new_value) < 0)
+ return -1;
+ }
+ return PyDict_Merge(dict, snake_dict, 0);
+}
+
+#ifdef PYPY_VERSION
+PyObject *_get_class_of_bm(PyObject *ob_bm)
+{
+ AutoDecRef self(PyObject_GetAttr(ob_bm, PyMagicName::self()));
+ auto *klass = PyObject_GetAttr(self, PyMagicName::class_());
+ return klass;
+}
+#endif
+
+PyObject *_get_class_of_cf(PyObject *ob_cf)
+{
+ PyObject *selftype = PyCFunction_GET_SELF(ob_cf);
+ if (selftype == nullptr) {
+ selftype = PyDict_GetItem(pyside_globals->map_dict, ob_cf);
+ if (selftype == nullptr) {
+ // This must be an overloaded function that we handled special.
+ AutoDecRef special(Py_BuildValue("(OO)", ob_cf, PyName::overload()));
+ selftype = PyDict_GetItem(pyside_globals->map_dict, special);
+ if (selftype == nullptr) {
+ // This is probably a module function. We will return type(None).
+ selftype = Py_None;
+ }
+ }
+ }
+
+ PyObject *obtype_mod = (PyType_Check(selftype) || PyModule_Check(selftype))
+ ? selftype
+ : reinterpret_cast<PyObject *>(Py_TYPE(selftype));
+ Py_INCREF(obtype_mod);
+ return obtype_mod;
+}
+
+PyObject *_get_class_of_sm(PyObject *ob_sm)
+{
+ AutoDecRef func(PyObject_GetAttr(ob_sm, PyMagicName::func()));
+ return _get_class_of_cf(func);
+}
+
+PyObject *_get_class_of_descr(PyObject *ob)
+{
+ return PyObject_GetAttr(ob, PyMagicName::objclass());
+}
+
+PyObject *_address_to_stringlist(PyObject *numkey)
+{
+ /*
+ * This is a tiny optimization that saves initialization time.
+ * Instead of creating all Python strings during the call to
+ * `PySide_BuildSignatureArgs`, we store the address of the stringlist.
+ * When needed in `PySide_BuildSignatureProps`, the strings are
+ * finally materialized.
+ */
+ Py_ssize_t address = PyNumber_AsSsize_t(numkey, PyExc_ValueError);
+ if (address == -1 && PyErr_Occurred())
+ return nullptr;
+ char **sig_strings = reinterpret_cast<char **>(address);
+ PyObject *res_list = PyList_New(0);
+ if (res_list == nullptr)
+ return nullptr;
+ for (; *sig_strings != nullptr; ++sig_strings) {
+ char *sig_str = *sig_strings;
+ AutoDecRef pystr(Py_BuildValue("s", sig_str));
+ if (pystr.isNull() || PyList_Append(res_list, pystr) < 0)
+ return nullptr;
+ }
+ return res_list;
+}
+
+int _build_func_to_type(PyObject *obtype)
+{
+ /*
+ * There is no general way to directly get the type of a static method.
+ * On Python 3, the type is hidden in an unused pointer in the
+ * PyCFunction structure, but the Limited API does not allow to access
+ * this, either.
+ *
+ * In the end, it was easier to avoid such tricks and build an explicit
+ * mapping from function to type.
+ *
+ * We walk through the method list of the type
+ * and record the mapping from static method to this type in a dict.
+ * We also check for hidden methods, see below.
+ */
+ auto *type = reinterpret_cast<PyTypeObject *>(obtype);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *dict = tpDict.object();
+
+ // PYSIDE-2404: Get the original dict for late initialization.
+ // The dict might have been switched before signature init.
+ static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type);
+ if (Py_TYPE(dict) != Py_TYPE(pyTypeType_tp_dict)) {
+ tpDict.reset(PyObject_GetAttr(dict, PyName::orig_dict()));
+ dict = tpDict.object();
+ }
+
+ PyMethodDef *meth = type->tp_methods;
+
+ if (meth == nullptr)
+ return 0;
+
+ for (; meth->ml_name != nullptr; meth++) {
+ /*
+ * It is possible that a method is overwritten by another
+ * attribute with the same name. This case was obviously provoked
+ * explicitly in "testbinding.TestObject.staticMethodDouble",
+ * where instead of the method a "PySide6.QtCore.Signal" object
+ * was in the dict.
+ * This overlap is also found in regular PySide under
+ * "PySide6.QtCore.QProcess.error" where again a signal object is
+ * returned. These hidden methods will be opened for the
+ * signature module by adding them under the name
+ * "{name}.overload".
+ */
+ PyObject *descr = PyDict_GetItemString(dict, meth->ml_name);
+ PyObject *look_attr = meth->ml_flags & METH_STATIC ? PyMagicName::func()
+ : PyMagicName::name();
+ int check_name = meth->ml_flags & METH_STATIC ? 0 : 1;
+ if (descr == nullptr)
+ return -1;
+
+ // We first check all methods if one is hidden by something else.
+ AutoDecRef look(PyObject_GetAttr(descr, look_attr));
+ AutoDecRef given(Py_BuildValue("s", meth->ml_name));
+ if (look.isNull()
+ || (check_name && PyObject_RichCompareBool(look, given, Py_EQ) != 1)) {
+ PyErr_Clear();
+ AutoDecRef cfunc(PyCFunction_NewEx(
+ meth, reinterpret_cast<PyObject *>(type), nullptr));
+ if (cfunc.isNull())
+ return -1;
+ if (meth->ml_flags & METH_STATIC)
+ descr = PyStaticMethod_New(cfunc);
+ else
+ descr = PyDescr_NewMethod(type, meth);
+ if (descr == nullptr)
+ return -1;
+ char mangled_name[200];
+ strcpy(mangled_name, meth->ml_name);
+ strcat(mangled_name, ".overload");
+ if (PyDict_SetItemString(dict, mangled_name, descr) < 0)
+ return -1;
+ if (meth->ml_flags & METH_STATIC) {
+ // This is the special case where a static method is hidden.
+ AutoDecRef special(Py_BuildValue("(Os)", cfunc.object(), "overload"));
+ if (PyDict_SetItem(pyside_globals->map_dict, special, obtype) < 0)
+ return -1;
+ }
+ if (PyDict_SetItemString(pyside_globals->map_dict, mangled_name, obtype) < 0)
+ return -1;
+ continue;
+ }
+ // Then we insert the mapping for static methods.
+ if (meth->ml_flags & METH_STATIC) {
+ if (PyDict_SetItem(pyside_globals->map_dict, look, obtype) < 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+} // extern "C"
diff --git a/sources/shiboken6/libshiboken/signature_p.h b/sources/shiboken6/libshiboken/signature_p.h
new file mode 100644
index 000000000..d0c4ee537
--- /dev/null
+++ b/sources/shiboken6/libshiboken/signature_p.h
@@ -0,0 +1,78 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SIGNATURE_IMPL_H
+#define SIGNATURE_IMPL_H
+
+#include "signature.h"
+
+extern "C" {
+
+// signature_globals.cpp
+
+struct safe_globals_struc {
+ // init part 1: get arg_dict
+ PyObject *helper_module;
+ PyObject *arg_dict;
+ PyObject *map_dict;
+ PyObject *value_dict; // for writing signatures
+ PyObject *feature_dict; // registry for PySide.support.__feature__
+ // init part 2: run module
+ PyObject *pyside_type_init_func;
+ PyObject *create_signature_func;
+ PyObject *seterror_argument_func;
+ PyObject *make_helptext_func;
+ PyObject *finish_import_func;
+ PyObject *feature_import_func;
+ PyObject *feature_imported_func;
+};
+
+extern safe_globals_struc *pyside_globals;
+extern PyMethodDef signature_methods[];
+
+void init_shibokensupport_module(void);
+
+// signature.cpp
+
+PyObject *GetTypeKey(PyObject *ob);
+
+PyObject *GetSignature_Function(PyObject *, PyObject *);
+PyObject *GetSignature_TypeMod(PyObject *, PyObject *);
+PyObject *GetSignature_Wrapper(PyObject *, PyObject *);
+
+LIBSHIBOKEN_API PyObject *get_signature_intern(PyObject *ob, PyObject *modifier);
+PyObject *PySide_BuildSignatureProps(PyObject *class_mod);
+PyObject *GetClassOrModOf(PyObject *ob);
+
+// signature_extend.cpp
+PyObject *pyside_cf_get___signature__(PyObject *func, PyObject *modifier);
+PyObject *pyside_sm_get___signature__(PyObject *sm, PyObject *modifier);
+PyObject *pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier);
+PyObject *pyside_wd_get___signature__(PyObject *ob, PyObject *modifier);
+PyObject *pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier);
+
+int PySide_PatchTypes(void);
+PyObject *pyside_tp_get___doc__(PyObject *tp);
+
+// signature_helper.cpp
+
+int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr);
+PyObject *name_key_to_func(PyObject *ob);
+int insert_snake_case_variants(PyObject *dict);
+PyObject *_get_class_of_cf(PyObject *ob_cf);
+PyObject *_get_class_of_sm(PyObject *ob_sm);
+PyObject *_get_class_of_descr(PyObject *ob);
+PyObject *_address_to_stringlist(PyObject *numkey);
+int _build_func_to_type(PyObject *obtype);
+int _finish_nested_classes(PyObject *dict);
+
+#ifdef PYPY_VERSION
+// PyPy has a special builtin method.
+PyObject *GetSignature_Method(PyObject *, PyObject *);
+PyObject *pyside_bm_get___signature__(PyObject *func, PyObject *modifier);
+PyObject *_get_class_of_bm(PyObject *ob_cf);
+#endif
+
+} // extern "C"
+
+#endif // SIGNATURE_IMPL_H
diff --git a/sources/shiboken6/libshiboken/threadstatesaver.cpp b/sources/shiboken6/libshiboken/threadstatesaver.cpp
new file mode 100644
index 000000000..9f74ed442
--- /dev/null
+++ b/sources/shiboken6/libshiboken/threadstatesaver.cpp
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "threadstatesaver.h"
+
+namespace Shiboken
+{
+
+ThreadStateSaver::ThreadStateSaver() = default;
+
+ThreadStateSaver::~ThreadStateSaver()
+{
+ restore();
+}
+
+void ThreadStateSaver::save()
+{
+ if (Py_IsInitialized())
+ m_threadState = PyEval_SaveThread();
+}
+
+void ThreadStateSaver::restore()
+{
+ if (m_threadState) {
+ PyEval_RestoreThread(m_threadState);
+ m_threadState = nullptr;
+ }
+}
+
+} // namespace Shiboken
+
diff --git a/sources/shiboken6/libshiboken/threadstatesaver.h b/sources/shiboken6/libshiboken/threadstatesaver.h
new file mode 100644
index 000000000..4289f6726
--- /dev/null
+++ b/sources/shiboken6/libshiboken/threadstatesaver.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef THREADSTATESAVER_H
+#define THREADSTATESAVER_H
+
+#include "sbkpython.h"
+#include <shibokenmacros.h>
+
+namespace Shiboken
+{
+
+class LIBSHIBOKEN_API ThreadStateSaver
+{
+public:
+ ThreadStateSaver(const ThreadStateSaver &) = delete;
+ ThreadStateSaver(ThreadStateSaver &&) = delete;
+ ThreadStateSaver &operator=(const ThreadStateSaver &) = delete;
+ ThreadStateSaver &operator=(ThreadStateSaver &&) = delete;
+
+ ThreadStateSaver();
+ ~ThreadStateSaver();
+ void save();
+ void restore();
+private:
+ PyThreadState *m_threadState = nullptr;
+};
+
+} // namespace Shiboken
+
+#endif // THREADSTATESAVER_H
+
diff --git a/sources/shiboken6/libshiboken/voidptr.cpp b/sources/shiboken6/libshiboken/voidptr.cpp
new file mode 100644
index 000000000..8bb3f6ac8
--- /dev/null
+++ b/sources/shiboken6/libshiboken/voidptr.cpp
@@ -0,0 +1,434 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "voidptr.h"
+#include "pep384ext.h"
+#include "sbkconverter.h"
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+
+extern "C"
+{
+
+// Void pointer object definition.
+struct SbkVoidPtrObject {
+ PyObject_HEAD
+ void *cptr;
+ Py_ssize_t size;
+ bool isWritable;
+};
+
+PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject * /* args */, PyObject * /* kwds */)
+{
+ // PYSIDE-560: It is much safer to first call a function and then do a
+ // type cast than to do everything in one line. The bad construct looked
+ // like this, actual call forgotten:
+ // SbkVoidPtrObject *self =
+ // reinterpret_cast<SbkVoidPtrObject *>(type->tp_alloc);
+ auto *self = PepExt_TypeCallAlloc<SbkVoidPtrObject>(type, 0);
+
+ if (self != nullptr) {
+ self->cptr = nullptr;
+ self->size = -1;
+ self->isWritable = false;
+ }
+
+ return reinterpret_cast<PyObject *>(self);
+}
+
+#define SbkVoidPtr_Check(op) (Py_TYPE(op) == SbkVoidPtr_TypeF())
+
+
+int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *addressObject;
+ Py_ssize_t size = -1;
+ int isWritable = 0;
+ auto *sbkSelf = reinterpret_cast<SbkVoidPtrObject *>(self);
+
+ static const char *kwlist[] = {"address", "size", "writeable", nullptr};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ni", const_cast<char **>(kwlist),
+ &addressObject, &size, &isWritable))
+ return -1;
+
+ // Void pointer.
+ if (SbkVoidPtr_Check(addressObject)) {
+ auto *sbkOther = reinterpret_cast<SbkVoidPtrObject *>(addressObject);
+ sbkSelf->cptr = sbkOther->cptr;
+ sbkSelf->size = sbkOther->size;
+ sbkSelf->isWritable = sbkOther->isWritable;
+ }
+ // Python buffer interface.
+ else if (PyObject_CheckBuffer(addressObject)) {
+ Py_buffer bufferView;
+
+ // Bail out if the object can't provide a simple contiguous buffer.
+ if (PyObject_GetBuffer(addressObject, &bufferView, PyBUF_SIMPLE) < 0)
+ return 0;
+
+ sbkSelf->cptr = bufferView.buf;
+ sbkSelf->size = bufferView.len > 0 ? bufferView.len : size;
+ sbkSelf->isWritable = bufferView.readonly <= 0;
+
+ // Release the buffer.
+ PyBuffer_Release(&bufferView);
+ }
+ // Shiboken::Object wrapper.
+ else if (Shiboken::Object::checkType(addressObject)) {
+ auto *sbkOther = reinterpret_cast<SbkObject *>(addressObject);
+ sbkSelf->cptr = sbkOther->d->cptr[0];
+ sbkSelf->size = size;
+ sbkSelf->isWritable = isWritable > 0;
+ }
+ // An integer representing an address.
+ else {
+ if (addressObject == Py_None) {
+ sbkSelf->cptr = nullptr;
+ sbkSelf->size = 0;
+ sbkSelf->isWritable = false;
+ }
+
+ else {
+ void *cptr = PyLong_AsVoidPtr(addressObject);
+ if (PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError,
+ "Creating a VoidPtr object requires an address of a C++ object, "
+ "a wrapped Shiboken Object type, "
+ "an object implementing the Python Buffer interface, "
+ "or another VoidPtr object.");
+ return -1;
+ }
+ sbkSelf->cptr = cptr;
+ sbkSelf->size = size;
+ sbkSelf->isWritable = isWritable > 0;
+ }
+ }
+
+ return 0;
+}
+
+PyObject *SbkVoidPtrObject_richcmp(PyObject *obj1, PyObject *obj2, int op)
+{
+ PyObject *result = Py_False;
+ void *cptr1 = nullptr;
+ void *cptr2 = nullptr;
+ bool validObjects = true;
+
+ if (SbkVoidPtr_Check(obj1))
+ cptr1 = reinterpret_cast<SbkVoidPtrObject *>(obj1)->cptr;
+ else
+ validObjects = false;
+
+ if (SbkVoidPtr_Check(obj2))
+ cptr2 = reinterpret_cast<SbkVoidPtrObject *>(obj2)->cptr;
+ else
+ validObjects = false;
+
+ if (validObjects) {
+ switch (op) {
+ case Py_EQ:
+ if (cptr1 == cptr2)
+ result = Py_True;
+ break;
+ case Py_NE:
+ if (cptr1 != cptr2)
+ result = Py_True;
+ break;
+ case Py_LT:
+ case Py_LE:
+ case Py_GT:
+ case Py_GE:
+ break;
+ }
+ }
+
+ Py_INCREF(result);
+ return result;
+}
+
+PyObject *SbkVoidPtrObject_int(PyObject *v)
+{
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v);
+ return PyLong_FromVoidPtr(sbkObject->cptr);
+}
+
+PyObject *toBytes(PyObject *self, PyObject * /* args */)
+{
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(self);
+ 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);
+ return bytes;
+}
+
+static struct PyMethodDef SbkVoidPtrObject_methods[] = {
+ {"toBytes", toBytes, METH_NOARGS, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+static Py_ssize_t SbkVoidPtrObject_length(PyObject *v)
+{
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v);
+ if (sbkObject->size < 0) {
+ PyErr_SetString(PyExc_IndexError, "VoidPtr does not have a size set.");
+ return -1;
+ }
+
+ return sbkObject->size;
+}
+
+static const char trueString[] = "True" ;
+static const char falseString[] = "False" ;
+
+PyObject *SbkVoidPtrObject_repr(PyObject *v)
+{
+
+
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v);
+ PyObject *s = PyUnicode_FromFormat("%s(%p, %zd, %s)",
+ Py_TYPE(sbkObject)->tp_name,
+ sbkObject->cptr,
+ sbkObject->size,
+ sbkObject->isWritable ? trueString : falseString);
+ Py_XINCREF(s);
+ return s;
+}
+
+PyObject *SbkVoidPtrObject_str(PyObject *v)
+{
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v);
+ PyObject *s = PyUnicode_FromFormat("%s(Address %p, Size %zd, isWritable %s)",
+ Py_TYPE(sbkObject)->tp_name,
+ sbkObject->cptr,
+ sbkObject->size,
+ sbkObject->isWritable ? trueString : falseString);
+ Py_XINCREF(s);
+ return s;
+}
+
+
+static int SbkVoidPtrObject_getbuffer(PyObject *obj, Py_buffer *view, int flags)
+{
+ if (view == nullptr)
+ return -1;
+
+ auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(obj);
+ if (sbkObject->size < 0)
+ return -1;
+
+ int readonly = sbkObject->isWritable ? 0 : 1;
+ if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) &&
+ (readonly == 1)) {
+ PyErr_SetString(PyExc_BufferError,
+ "Object is not writable.");
+ return -1;
+ }
+
+ view->obj = obj;
+ if (obj)
+ Py_XINCREF(obj);
+ view->buf = sbkObject->cptr;
+ view->len = sbkObject->size;
+ view->readonly = readonly;
+ view->itemsize = 1;
+ view->format = nullptr;
+ if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
+ view->format = const_cast<char *>("B");
+ view->ndim = 1;
+ view->shape = nullptr;
+ if ((flags & PyBUF_ND) == PyBUF_ND)
+ view->shape = &(view->len);
+ view->strides = nullptr;
+ if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
+ view->strides = &(view->itemsize);
+ view->suboffsets = nullptr;
+ view->internal = nullptr;
+ return 0;
+}
+
+static PyBufferProcs SbkVoidPtrObjectBufferProc = {
+ (getbufferproc)SbkVoidPtrObject_getbuffer, // bf_getbuffer
+ (releasebufferproc)nullptr // bf_releasebuffer
+};
+
+static PyTypeObject *createVoidPtrType()
+{
+ PyType_Slot SbkVoidPtrType_slots[] = {
+ {Py_tp_repr, reinterpret_cast<void *>(SbkVoidPtrObject_repr)},
+ {Py_nb_int, reinterpret_cast<void *>(SbkVoidPtrObject_int)},
+ {Py_sq_length, reinterpret_cast<void *>(SbkVoidPtrObject_length)},
+ {Py_tp_str, reinterpret_cast<void *>(SbkVoidPtrObject_str)},
+ {Py_tp_richcompare, reinterpret_cast<void *>(SbkVoidPtrObject_richcmp)},
+ {Py_tp_init, reinterpret_cast<void *>(SbkVoidPtrObject_init)},
+ {Py_tp_new, reinterpret_cast<void *>(SbkVoidPtrObject_new)},
+ {Py_tp_dealloc, reinterpret_cast<void *>(Sbk_object_dealloc)},
+ {Py_tp_methods, reinterpret_cast<void *>(SbkVoidPtrObject_methods)},
+ {0, nullptr}
+ };
+
+ PyType_Spec SbkVoidPtrType_spec = {
+ "2:shiboken6.Shiboken.VoidPtr",
+ sizeof(SbkVoidPtrObject),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ SbkVoidPtrType_slots,
+ };
+
+ return SbkType_FromSpec_BMDWB(&SbkVoidPtrType_spec,
+ nullptr, nullptr, 0, 0,
+ &SbkVoidPtrObjectBufferProc);
+}
+
+PyTypeObject *SbkVoidPtr_TypeF(void)
+{
+ static auto *type = createVoidPtrType();
+ return type;
+}
+
+} // extern "C"
+
+namespace VoidPtr {
+
+static int voidPointerInitialized = false;
+
+void init()
+{
+ if (PyType_Ready(SbkVoidPtr_TypeF()) < 0)
+ Py_FatalError("[libshiboken] Failed to initialize Shiboken.VoidPtr type.");
+ else
+ voidPointerInitialized = true;
+}
+
+void addVoidPtrToModule(PyObject *module)
+{
+ if (voidPointerInitialized) {
+ Py_INCREF(SbkVoidPtr_TypeF());
+ PyModule_AddObject(module, PepType_GetNameStr(SbkVoidPtr_TypeF()),
+ reinterpret_cast<PyObject *>(SbkVoidPtr_TypeF()));
+ }
+}
+
+static PyObject *createVoidPtr(void *cppIn, Py_ssize_t size = 0, bool isWritable = false)
+{
+ if (!cppIn)
+ Py_RETURN_NONE;
+
+ SbkVoidPtrObject *result = PyObject_New(SbkVoidPtrObject, SbkVoidPtr_TypeF());
+ if (!result)
+ Py_RETURN_NONE;
+
+ result->cptr = cppIn;
+ result->size = size;
+ result->isWritable = isWritable;
+
+ return reinterpret_cast<PyObject *>(result);
+}
+
+static PyObject *toPython(const void *cppIn)
+{
+ return createVoidPtr(const_cast<void *>(cppIn));
+}
+
+static void VoidPtrToCpp(PyObject *pyIn, void *cppOut)
+{
+ auto *sbkIn = reinterpret_cast<SbkVoidPtrObject *>(pyIn);
+ *reinterpret_cast<void **>(cppOut) = sbkIn->cptr;
+}
+
+static PythonToCppFunc VoidPtrToCppIsConvertible(PyObject *pyIn)
+{
+ return SbkVoidPtr_Check(pyIn) ? VoidPtrToCpp : nullptr;
+}
+
+static void SbkObjectToCpp(PyObject *pyIn, void *cppOut)
+{
+ auto *sbkIn = reinterpret_cast<SbkObject *>(pyIn);
+ *reinterpret_cast<void **>(cppOut) = sbkIn->d->cptr[0];
+}
+
+static PythonToCppFunc SbkObjectToCppIsConvertible(PyObject *pyIn)
+{
+ return Shiboken::Object::checkType(pyIn) ? SbkObjectToCpp : nullptr;
+}
+
+static void PythonBufferToCpp(PyObject *pyIn, void *cppOut)
+{
+ if (PyObject_CheckBuffer(pyIn)) {
+ Py_buffer bufferView;
+
+ // Bail out if the object can't provide a simple contiguous buffer.
+ if (PyObject_GetBuffer(pyIn, &bufferView, PyBUF_SIMPLE) < 0)
+ return;
+
+ *reinterpret_cast<void **>(cppOut) = bufferView.buf;
+
+ // Release the buffer.
+ PyBuffer_Release(&bufferView);
+ }
+}
+
+static PythonToCppFunc PythonBufferToCppIsConvertible(PyObject *pyIn)
+{
+ if (PyObject_CheckBuffer(pyIn)) {
+ Py_buffer bufferView;
+
+ // Bail out if the object can't provide a simple contiguous buffer.
+ if (PyObject_GetBuffer(pyIn, &bufferView, PyBUF_SIMPLE) < 0)
+ return nullptr;
+
+ // Release the buffer.
+ PyBuffer_Release(&bufferView);
+
+ return PythonBufferToCpp;
+ }
+ return nullptr;
+}
+
+SbkConverter *createConverter()
+{
+ SbkConverter *converter = Shiboken::Conversions::createConverter(SbkVoidPtr_TypeF(), toPython);
+ Shiboken::Conversions::addPythonToCppValueConversion(converter,
+ VoidPtrToCpp,
+ VoidPtrToCppIsConvertible);
+ Shiboken::Conversions::addPythonToCppValueConversion(converter,
+ SbkObjectToCpp,
+ SbkObjectToCppIsConvertible);
+ Shiboken::Conversions::addPythonToCppValueConversion(converter,
+ PythonBufferToCpp,
+ PythonBufferToCppIsConvertible);
+ return converter;
+}
+
+void setSize(PyObject *voidPtr, Py_ssize_t size)
+{
+ assert(voidPtr->ob_type == SbkVoidPtr_TypeF());
+ auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr);
+ voidPtrObj->size = size;
+}
+
+Py_ssize_t getSize(PyObject *voidPtr)
+{
+ assert(voidPtr->ob_type == SbkVoidPtr_TypeF());
+ auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr);
+ return voidPtrObj->size;
+}
+
+bool isWritable(PyObject *voidPtr)
+{
+ assert(voidPtr->ob_type == SbkVoidPtr_TypeF());
+ auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr);
+ return voidPtrObj->isWritable;
+}
+
+void setWritable(PyObject *voidPtr, bool isWritable)
+{
+ assert(voidPtr->ob_type == SbkVoidPtr_TypeF());
+ auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr);
+ voidPtrObj->isWritable = isWritable;
+}
+
+} // namespace VoidPtr
diff --git a/sources/shiboken6/libshiboken/voidptr.h b/sources/shiboken6/libshiboken/voidptr.h
new file mode 100644
index 000000000..8360bf9c7
--- /dev/null
+++ b/sources/shiboken6/libshiboken/voidptr.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef VOIDPTR_H
+#define VOIDPTR_H
+
+#include "sbkpython.h"
+#include "shibokenmacros.h"
+#include "sbkconverter.h"
+
+extern "C"
+{
+
+// Void pointer type declaration.
+extern LIBSHIBOKEN_API PyTypeObject *SbkVoidPtr_TypeF(void);
+
+} // extern "C"
+
+namespace VoidPtr
+{
+
+void init();
+SbkConverter *createConverter();
+LIBSHIBOKEN_API void addVoidPtrToModule(PyObject *module);
+
+LIBSHIBOKEN_API void setSize(PyObject *voidPtr, Py_ssize_t size);
+LIBSHIBOKEN_API Py_ssize_t getSize(PyObject *voidPtr);
+LIBSHIBOKEN_API bool isWritable(PyObject *voidPtr);
+LIBSHIBOKEN_API void setWritable(PyObject *voidPtr, bool isWritable);
+}
+
+
+#endif // VOIDPTR_H
diff --git a/sources/shiboken6/shiboken_tool.py b/sources/shiboken6/shiboken_tool.py
new file mode 100755
index 000000000..30d334f44
--- /dev/null
+++ b/sources/shiboken6/shiboken_tool.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+import sys
+import os
+import subprocess
+from pathlib import Path
+
+
+def main():
+ # The tools listed as entrypoints in setup.py are copied to 'scripts/..'
+ cmd = Path("..") / Path(sys.argv[0]).name
+ command = [os.fspath(Path(__file__).parent.resolve() / cmd)]
+ command.extend(sys.argv[1:])
+ sys.exit(subprocess.call(command))
+
+
+def genpyi():
+ # After we changed the shibokensupport module to be totally virtual,
+ # it is no longer possible to call the pyi generator from the file system.
+ command = [sys.executable, "-c",
+ "import shiboken6;"
+ "from shibokensupport.signature.lib.pyi_generator import main;"
+ "main()"] + sys.argv[1:]
+ sys.exit(subprocess.call(command))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/sources/shiboken6/shiboken_version.py b/sources/shiboken6/shiboken_version.py
new file mode 100644
index 000000000..07b247316
--- /dev/null
+++ b/sources/shiboken6/shiboken_version.py
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+major_version = "@shiboken_MAJOR_VERSION@"
+minor_version = "@shiboken_MINOR_VERSION@"
+patch_version = "@shiboken_MICRO_VERSION@"
+
+# For example: "a", "b", "rc"
+# (which means "alpha", "beta", "release candidate").
+# An empty string means the generated package will be an official release.
+release_version_type = "@shiboken_PRE_RELEASE_VERSION_TYPE@"
+
+# For example: "1", "2" (which means "beta1", "beta2", if type is "b").
+pre_release_version = "@shiboken_PRE_RELEASE_VERSION@"
+
+if __name__ == '__main__':
+ # Used by CMake.
+ print(f'{major_version};{minor_version};{patch_version};'
+ f'{release_version_type};{pre_release_version}')
diff --git a/sources/shiboken6/shibokenmodule/CMakeLists.txt b/sources/shiboken6/shibokenmodule/CMakeLists.txt
new file mode 100644
index 000000000..702750450
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/CMakeLists.txt
@@ -0,0 +1,84 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(shibokenmodule)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/shibokenmodule.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/shibokenmodule.txt" @ONLY)
+
+set(sample_SRC ${CMAKE_CURRENT_BINARY_DIR}/Shiboken/shiboken_module_wrapper.cpp)
+
+set(shibokenmodule_TYPESYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/typesystem_shiboken.xml)
+
+shiboken_get_tool_shell_wrapper(shiboken tool_wrapper)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+ BYPRODUCTS ${sample_SRC}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Shiboken6::shiboken6>
+ --project-file=${CMAKE_CURRENT_BINARY_DIR}/shibokenmodule.txt
+ ${GENERATOR_EXTRA_FLAGS}
+ DEPENDS ${shibokenmodule_TYPESYSTEM}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Running generator for 'Shiboken'..."
+)
+
+add_library(shibokenmodule MODULE ${sample_SRC})
+target_include_directories(shibokenmodule PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR})
+
+set_target_properties(shibokenmodule PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "Shiboken${PYTHON_EXTENSION_SUFFIX}"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..")
+
+if(WIN32)
+ set_property(TARGET shibokenmodule PROPERTY SUFFIX ".pyd")
+endif()
+target_link_libraries(shibokenmodule PUBLIC libshiboken)
+
+create_generator_target(shibokenmodule)
+
+qfp_strip_library("shibokenmodule")
+
+install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}/shiboken6)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/_config.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/_config.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken6")
+
+if ("${MINIMUM_PYTHON_VERSION}" STREQUAL "")
+ set(MINIMUM_PYTHON_VERSION None)
+ set(MAXIMUM_PYTHON_VERSION None)
+endif()
+
+# PYSIDE-1497: This `..` is the crucial trick to unify the path location of `Shiboken`.
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../__init__.py" @ONLY)
+# PYSIDE-1415: Copy Shiboken.pyi into the target.
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Shiboken.pyi"
+ "${CMAKE_CURRENT_BINARY_DIR}/../Shiboken.pyi" @ONLY)
+# typing support for mypy
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/py.typed.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/../py.typed" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/../Shiboken.pyi"
+ "${CMAKE_CURRENT_BINARY_DIR}/../py.typed"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken6")
+
+# PYSIDE-1497: This `..` is the crucial trick to unify the path location of `Shiboken`.
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/../__init__.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken6")
+
+# Use absolute path instead of relative path, to avoid ninja build errors due to
+# duplicate file dependency inconsistency.
+set(shiboken_version_relative_path "${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_version.py")
+get_filename_component(shiboken_version_path ${shiboken_version_relative_path} ABSOLUTE)
+configure_file("${shiboken_version_path}"
+ "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_module_version.py" @ONLY)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_module_version.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken6")
diff --git a/sources/shiboken6/shibokenmodule/Shiboken.pyi b/sources/shiboken6/shibokenmodule/Shiboken.pyi
new file mode 100644
index 000000000..6a1a63217
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/Shiboken.pyi
@@ -0,0 +1,37 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+from __future__ import annotations
+
+"""
+This file contains the exact signatures for all functions in module
+Shiboken, except for defaults which are replaced by "...".
+"""
+
+# Module `Shiboken`
+
+from shiboken6 import Shiboken
+
+
+class Object(object):
+
+ def __init__(self) -> None: ...
+
+
+class VoidPtr(object):
+ def __init__(self, value: int) -> None: ...
+
+
+def _unpickle_enum(arg__1: object, arg__2: object) -> object: ...
+def createdByPython(arg__1: Shiboken.Object) -> bool: ...
+def delete(arg__1: Shiboken.Object) -> None: ...
+def dump(arg__1: object) -> str: ...
+def getAllValidWrappers() -> list[Shiboken.Object]: ...
+def getCppPointer(arg__1: Shiboken.Object) -> tuple[int, ...]: ...
+def invalidate(arg__1: Shiboken.Object) -> None: ...
+def isValid(arg__1: object) -> bool: ...
+def ownedByPython(arg__1: Shiboken.Object) -> bool: ...
+def wrapInstance(arg__1: int, arg__2: type) -> Shiboken.Object: ...
+
+
+# eof
diff --git a/sources/shiboken6/shibokenmodule/__init__.py.in b/sources/shiboken6/shibokenmodule/__init__.py.in
new file mode 100644
index 000000000..c859160bc
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/__init__.py.in
@@ -0,0 +1,27 @@
+__version__ = "@FINAL_PACKAGE_VERSION@"
+__version_info__ = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+__minimum_python_version__ = @MINIMUM_PYTHON_VERSION@
+__maximum_python_version__ = @MAXIMUM_PYTHON_VERSION@
+
+# PYSIDE-932: Python 2 cannot import 'zipfile' for embedding while being imported, itself.
+# We simply pre-load all imports for the signature extension.
+# Also, PyInstaller seems not always to be reliable in finding modules.
+# We explicitly import everything that is needed:
+import sys
+import os
+import zipfile
+import base64
+import marshal
+import io
+import contextlib
+import textwrap
+import traceback
+import types
+import struct
+import re
+import tempfile
+import keyword
+import functools
+import typing
+
+from shiboken6.Shiboken import *
diff --git a/sources/shiboken6/shibokenmodule/_config.py.in b/sources/shiboken6/shibokenmodule/_config.py.in
new file mode 100644
index 000000000..600c431c9
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/_config.py.in
@@ -0,0 +1,12 @@
+shiboken_library_soversion = str(@shiboken6_library_so_version@)
+
+version = "@FINAL_PACKAGE_VERSION@"
+version_info = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+
+@PACKAGE_BUILD_DATE@
+@PACKAGE_BUILD_COMMIT_DATE@
+@PACKAGE_BUILD_COMMIT_HASH@
+@PACKAGE_BUILD_COMMIT_HASH_DESCRIBED@
+@PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
+@PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT@
+@QT_MACOS_DEPLOYMENT_TARGET@
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py
new file mode 100644
index 000000000..e54bec75a
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/__init__.py
@@ -0,0 +1,4 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+# this file intentionally left blank
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py
new file mode 100644
index 000000000..7a0871ee7
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py
@@ -0,0 +1,248 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+# flake8: noqa F:821
+# flake8: noqa F:401
+
+"""
+__feature__.py (renamed to feature.py)
+
+This is the feature file for the Qt for Python project. There is some
+similarity to Python's `__future__` file, but also some distinction.
+
+The normal usage is like
+
+ from __feature__ import <feature_name> [, ...]
+ ...
+
+Alternatively, there is the `set_selection` function which uses select_id's
+and takes an optional `mod_name` parameter.
+
+The select id `-1` has the special meaning "ignore this module".
+"""
+
+import inspect
+import sys
+from contextlib import contextmanager
+
+all_feature_names = [
+ "snake_case",
+ "true_property",
+ "_feature_04",
+ "_feature_08",
+ "_feature_10",
+ "_feature_20",
+ "_feature_40",
+ "_feature_80",
+]
+
+__all__ = ["all_feature_names", "info", "reset", "set_selection"] + all_feature_names
+
+snake_case = 0x01
+true_property = 0x02
+_feature_04 = 0x04
+_feature_08 = 0x08
+_feature_10 = 0x10
+_feature_20 = 0x20
+_feature_40 = 0x40
+_feature_80 = 0x80
+
+# let's remove the dummies for the normal user
+_really_all_feature_names = all_feature_names[:]
+all_feature_names = list(_ for _ in all_feature_names if not _.startswith("_"))
+
+# Install an import hook that controls the `__feature__` import.
+"""
+Note: This are two imports.
+>>> import dis
+>>> def test():
+... from __feature__ import snake_case
+...
+>>> dis.dis(test)
+ 2 0 LOAD_CONST 1 (0)
+ 2 LOAD_CONST 2 (('snake_case',))
+ 4 IMPORT_NAME 0 (__feature__)
+ 6 IMPORT_FROM 1 (snake_case)
+ 8 STORE_FAST 0 (snake_case)
+ 10 POP_TOP
+ 12 LOAD_CONST 0 (None)
+ 14 RETURN_VALUE
+"""
+
+"""
+The redirection of __import__
+-----------------------------
+
+This construction avoids irritating extra redirections in tracebacks.
+
+The normal `__import__` is replaced by C function `__feature_import__`.
+`__feature_import__` calls this `feature_import` function first, to
+see if a feature is requested. If this function does not handle it, it returns
+None to indicate that a normal import should be performed, and
+`__feature_import__` calls the original import `__orig_import__`.
+All these variables are transparently kept in module `builtins`.
+"""
+
+
+def feature_import(name, *args, **kwargs):
+ # PYSIDE-1368: The `__name__` attribute does not need to exist in all modules.
+ # PYSIDE-1398: sys._getframe(1) may not exist when embedding.
+ # PYSIDE-1338: The "1" below is the redirection in loader.py .
+ # PYSIDE-1548: Ensure that features are not affected by other imports.
+ # PYSIDE-2029: Need to always switch. The cache was wrong interpreted.
+ calling_frame = _cf = sys._getframe(1).f_back
+ importing_module = _cf.f_globals.get("__name__", "__main__") if _cf else "__main__"
+ existing = pyside_feature_dict.get(importing_module, 0)
+
+ if name == "__feature__" and args[2]:
+ __init__()
+
+ # This is an `import from` statement that corresponds to `IMPORT_NAME`.
+ # The following `IMPORT_FROM` will handle errors. (Confusing, ofc.)
+ flag = get_select_id(args[2])
+
+ flag |= existing & 255 if isinstance(existing, int) and existing >= 0 else 0
+ pyside_feature_dict[importing_module] = flag
+
+ if importing_module == "__main__":
+ # We need to add all modules here which should see __feature__.
+ pyside_feature_dict["rlcompleter"] = flag
+
+ # Initialize feature (multiple times allowed) and clear cache.
+ sys.modules["PySide6.QtCore"].__init_feature__()
+ return sys.modules["__feature__"]
+ # Redirect to the original import
+ return None
+
+
+_is_initialized = False
+
+
+def __init__():
+ global _is_initialized
+ if not _is_initialized:
+ # use _one_ recursive import...
+ import PySide6.QtCore
+ # Initialize all prior imported modules
+ for name, module in sys.modules.items():
+ if name not in pyside_feature_dict:
+ pyside_feature_dict[name] = 0 if _mod_uses_pyside(module) else -1
+ _is_initialized = True
+
+
+def feature_imported(module):
+ # PYSIDE-2029: Need to inspect imported modules for PySide usage.
+ """
+ Set the module feature default after import.
+
+ A module that uses PySide has a switching default of 0 = "no feature".
+ Otherwise the default is -1 = "ignore this module".
+ """
+
+ # PYSIDE-1368: The `__name__` attribute does not need to exist in all modules.
+ if hasattr(module, "__name__"):
+ name = module.__name__
+ if name not in pyside_feature_dict:
+ pyside_feature_dict[name] = 0 if _mod_uses_pyside(module) else -1
+
+
+def _mod_uses_pyside(module):
+ """
+ Find out if this module uses PySide.
+
+ Simple approach: Search the source code for the string "PySide6".
+ Maybe we later support source-less modules by inspecting all code objects.
+ """
+ try:
+ source = inspect.getsource(module)
+ except TypeError:
+ # this is a builtin module like sys
+ return False
+ except OSError:
+ # this is a module withot source file
+ return False
+ except SyntaxError:
+ # PYSIDE-2189: A UnicodeError happens in tokenize.py in find_cookie
+ # which is then creating a SyntaxError in inspect.
+ # This is undocumented and a Python error, seen in Python 3.10.2 on Windows,
+ # importing `pythoncom` of the win32 package.
+ return False
+ except Exception:
+ # PYSIDE-2393: pytest behaves weird when allowing any other error.
+ return False
+ return "PySide6" in source
+
+
+def set_selection(select_id, mod_name=None):
+ """
+ Internal use: Set the feature directly by Id.
+ Id == -1: ignore this module in switching.
+ """
+ mod_name = mod_name or sys._getframe(1).f_globals['__name__']
+ __init__()
+ # Reset the features to the given id
+ flag = 0
+ if isinstance(select_id, int):
+ flag = select_id & 255
+ pyside_feature_dict[mod_name] = flag
+ sys.modules["PySide6.QtCore"].__init_feature__()
+ return _current_selection(flag)
+
+
+# The set_section(0) case seems to be unsafe. We will migrate to
+# use the opaque feature.reset() call in all test cases.
+def reset():
+ set_selection(0)
+ pyside_feature_dict.clear()
+ _is_initialized = False
+
+
+def info(mod_name=None):
+ """
+ Internal use: Return the current selection
+ """
+ mod_name = mod_name or sys._getframe(1).f_globals['__name__']
+ flag = pyside_feature_dict.get(mod_name, 0)
+ return _current_selection(flag)
+
+
+def _current_selection(flag):
+ names = []
+ if flag >= 0:
+ for idx, name in enumerate(_really_all_feature_names):
+ if (1 << idx) & flag:
+ names.append(name)
+ return names
+
+
+def get_select_id(feature_names):
+ flag = 0
+ for feature in feature_names:
+ if feature in _really_all_feature_names:
+ flag |= globals()[feature]
+ else:
+ raise SyntaxError(f"PySide feature {feature} is not defined")
+ return flag
+
+
+@contextmanager
+def force_selection(select_id, mod_name):
+ """
+ This function is for generating pyi files with features.
+ The selection id is set globally after performing the unswitched
+ import.
+
+ """
+ __init__()
+ saved_feature_dict = pyside_feature_dict.copy()
+ for name in pyside_feature_dict:
+ set_selection(0, name)
+ __import__(mod_name)
+ for name in pyside_feature_dict.copy():
+ set_selection(select_id, name)
+ try:
+ yield
+ finally:
+ pyside_feature_dict.update(saved_feature_dict)
+
+#eof
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py
new file mode 100644
index 000000000..f7190b12f
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py
@@ -0,0 +1,59 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+fix-complaints.py
+
+This module fixes the buildbot messages of external python files.
+Run it once after copying a new version. It is idem-potent, unless
+you are changing messages (what I did, of course :-) .
+"""
+
+import glob
+from pathlib import Path
+
+patched_file_patterns = "backport_inspect.py typing27.py python_minilib_*.py"
+
+offending_words = {
+ "behavio""ur": "behavior",
+ "at""least": "at_least",
+ "reali""sed": "realized",
+}
+
+utf8_line = "# This Python file uses the following encoding: utf-8\n"
+marker_line = f"# It has been edited by {Path(__file__).name} .\n"
+
+
+def patch_file(fname):
+ with fname.open() as f:
+ lines = f.readlines()
+ dup = lines[:]
+ for idx, line in enumerate(lines):
+ for word, repl in offending_words.items():
+ if word in line:
+ lines[idx] = line.replace(word, repl)
+ print(f"line:{line!r} {word!r}->{repl!r}")
+ if lines[0].strip() != utf8_line.strip():
+ lines[:0] = [utf8_line, "\n"]
+ if lines[1] != marker_line:
+ lines[1:1] = marker_line
+ if lines != dup:
+ with open(fname, "w") as f:
+ f.write("".join(lines))
+
+
+def doit():
+ dirname = Path(__file__).parent
+ patched_files = []
+ for name in patched_file_patterns.split():
+ pattern = dirname / name
+ patched_files += glob.glob(pattern)
+ for fname in patched_files:
+ print("Working on", fname)
+ patch_file(fname)
+
+
+if __name__ == "__main__":
+ doit()
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/shibokensupport.pyproject b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/shibokensupport.pyproject
new file mode 100644
index 000000000..7147a4148
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/shibokensupport.pyproject
@@ -0,0 +1,16 @@
+{
+ "files": ["__init__.py",
+ "feature.py",
+ "fix-complaints.py",
+ "signature/__init__.py",
+ "signature/errorhandler.py",
+ "signature/importhandler.py",
+ "signature/layout.py",
+ "signature/lib/__init__.py",
+ "signature/lib/enum_sig.py",
+ "signature/lib/pyi_generator.py",
+ "signature/lib/tool.py",
+ "signature/loader.py",
+ "signature/mapping.py",
+ "signature/parser.py"]
+}
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt
new file mode 100644
index 000000000..be42010dd
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt
@@ -0,0 +1,43 @@
+PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+ the Individual or Organization ("Licensee") accessing and otherwise using Python
+ 3.7.0 software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python 3.7.0 alone or in any derivative
+ version, provided, however, that PSF's License Agreement and PSF's notice of
+ copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+ Reserved" are retained in Python 3.7.0 alone or in any derivative version
+ prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates Python 3.7.0 or any part thereof, and wants to make the
+ derivative work available to others as provided herein, then Licensee hereby
+ agrees to include in any such work a brief summary of the changes made to Python
+ 3.7.0.
+
+4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+ PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+ EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+ USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+ its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between PSF and Licensee. This License
+ Agreement does not grant permission to use PSF trademarks or trade name in a
+ trademark sense to endorse or promote products or services of Licensee, or any
+ third party.
+
+8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+ to be bound by the terms and conditions of this License Agreement.
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py
new file mode 100644
index 000000000..bebf56c7e
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/__init__.py
@@ -0,0 +1,4 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+__all__ = "get_signature layout mapping lib".split()
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
new file mode 100644
index 000000000..c2a19efef
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
@@ -0,0 +1,150 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+# flake8: noqa E:721
+
+"""
+errorhandler.py
+
+This module handles the TypeError messages which were previously
+produced by the generated C code.
+
+This version is at least consistent with the signatures, which
+are created by the same module.
+
+Experimentally, we are trying to guess those errors which are
+just the wrong number of elements in an iterator.
+At the moment, it is unclear whether the information given is
+enough to produce a useful ValueError.
+
+This matter will be improved in a later version.
+"""
+
+import collections.abc
+import typing
+
+from shibokensupport.signature import get_signature
+from shibokensupport.signature.mapping import namespace
+from textwrap import dedent
+
+
+def qt_isinstance(inst, the_type):
+ if the_type == float:
+ # Qt thinks differently about int and float - simply keep it.
+ return isinstance(inst, int) or isinstance(inst, float)
+ if the_type.__module__ == "typing":
+ if the_type is typing.Any:
+ return True
+ if the_type.__origin__ is typing.Union:
+ return any(qt_isinstance(inst, _) for _ in the_type.__args__)
+ if the_type.__origin__ in (collections.abc.Sequence,
+ collections.abc.Iterable):
+ try:
+ return all(qt_isinstance(_, the_type.__args__[0]) for _ in inst)
+ except TypeError:
+ return False
+ try:
+ return isinstance(inst, the_type)
+ except TypeError as e:
+ print(f"FIXME qt_isinstance({inst}, {the_type}):", e)
+ return False
+
+
+def matched_type(args, sigs):
+ for sig in sigs:
+ params = list(sig.parameters.values())
+ if len(args) > len(params):
+ continue
+ if len(args) < len(params):
+ k = len(args)
+ if params[k].default is params[k].empty:
+ # this is a necessary parameter, so it fails.
+ continue
+ if all(qt_isinstance(arg, param.annotation) for arg, param in zip(args, params)):
+ return sig
+ return None
+
+
+def seterror_argument(args, func_name, info):
+ func = None
+ try:
+ func = eval(func_name, namespace)
+ except Exception as e:
+ msg = f"Error evaluating `{func_name}`: {e}"
+ return type(e), msg
+ if info and type(info) is str:
+ err = TypeError
+ if info == "<":
+ msg = f"{func_name}(): not enough arguments"
+ elif info == "0":
+ msg = (f"{func_name}(): not enough arguments. "
+ "Note: keyword arguments are only supported for optional parameters.")
+ elif info == ">":
+ msg = f"{func_name}(): too many arguments"
+ elif info.isalnum():
+ msg = f"{func_name}(): got multiple values for keyword argument '{info}'"
+ else:
+ msg = f"{func_name}(): {info}"
+ err = AttributeError
+ return err, msg
+ if isinstance(info, Exception):
+ # PYSIDE-2230: Python 3.12 seems to always do normalization.
+ err = type(info)
+ info = info.args[0]
+ msg = f"{func_name}(): {info}"
+ return err, msg
+ if info and type(info) is dict:
+ msg = f"{func_name}(): unsupported keyword '{tuple(info)[0]}'"
+ return AttributeError, msg
+ sigs = get_signature(func, "typeerror")
+ if not sigs:
+ msg = f"{func_name}({args}) is wrong (missing signature)"
+ return TypeError, msg
+ if type(sigs) != list:
+ sigs = [sigs]
+ if type(args) != tuple:
+ args = (args,)
+ # temp!
+ found = matched_type(args, sigs)
+ if found:
+ msg = dedent(f"""
+ {func_name!r} called with wrong argument values:
+ {func_name}{args}
+ Found signature:
+ {func_name}{found}
+ """).strip()
+ return ValueError, msg
+ type_str = ", ".join(type(arg).__name__ for arg in args)
+ msg = dedent(f"""
+ {func_name!r} called with wrong argument types:
+ {func_name}({type_str})
+ Supported signatures:
+ """).strip()
+ for sig in sigs:
+ msg += f"\n {func_name}{sig}"
+ # We don't raise the error here, to avoid the loader in the traceback.
+ return TypeError, msg
+
+
+def check_string_type(s):
+ return isinstance(s, str)
+
+
+def make_helptext(func):
+ existing_doc = func.__doc__
+ if existing_doc is None and hasattr(func, "__dict__"):
+ existing_doc = func.__dict__.get("__doc__")
+ sigs = get_signature(func)
+ if not sigs:
+ return existing_doc
+ if type(sigs) != list:
+ sigs = [sigs]
+ try:
+ func_name = func.__name__
+ except AttributeError:
+ func_name = func.__func__.__name__
+ sigtext = "\n".join(func_name + str(sig) for sig in sigs)
+ msg = f"{sigtext}\n\n{existing_doc}" if check_string_type(existing_doc) else sigtext
+ return msg
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
new file mode 100644
index 000000000..bae264294
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
@@ -0,0 +1,65 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+importhandler.py
+
+This module handles special actions after the import of PySide modules.
+The reason for this was the wish to replace some deprecated functions
+by a Python implementation that gives a warning.
+
+It provides a framework to safely call functions outside of files.dir,
+because the implementation of deprecated functions should be visible
+to the users (in the hope they don't use it any longer <wink>).
+
+As a first approach, the function finish_import redirects to
+PySide6/support/deprecated.py . There can come other extensions as well.
+"""
+
+try:
+ from PySide6.support import deprecated
+ have_deprecated = True
+except ImportError:
+ have_deprecated = False
+
+
+# called by loader.py from signature.cpp
+def finish_import(module):
+ if have_deprecated and module.__name__.startswith("PySide6."):
+ try:
+ name = "fix_for_" + module.__name__.split(".")[1]
+ func = getattr(deprecated, name, None)
+ if func:
+ func(module)
+ except Exception as e:
+ name = e.__class__.__qualname__
+ print(72 * "*")
+ print("Error in deprecated.py, ignored:")
+ print(f" {name}: {e}")
+
+
+"""
+A note for people who might think this could be written in pure Python:
+
+Sure, by an explicit import of the modules to patch, this is no problem.
+But in the general case, a module should only be imported on user
+request and not because we want to patch it. So I started over.
+
+I then tried to do it on demand by redirection of the __import__ function.
+Things worked quite nicely as it seemed, but at second view this solution
+was much less appealing.
+
+Reason:
+If someone executes as the first PySide statement
+
+ from PySide6 import QtGui
+
+then this import is already running. We can see the other imports like the
+diverse initializations and QtCore, because it is triggered by import of
+QtGui. But the QtGui import can not be seen at all!
+
+With a lot of effort, sys.setprofile() and stack inspection with the inspect
+module, it is *perhaps* possible to solve that. I tried for a day and then
+gave up, since the solution is anyway not too nice when __import__ must
+be overridden.
+"""
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
new file mode 100644
index 000000000..0e781cbcb
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
@@ -0,0 +1,247 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+layout.py
+
+The signature module now has the capability to configure
+differently formatted versions of signatures. The default
+layout is known from the "__signature__" attribute.
+
+The function "get_signature(ob, modifier=None)" produces the same
+signatures by default. By passing different modifiers, you
+can select different layouts.
+
+This module configures the different layouts which can be used.
+It also implements them in this file. The configurations are
+used literally as strings like "signature", "existence", etc.
+"""
+
+import inspect
+import typing
+
+from types import SimpleNamespace
+from textwrap import dedent
+from shibokensupport.signature.mapping import ellipsis
+
+
+class SignatureLayout(SimpleNamespace):
+ """
+ Configure a signature.
+
+ The layout of signatures can have different layouts which are
+ controlled by keyword arguments:
+
+ definition=True Determines if self will generated.
+ defaults=True
+ ellipsis=False Replaces defaults by "...".
+ return_annotation=True
+ parameter_names=True False removes names before ":".
+ """
+ allowed_keys = SimpleNamespace(definition=True,
+ defaults=True,
+ ellipsis=False,
+ return_annotation=True,
+ parameter_names=True)
+ allowed_values = True, False
+
+ def __init__(self, **kwds):
+ args = SimpleNamespace(**self.allowed_keys.__dict__)
+ args.__dict__.update(kwds)
+ self.__dict__.update(args.__dict__)
+ err_keys = list(set(self.__dict__) - set(self.allowed_keys.__dict__))
+ if err_keys:
+ self._attributeerror(err_keys)
+ err_values = list(set(self.__dict__.values()) - set(self.allowed_values))
+ if err_values:
+ self._valueerror(err_values)
+
+ def __setattr__(self, key, value):
+ if key not in self.allowed_keys.__dict__:
+ self._attributeerror([key])
+ if value not in self.allowed_values:
+ self._valueerror([value])
+ self.__dict__[key] = value
+
+ def _attributeerror(self, err_keys):
+ err_keys = ", ".join(err_keys)
+ allowed_keys = ", ".join(self.allowed_keys.__dict__.keys())
+ raise AttributeError(dedent(f"""\
+ Not allowed: '{err_keys}'.
+ The only allowed keywords are '{allowed_keys}'.
+ """))
+
+ def _valueerror(self, err_values):
+ err_values = ", ".join(map(str, err_values))
+ allowed_values = ", ".join(map(str, self.allowed_values))
+ raise ValueError(dedent(f"""\
+ Not allowed: '{err_values}'.
+ The only allowed values are '{allowed_values}'.
+ """))
+
+
+# The following names are used literally in this module.
+# This way, we avoid the dict hashing problem.
+signature = SignatureLayout()
+
+existence = SignatureLayout(definition=False,
+ defaults=False,
+ return_annotation=False,
+ parameter_names=False)
+
+hintingstub = SignatureLayout(ellipsis=True)
+
+typeerror = SignatureLayout(definition=False,
+ return_annotation=False,
+ parameter_names=False)
+
+
+def define_nameless_parameter():
+ """
+ Create Nameless Parameters
+
+ A nameless parameter has a reduced string representation.
+ This is done by cloning the parameter type and overwriting its
+ __str__ method. The inner structure is still a valid parameter.
+ """
+ def __str__(self):
+ # for Python 2, we must change self to be an instance of P
+ klass = self.__class__
+ self.__class__ = P
+ txt = P.__str__(self)
+ self.__class__ = klass
+ txt = txt[txt.index(":") + 1:].strip() if ":" in txt else txt
+ return txt
+
+ P = inspect.Parameter
+ newname = "NamelessParameter"
+ bases = P.__bases__
+ body = dict(P.__dict__) # get rid of mappingproxy
+ if "__slots__" in body:
+ # __slots__ would create duplicates
+ for name in body["__slots__"]:
+ del body[name]
+ body["__str__"] = __str__
+ return type(newname, bases, body)
+
+
+NamelessParameter = define_nameless_parameter()
+
+"""
+Note on the "Optional" feature:
+
+When an annotation has a default value that is None, then the
+type has to be wrapped into "typing.Optional".
+
+Note that only the None value creates an Optional expression,
+because the None leaves the domain of the variable.
+Defaults like integer values are ignored: They stay in the domain.
+
+That information would be lost when we use the "..." convention.
+
+Note that the typing module has the remarkable expansion
+
+ Optional[T] is Union[T, NoneType]
+
+We want to avoid that when generating the .pyi file.
+This is done by a regex in pyi_generator.py .
+The following would work in Python 3, but this is a version-dependent
+hack that also won't work in Python 2 and would be _very_ complex.
+"""
+# import sys
+# if sys.version_info[0] == 3:
+# class hugo(list):pass
+# typing._normalize_alias["hugo"] = "Optional"
+# Optional = typing._alias(hugo, typing.T, inst=False)
+# else:
+# Optional = typing.Optional
+
+
+def make_signature_nameless(signature):
+ """
+ Make a Signature Nameless
+
+ We use an existing signature and change the type of its parameters.
+ The signature looks different, but is totally intact.
+ """
+ for key in signature.parameters.keys():
+ signature.parameters[key].__class__ = NamelessParameter
+
+
+_POSITIONAL_ONLY = inspect._POSITIONAL_ONLY # noqa E:201
+_POSITIONAL_OR_KEYWORD = inspect._POSITIONAL_OR_KEYWORD # noqa E:201
+_VAR_POSITIONAL = inspect._VAR_POSITIONAL # noqa E:201
+_KEYWORD_ONLY = inspect._KEYWORD_ONLY # noqa E:201
+_VAR_KEYWORD = inspect._VAR_KEYWORD # noqa E:201
+_empty = inspect._empty # noqa E:201
+
+
+def create_signature(props, key):
+ if not props:
+ # empty signatures string
+ return
+ if isinstance(props["multi"], list):
+ # multi sig: call recursively
+ return list(create_signature(elem, key)
+ for elem in props["multi"])
+ if type(key) is tuple:
+ _, modifier = key
+ else:
+ _, modifier = key, "signature"
+
+ layout = globals()[modifier] # lookup of the modifier in this module
+ if not isinstance(layout, SignatureLayout):
+ raise SystemError("Modifiers must be names of a SignatureLayout "
+ "instance")
+
+ # this is the basic layout of a signature
+ varnames = props["varnames"]
+ if layout.definition:
+ # PYSIDE-1328: We no longer use info from the sig_kind which is
+ # more complex for multiple signatures. We now get `self` from the
+ # parser.
+ pass
+ else:
+ if varnames and varnames[0] in ("self", "cls"):
+ varnames = varnames[1:]
+
+ # calculate the modifications
+ defaults = props["defaults"][:]
+ if not layout.defaults:
+ defaults = ()
+ annotations = props["annotations"].copy()
+ if not layout.return_annotation and "return" in annotations:
+ del annotations["return"]
+
+ # Build a signature.
+ kind = inspect._POSITIONAL_OR_KEYWORD
+ params = []
+ for idx, name in enumerate(varnames):
+ if name.startswith("**"):
+ kind = _VAR_KEYWORD
+ elif name.startswith("*"):
+ kind = _VAR_POSITIONAL
+ ann = annotations.get(name, _empty)
+ if ann in ("self", "cls"):
+ ann = _empty
+ name = name.lstrip("*")
+ defpos = idx - len(varnames) + len(defaults)
+ default = defaults[defpos] if defpos >= 0 else _empty
+ if default is None:
+ ann = typing.Optional[ann]
+ if default is not _empty and layout.ellipsis:
+ default = ellipsis
+ param = inspect.Parameter(name, kind, annotation=ann, default=default)
+ params.append(param)
+ if kind == _VAR_POSITIONAL:
+ kind = _KEYWORD_ONLY
+ sig = inspect.Signature(params,
+ return_annotation=annotations.get('return', _empty),
+ __validate_parameters__=False)
+
+ # the special case of nameless parameters
+ if not layout.parameter_names:
+ make_signature_nameless(sig)
+ return sig
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py
new file mode 100644
index 000000000..e54bec75a
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py
@@ -0,0 +1,4 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+# this file intentionally left blank
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
new file mode 100644
index 000000000..5650e2bc1
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
@@ -0,0 +1,304 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+enum_sig.py
+
+Enumerate all signatures of a class.
+
+This module separates the enumeration process from the formatting.
+It is not easy to adhere to this protocol, but in the end, it paid off
+by producing a lot of clarity.
+"""
+
+import inspect
+import sys
+import types
+from shibokensupport.signature import get_signature as get_sig
+
+
+"""
+PYSIDE-1599: Making sure that pyi files always are tested.
+
+A new problem popped up when supporting true properties:
+When there exists an item named "property", then we cannot use
+the builtin `property` as decorator, but need to prefix it with "builtins".
+
+We scan for such a name in a class, and if there should a property be
+declared in the same class, we use `builtins.property` in the class and
+all sub-classes. The same consideration holds for "overload".
+"""
+
+_normal_functions = (types.BuiltinFunctionType, types.FunctionType)
+if hasattr(sys, "pypy_version_info"):
+ # In PyPy, there are more types because our builtin functions
+ # are created differently in C++ and not in PyPy.
+ _normal_functions += (type(get_sig),)
+
+
+def signal_check(thing):
+ return thing and type(thing) in (Signal, SignalInstance)
+
+
+class ExactEnumerator(object):
+ """
+ ExactEnumerator enumerates all signatures in a module as they are.
+
+ This class is used for generating complete listings of all signatures.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+
+ def __init__(self, formatter, result_type=dict):
+ global EnumMeta, Signal, SignalInstance
+ try:
+ # Lazy import
+ from PySide6.QtCore import Qt, Signal, SignalInstance
+ EnumMeta = type(Qt.Key)
+ except ImportError:
+ EnumMeta = Signal = SignalInstance = None
+
+ self.fmt = formatter
+ self.result_type = result_type
+ self.fmt.level = 0
+ self.fmt.is_method = self.is_method
+ self.collision_candidates = {"property", "overload"}
+
+ def is_method(self):
+ """
+ Is this function a method?
+ We check if it is a simple function.
+ """
+ tp = type(self.func)
+ return tp not in _normal_functions
+
+ def section(self):
+ if hasattr(self.fmt, "section"):
+ self.fmt.section()
+
+ def module(self, mod_name):
+ __import__(mod_name)
+ self.fmt.mod_name = mod_name
+ with self.fmt.module(mod_name):
+ module = sys.modules[mod_name]
+ members = inspect.getmembers(module, inspect.isclass)
+ functions = inspect.getmembers(module, inspect.isroutine)
+ ret = self.result_type()
+ self.fmt.class_name = None
+ for class_name, klass in members:
+ self.collision_track = set()
+ ret.update(self.klass(class_name, klass))
+ if len(members):
+ self.section()
+ for func_name, func in functions:
+ ret.update(self.function(func_name, func))
+ if len(functions):
+ self.section()
+ return ret
+
+ def klass(self, class_name, klass):
+ ret = self.result_type()
+ if ("._") in class_name:
+ # This happens when introspecting enum.Enum etc. Python 3.8.8 does not
+ # like this, but we want to remove that, anyway.
+ return ret
+ if "<" in class_name:
+ # This is happening in QtQuick for some reason:
+ # class std::shared_ptr<QQuickItemGrabResult >:
+ # We simply skip over this class.
+ return ret
+ bases_list = []
+ for base in klass.__bases__:
+ name = base.__qualname__
+ if name not in ("object", "property", "type"):
+ name = base.__module__ + "." + name
+ bases_list.append(name)
+ bases_str = ', '.join(bases_list)
+ class_str = f"{class_name}({bases_str})"
+ # class_members = inspect.getmembers(klass)
+ # gives us also the inherited things.
+ class_members = sorted(list(klass.__dict__.items()))
+ subclasses = []
+ functions = []
+ enums = []
+ properties = []
+ signals = []
+ attributes = {}
+
+ for thing_name, thing in class_members:
+ if signal_check(thing):
+ signals.append((thing_name, thing))
+ elif inspect.isclass(thing):
+ # If this is the only member of the class, it causes the stub
+ # to be printed empty without ..., as self.fmt.have_body will
+ # then be True. (Example: QtCore.QCborTag). Skip it to avoid
+ # this problem.
+ if thing_name == "_member_type_":
+ continue
+ subclass_name = ".".join((class_name, thing_name))
+ subclasses.append((subclass_name, thing))
+ elif inspect.isroutine(thing):
+ func_name = thing_name.split(".")[0] # remove ".overload"
+ functions.append((func_name, thing))
+ elif type(type(thing)) is EnumMeta:
+ # take the real enum name, not what is in the dict
+ if not thing_name.startswith("_"):
+ enums.append((thing_name, type(thing).__qualname__, thing))
+ elif isinstance(thing, property):
+ properties.append((thing_name, thing))
+ # Support attributes that have PySide types as values,
+ # but we skip the 'staticMetaObject' that needs
+ # to be defined at a QObject level.
+ elif "PySide" in str(type(thing)) and "QMetaObject" not in str(type(thing)):
+ if class_name not in attributes:
+ attributes[class_name] = {}
+ attributes[class_name][thing_name] = thing
+
+ if thing_name in self.collision_candidates:
+ self.collision_track.add(thing_name)
+
+ init_signature = getattr(klass, "__signature__", None)
+ # sort by class then enum value
+ enums.sort(key=lambda tup: (tup[1], tup[2].value))
+
+ # We want to handle functions and properties together.
+ func_prop = sorted(functions + properties, key=lambda tup: tup[0])
+
+ # find out how many functions create a signature
+ sigs = list(_ for _ in functions if get_sig(_[1]))
+ self.fmt.have_body = bool(subclasses or sigs or properties or enums or # noqa W:504
+ init_signature or signals or attributes)
+
+ with self.fmt.klass(class_name, class_str):
+ self.fmt.level += 1
+ self.fmt.class_name = class_name
+ if hasattr(self.fmt, "enum"):
+ # this is an optional feature
+ if len(enums):
+ self.section()
+ for enum_name, enum_class_name, value in enums:
+ with self.fmt.enum(enum_class_name, enum_name, value.value):
+ pass
+ if hasattr(self.fmt, "signal"):
+ # this is an optional feature
+ if len(signals):
+ self.section()
+ for signal_name, signal in signals:
+ sig_class = type(signal)
+ sig_class_name = f"{sig_class.__qualname__}"
+ sig_str = str(signal)
+ with self.fmt.signal(sig_class_name, signal_name, sig_str):
+ pass
+ if hasattr(self.fmt, "attribute"):
+ if len(attributes):
+ self.section()
+ for class_name, attrs in attributes.items():
+ for attr_name, attr_value in attrs.items():
+ with self.fmt.attribute(attr_name, attr_value):
+ pass
+ if len(subclasses):
+ self.section()
+ for subclass_name, subclass in subclasses:
+ save = self.collision_track.copy()
+ ret.update(self.klass(subclass_name, subclass))
+ self.collision_track = save
+ self.fmt.class_name = class_name
+ if len(subclasses):
+ self.section()
+ ret.update(self.function("__init__", klass))
+ for func_name, func in func_prop:
+ if func_name != "__init__":
+ if isinstance(func, property):
+ ret.update(self.fproperty(func_name, func))
+ else:
+ ret.update(self.function(func_name, func))
+ self.fmt.level -= 1
+ if len(func_prop):
+ self.section()
+ return ret
+
+ @staticmethod
+ def get_signature(func):
+ return get_sig(func)
+
+ def function(self, func_name, func, decorator=None):
+ self.func = func # for is_method()
+ ret = self.result_type()
+ if decorator in self.collision_track:
+ decorator = f"builtins.{decorator}"
+ signature = self.get_signature(func, decorator)
+ if signature is not None:
+ with self.fmt.function(func_name, signature, decorator) as key:
+ ret[key] = signature
+ del self.func
+ return ret
+
+ def fproperty(self, prop_name, prop):
+ ret = self.function(prop_name, prop.fget, type(prop).__qualname__)
+ if prop.fset:
+ ret.update(self.function(prop_name, prop.fset, f"{prop_name}.setter"))
+ if prop.fdel:
+ ret.update(self.function(prop_name, prop.fdel, f"{prop_name}.deleter"))
+ return ret
+
+
+def stringify(signature):
+ if isinstance(signature, list):
+ # remove duplicates which still sometimes occour:
+ ret = set(stringify(sig) for sig in signature)
+ return sorted(ret) if len(ret) > 1 else list(ret)[0]
+ return tuple(str(pv) for pv in signature.parameters.values())
+
+
+class SimplifyingEnumerator(ExactEnumerator):
+ """
+ SimplifyingEnumerator enumerates all signatures in a module filtered.
+
+ There are no default values, no variable
+ names and no self parameter. Only types are present after simplification.
+ The functions 'next' resp. '__next__' are removed
+ to make the output identical for Python 2 and 3.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+
+ def function(self, func_name, func):
+ ret = self.result_type()
+ signature = get_sig(func, 'existence')
+ sig = stringify(signature) if signature is not None else None
+ if sig is not None and func_name not in ("next", "__next__", "__div__"):
+ with self.fmt.function(func_name, sig) as key:
+ ret[key] = sig
+ return ret
+
+
+class HintingEnumerator(ExactEnumerator):
+ """
+ HintingEnumerator enumerates all signatures in a module slightly changed.
+
+ This class is used for generating complete listings of all signatures for
+ hinting stubs. Only default values are replaced by "...".
+ """
+
+ def __init__(self, *args, **kwds):
+ super().__init__(*args, **kwds)
+ # We need to provide default signatures for class properties.
+ cls_param = inspect.Parameter("cls", inspect._POSITIONAL_OR_KEYWORD)
+ set_param = inspect.Parameter("arg_1", inspect._POSITIONAL_OR_KEYWORD, annotation=object)
+ self.getter_sig = inspect.Signature([cls_param], return_annotation=object)
+ self.setter_sig = inspect.Signature([cls_param, set_param])
+ self.deleter_sig = inspect.Signature([cls_param])
+
+ def get_signature(self, func, decorator=None):
+ # Class properties don't have signature support (yet).
+ # In that case, produce a fake one.
+ sig = get_sig(func, "hintingstub")
+ if not sig:
+ if decorator:
+ if decorator.endswith(".setter"):
+ sig = self.setter_sig
+ elif decorator.endswith(".deleter"):
+ sig = self.deleter_sig
+ else:
+ sig = self.getter_sig
+ return sig
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
new file mode 100644
index 000000000..ce12dd6c8
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
@@ -0,0 +1,334 @@
+LICENSE_TEXT = """
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+"""
+
+# flake8: noqa E:402
+
+"""
+pyi_generator.py
+
+This script generates .pyi files for arbitrary modules.
+"""
+
+import argparse
+import io
+import logging
+import os
+import re
+import sys
+import typing
+
+from pathlib import Path
+from contextlib import contextmanager
+from textwrap import dedent
+
+from shibokensupport.signature.lib.enum_sig import HintingEnumerator
+from shibokensupport.signature.lib.tool import build_brace_pattern
+
+# Can we use forward references?
+USE_PEP563 = sys.version_info[:2] >= (3, 7)
+
+indent = " " * 4
+
+
+class Writer(object):
+ def __init__(self, outfile, *args):
+ self.outfile = outfile
+ self.history = [True, True]
+
+ def print(self, *args, **kw):
+ # controlling too much blank lines
+ if self.outfile:
+ if args == () or args == ("",):
+ # We use that to skip too many blank lines:
+ if self.history[-2:] == [True, True]:
+ return
+ print("", file=self.outfile, **kw)
+ self.history.append(True)
+ else:
+ print(*args, file=self.outfile, **kw)
+ self.history.append(False)
+
+
+class Formatter(Writer):
+ """
+ Formatter is formatting the signature listing of an enumerator.
+
+ It is written as context managers in order to avoid many callbacks.
+ The separation in formatter and enumerator is done to keep the
+ unrelated tasks of enumeration and formatting apart.
+ """
+ def __init__(self, outfile, options, *args):
+ # XXX Find out which of these patches is still necessary!
+ self.options = options
+ Writer.__init__(self, outfile, *args)
+ # patching __repr__ to disable the __repr__ of typing.TypeVar:
+ """
+ def __repr__(self):
+ if self.__covariant__:
+ prefix = '+'
+ elif self.__contravariant__:
+ prefix = '-'
+ else:
+ prefix = '~'
+ return prefix + self.__name__
+ """
+ def _typevar__repr__(self):
+ return f"typing.{self.__name__}"
+ # This is no longer necessary for modern typing versions.
+ # Ignore therefore if the repr is read-only and cannot be changed.
+ try:
+ typing.TypeVar.__repr__ = _typevar__repr__
+ except TypeError:
+ pass
+ # Adding a pattern to substitute "Union[T, NoneType]" by "Optional[T]"
+ # I tried hard to replace typing.Optional by a simple override, but
+ # this became _way_ too much.
+ # See also the comment in layout.py .
+ brace_pat = build_brace_pattern(3, ",")
+ pattern = fr"\b Union \s* \[ \s* {brace_pat} \s*, \s* NoneType \s* \]"
+ replace = r"Optional[\1]"
+ optional_searcher = re.compile(pattern, flags=re.VERBOSE)
+
+ def optional_replacer(source):
+ return optional_searcher.sub(replace, str(source))
+ self.optional_replacer = optional_replacer
+ # self.level is maintained by enum_sig.py
+ # self.is_method() is true for non-plain functions.
+
+ def section(self):
+ if self.level == 0:
+ self.print()
+ self.print()
+
+ @contextmanager
+ def module(self, mod_name):
+ self.mod_name = mod_name
+ txt = f"""\
+ # Module `{mod_name}`
+
+ <<IMPORTS>>
+ """
+ self.print(dedent(txt))
+ yield
+
+ @contextmanager
+ def klass(self, class_name, class_str):
+ spaces = indent * self.level
+ while "." in class_name:
+ class_name = class_name.split(".", 1)[-1]
+ class_str = class_str.split(".", 1)[-1]
+ if self.have_body:
+ self.print(f"{spaces}class {class_str}:")
+ else:
+ self.print(f"{spaces}class {class_str}: ...")
+ yield
+
+ @contextmanager
+ def function(self, func_name, signature, decorator=None):
+ if func_name == "__init__":
+ self.print()
+ key = func_name
+ spaces = indent * self.level
+ if isinstance(signature, list):
+ for sig in signature:
+ self.print(f'{spaces}@overload')
+ self._function(func_name, sig, spaces)
+ else:
+ self._function(func_name, signature, spaces, decorator)
+ if func_name == "__init__":
+ self.print()
+ yield key
+
+ def _function(self, func_name, signature, spaces, decorator=None):
+ if decorator:
+ # In case of a PyClassProperty the classmethod decorator is not used.
+ self.print(f'{spaces}@{decorator}')
+ elif self.is_method() and "self" not in signature.parameters:
+ kind = "class" if "cls" in signature.parameters else "static"
+ self.print(f'{spaces}@{kind}method')
+ signature = self.optional_replacer(signature)
+ self.print(f'{spaces}def {func_name}{signature}: ...')
+
+ @contextmanager
+ def enum(self, class_name, enum_name, value):
+ spaces = indent * self.level
+ hexval = hex(value)
+ self.print(f"{spaces}{enum_name:25}: {class_name} = ... # {hexval}")
+ yield
+
+ @contextmanager
+ def attribute(self, attr_name, attr_value):
+ spaces = indent * self.level
+ self.print(f"{spaces}{attr_name:25} = ... # type: {type(attr_value).__qualname__}")
+ yield
+
+ @contextmanager
+ def signal(self, class_name, sig_name, sig_str):
+ spaces = indent * self.level
+ self.print(f"{spaces}{sig_name:25}: ClassVar[{class_name}] = ... # {sig_str}")
+ yield
+
+
+def find_imports(text):
+ return [imp for imp in PySide6.__all__ if f"PySide6.{imp}." in text]
+
+
+FROM_IMPORTS = [
+ (None, ["builtins"]),
+ (None, ["os"]),
+ (None, ["enum"]),
+ ("collections.abc", ["Iterable"]),
+ ("typing", sorted(typing.__all__)),
+ ("PySide6.QtCore", ["PyClassProperty", "Signal", "SignalInstance"]),
+ ("shiboken6", ["Shiboken"]),
+ ]
+
+
+def filter_from_imports(from_struct, text):
+ """
+ Build a reduced new `from` structure (nfs) with found entries, only
+ """
+ nfs = []
+ for mod, imports in from_struct:
+ lis = []
+ nfs.append((mod, lis))
+ for each in imports:
+ # PYSIDE-1603: We search text that is a usage of the class `each`,
+ # but only if the class is not also defined here.
+ if (f"class {each}(") not in text:
+ if re.search(rf"(\b|@){each}\b([^\s\(:]|\n)", text):
+ lis.append(each)
+ # Search if a type is present in the return statement
+ # of function declarations: '... -> here:'
+ if re.search(rf"->.*{each}.*:", text):
+ lis.append(each)
+ if not lis:
+ nfs.pop()
+ return nfs
+
+
+def find_module(import_name, outpath, from_pyside):
+ """
+ Find a module either directly by import, or use the full path,
+ add the path to sys.path and import then.
+ """
+ if from_pyside:
+ # internal mode for generate_pyi.py
+ plainname = import_name.split(".")[-1]
+ outfilepath = Path(outpath) / f"{plainname}.pyi"
+ return import_name, plainname, outfilepath
+ # we are alone in external module mode
+ p = Path(import_name).resolve()
+ if not p.exists():
+ raise ValueError(f"File {p} does not exist.")
+ if not outpath:
+ outpath = p.parent
+ # temporarily add the path and do the import
+ sys.path.insert(0, os.fspath(p.parent))
+ plainname = p.name.split(".")[0]
+ __import__(plainname)
+ sys.path.pop(0)
+ return plainname, plainname, Path(outpath) / (plainname + ".pyi")
+
+
+def generate_pyi(import_name, outpath, options):
+ """
+ Generates a .pyi file.
+ """
+ import_name, plainname, outfilepath = find_module(import_name, outpath, options._pyside_call)
+ top = __import__(import_name)
+ obj = getattr(top, plainname) if import_name != plainname else top
+ if not getattr(obj, "__file__", None) or Path(obj.__file__).is_dir():
+ raise ModuleNotFoundError(f"We do not accept a namespace as module `{plainname}`")
+
+ outfile = io.StringIO()
+ fmt = Formatter(outfile, options)
+ fmt.print(LICENSE_TEXT.strip())
+ if USE_PEP563:
+ fmt.print("from __future__ import annotations")
+ fmt.print()
+ fmt.print(dedent(f'''\
+ """
+ This file contains the exact signatures for all functions in module
+ {import_name}, except for defaults which are replaced by "...".
+ """
+ '''))
+ HintingEnumerator(fmt).module(import_name)
+ fmt.print("# eof")
+ # Postprocess: resolve the imports
+ if options._pyside_call:
+ global PySide6
+ import PySide6
+ with outfilepath.open("w") as realfile:
+ wr = Writer(realfile)
+ outfile.seek(0)
+ while True:
+ line = outfile.readline()
+ if not line:
+ break
+ line = line.rstrip()
+ # we remove the "<<IMPORTS>>" marker and insert imports if needed
+ if line == "<<IMPORTS>>":
+ text = outfile.getvalue()
+ wr.print("import " + import_name)
+ for mod_name in find_imports(text):
+ imp = "PySide6." + mod_name
+ if imp != import_name:
+ wr.print("import " + imp)
+ wr.print()
+ for mod, imports in filter_from_imports(FROM_IMPORTS, text):
+ import_args = ', '.join(imports)
+ if mod is None:
+ # special case, a normal import
+ wr.print(f"import {import_args}")
+ else:
+ wr.print(f"from {mod} import {import_args}")
+ wr.print()
+ wr.print()
+ wr.print("NoneType: TypeAlias = type[None]")
+ wr.print()
+ else:
+ wr.print(line)
+ if not options.quiet:
+ options.logger.info(f"Generated: {outfilepath}")
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description=dedent("""\
+ pyi_generator.py
+ ----------------
+
+ This script generates the .pyi file for an arbitrary module.
+ You pass in the full path of a compiled, importable module.
+ pyi_generator will try to generate an interface "<module>.pyi".
+ """))
+ parser.add_argument("module",
+ help="The full path name of an importable module binary (.pyd, .so)") # noqa E:128
+ parser.add_argument("--quiet", action="store_true", help="Run quietly")
+ parser.add_argument("--outpath",
+ help="the output directory (default = location of module binary)") # noqa E:128
+ options = parser.parse_args()
+ module = options.module
+ outpath = options.outpath
+
+ qtest_env = os.environ.get("QTEST_ENVIRONMENT", "")
+ logging.basicConfig(level=logging.DEBUG if qtest_env else logging.INFO)
+ logger = logging.getLogger("pyi_generator")
+
+ if outpath and not Path(outpath).exists():
+ os.makedirs(outpath)
+ logger.info(f"+++ Created path {outpath}")
+ options._pyside_call = False
+ options.is_ci = qtest_env == "ci"
+
+ options.logger = logger
+ generate_pyi(module, outpath, options=options)
+
+
+if __name__ == "__main__":
+ main()
+# eof
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
new file mode 100644
index 000000000..979dcf4ce
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
@@ -0,0 +1,110 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+tool.py
+
+Some useful stuff, see below.
+On the function with_metaclass see the answer from Martijn Pieters on
+https://stackoverflow.com/questions/18513821/python-metaclass-understanding-the-with-metaclass
+"""
+
+from inspect import currentframe
+from textwrap import dedent
+
+
+def build_brace_pattern(level, separators):
+ """
+ Build a brace pattern upto a given depth
+
+ The brace pattern parses any pattern with round, square, curly, or angle
+ brackets. Inside those brackets, any characters are allowed.
+
+ The structure is quite simple and is recursively repeated as needed.
+ When separators are given, the match stops at that separator.
+
+ Reason to use this instead of some Python function:
+ The resulting regex is _very_ fast!
+
+ A faster replacement would be written in C, but this solution is
+ sufficient when the nesting level is not too large.
+
+ Because of the recursive nature of the pattern, the size grows by a factor
+ of 4 at every level, as does the creation time. Up to a level of 6, this
+ is below 10 ms.
+
+ There are other regex engines available which allow recursive patterns,
+ avoiding this problem completely. It might be considered to switch to
+ such an engine if the external module is not a problem.
+ """
+ assert type(separators) is str
+
+ def escape(txt):
+ return "".join("\\" + c for c in txt)
+
+ ro, rc = round_ = "()"
+ so, sc = square = "[]"
+ co, cc = curly = "CD" # noqa E:201 we insert "{}", later...
+ ao, ac = angle = "<>" # noqa E:201
+ q2, bs, q1 = '"', "\\", "'"
+ allpat = round_ + square + curly + angle
+ __ = " "
+ ro, rc, so, sc, co, cc, ao, ac, separators, q2, bs, q1, allpat = map(
+ escape, (ro, rc, so, sc, co, cc, ao, ac, separators, q2, bs, q1, allpat))
+
+ no_brace_sep_q = fr"[^{allpat}{separators}{q2}{bs}{q1}]"
+ no_quot2 = fr"(?: [^{q2}{bs}] | {bs}. )*"
+ no_quot1 = fr"(?: [^{q1}{bs}] | {bs}. )*"
+ pattern = dedent(r"""
+ (
+ (?: {__} {no_brace_sep_q}
+ | {q2} {no_quot2} {q2}
+ | {q1} {no_quot1} {q1}
+ | {ro} {replacer} {rc}
+ | {so} {replacer} {sc}
+ | {co} {replacer} {cc}
+ | {ao} {replacer} {ac}
+ )+
+ )
+ """)
+ no_braces_q = f"[^{allpat}{q2}{bs}{q1}]*"
+ repeated = dedent(r"""
+ {indent} (?: {__} {no_braces_q}
+ {indent} | {q2} {no_quot2} {q2}
+ {indent} | {q1} {no_quot1} {q1}
+ {indent} | {ro} {replacer} {rc}
+ {indent} | {so} {replacer} {sc}
+ {indent} | {co} {replacer} {cc}
+ {indent} | {ao} {replacer} {ac}
+ {indent} )*
+ """)
+ for idx in range(level):
+ pattern = pattern.format(replacer=repeated if idx < level - 1 else no_braces_q,
+ indent=idx * " ", **locals())
+ return pattern.replace("C", "{").replace("D", "}")
+
+
+# Copied from the six module:
+def with_metaclass(meta, *bases):
+ """Create a base class with a metaclass."""
+ # This requires a bit of explanation: the basic idea is to make a dummy
+ # metaclass for one level of class instantiation that replaces itself with
+ # the actual metaclass.
+ class metaclass(type):
+
+ def __new__(cls, name, this_bases, d):
+ return meta(name, bases, d)
+
+ @classmethod
+ def __prepare__(cls, name, this_bases):
+ return meta.__prepare__(name, bases)
+ return type.__new__(metaclass, 'temporary_class', (), {})
+
+
+# A handy tool that shows the current line number and indents.
+def lno(level):
+ lineno = currentframe().f_back.f_lineno
+ spaces = level * " "
+ return f"{lineno}{spaces}"
+
+# eof
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py
new file mode 100644
index 000000000..fb4c9eeca
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py
@@ -0,0 +1,158 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+# flake8: noqa E:402
+# flake8: noqa F:401
+
+"""
+loader.py
+
+The loader has to load the signature module completely at startup,
+to make sure that the functions are available when needed.
+This is meanwhile necessary to make the '__doc__' attribute work correctly.
+
+It does not mean that everything is initialized in advance. Only the modules
+are loaded completely after 'import PySide6'.
+
+This version uses both a normal directory, but has also an embedded ZIP file
+as a fallback solution. The ZIP file is generated by 'embedding_generator.py'
+and embedded into 'signature.cpp' as "embed/signature.inc".
+
+Meanwhile, the ZIP file grew so much, that MSVC had problems
+with it's 64k string limit, so we had to break the string up.
+See 'zipped_string_sequence' in signature.cpp.
+"""
+
+import sys
+import os
+import traceback
+import types
+
+
+# name used in signature.cpp
+def pyside_type_init(type_key, sig_strings):
+ return parser.pyside_type_init(type_key, sig_strings)
+
+
+# name used in signature.cpp
+def create_signature(props, key):
+ return layout.create_signature(props, key)
+
+
+# name used in signature.cpp
+def seterror_argument(args, func_name, info):
+ return errorhandler.seterror_argument(args, func_name, info)
+
+
+# name used in signature.cpp
+def make_helptext(func):
+ return errorhandler.make_helptext(func)
+
+
+# name used in signature.cpp
+def finish_import(module):
+ return importhandler.finish_import(module)
+
+
+# name used in signature.cpp
+def feature_import(*args, **kwds):
+ # don't spend a stack level here for speed and compatibility
+ global feature_import
+ feature_import = feature.feature_import
+ return feature_import(*args, **kwds)
+
+
+# name used in signature.cpp
+def feature_imported(*args, **kwds):
+ # don't spend a stack level here for speed and compatibility
+ global feature_imported
+ feature_imported = feature.feature_imported
+ return feature_imported(*args, **kwds)
+
+
+import builtins
+import signature_bootstrap
+from shibokensupport import signature, feature
+signature.get_signature = signature_bootstrap.get_signature
+# PYSIDE-1019: Publish the __feature__ dictionary.
+feature.pyside_feature_dict = signature_bootstrap.pyside_feature_dict
+builtins.__feature_import__ = signature_bootstrap.__feature_import__
+del signature_bootstrap
+
+is_pypy = hasattr(sys, "pypy_version_info")
+
+
+def put_into_package(package, module, override=None):
+ # take the last component of the module name
+ name = (override if override else module.__spec__.name).rsplit(".", 1)[-1]
+ # allow access as {package}.{name}
+ if package:
+ setattr(package, name, module)
+ # put into sys.modules as a package to allow all import options
+ fullname = f"{package.__spec__.name}.{name}" if package else name
+ module.__spec__.name = fullname
+ # publish new dotted name in sys.modules
+ sys.modules[fullname] = module
+
+
+def move_into_pyside_package():
+ import shibokensupport
+ import PySide6
+ try:
+ import PySide6.support
+ except ModuleNotFoundError:
+ # This can happen in the embedding case.
+ put_into_package(PySide6, shibokensupport, "support")
+ if not is_pypy:
+ put_into_package(PySide6.support, feature)
+ put_into_package(PySide6.support, signature)
+ put_into_package(PySide6.support.signature, mapping)
+ put_into_package(PySide6.support.signature, errorhandler)
+ put_into_package(PySide6.support.signature, layout)
+ put_into_package(PySide6.support.signature, lib)
+ put_into_package(PySide6.support.signature, parser)
+ put_into_package(PySide6.support.signature, importhandler)
+ put_into_package(PySide6.support.signature.lib, enum_sig)
+ put_into_package(PySide6.support.signature.lib, pyi_generator)
+ put_into_package(PySide6.support.signature.lib, tool)
+
+
+from shibokensupport.signature import mapping
+from shibokensupport.signature import errorhandler
+from shibokensupport.signature import layout
+from shibokensupport.signature import lib
+from shibokensupport.signature import parser
+from shibokensupport.signature import importhandler
+from shibokensupport.signature.lib import enum_sig
+from shibokensupport.signature.lib import pyi_generator
+from shibokensupport.signature.lib import tool
+
+import enum
+
+post_init = lambda: None # noqa E:731 default
+
+if "PySide6" in sys.modules:
+ # We publish everything under "PySide6.support", again.
+ move_into_pyside_package()
+ # PYSIDE-1502: Make sure that support can be imported.
+ try:
+ import PySide6.support
+ except ModuleNotFoundError:
+ print("PySide6.support could not be imported. "
+ "This is a serious configuration error.", file=sys.stderr)
+ raise
+
+ def post_init():
+ """
+ This function needs to be called explicitly when all function pointers are set.
+ Doing this during import has bad side-effects when preloading the loader.
+ """
+ # PYSIDE-1019: Modify `__import__` to be `__feature__` aware.
+ if not is_pypy:
+ # PYSIDE-535: Cannot enable __feature__ for various reasons.
+ import PySide6.support.feature
+ sys.modules["__feature__"] = PySide6.support.feature
+ builtins.__orig_import__ = builtins.__import__
+ builtins.__import__ = builtins.__feature_import__
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
new file mode 100644
index 000000000..944a928e6
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
@@ -0,0 +1,719 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+# flake8: noqa E:203
+
+"""
+mapping.py
+
+This module has the mapping from the pyside C-modules view of signatures
+to the Python representation.
+
+The PySide modules are not loaded in advance, but only after they appear
+in sys.modules. This minimizes the loading overhead.
+"""
+
+import os
+import struct
+import sys
+import typing
+
+from pathlib import Path
+from typing import TypeVar, Generic
+from _imp import is_builtin
+
+
+class ellipsis(object):
+ def __repr__(self):
+ return "..."
+
+
+ellipsis = ellipsis()
+Point = typing.Tuple[int, int]
+Variant = typing.Any
+QImageCleanupFunction = typing.Callable
+
+# unfortunately, typing.Optional[t] expands to typing.Union[t, NoneType]
+# Until we can force it to create Optional[t] again, we use this.
+NoneType = type(None)
+
+_S = TypeVar("_S")
+
+MultiMap = typing.DefaultDict[str, typing.List[str]]
+
+# ulong_max is only 32 bit on windows.
+ulong_max = 2 * sys.maxsize + 1 if len(struct.pack("L", 1)) != 4 else 0xffffffff
+ushort_max = 0xffff
+
+GL_COLOR_BUFFER_BIT = 0x00004000
+GL_NEAREST = 0x2600
+
+WId = int
+
+# from 5.9
+GL_TEXTURE_2D = 0x0DE1
+GL_RGBA = 0x1908
+
+
+class _NotCalled(str):
+ """
+ Wrap some text with semantics
+
+ This class is wrapped around text in order to avoid calling it.
+ There are three reasons for this:
+
+ - some instances cannot be created since they are abstract,
+ - some can only be created after qApp was created,
+ - some have an ugly __repr__ with angle brackets in it.
+
+ By using derived classes, good looking instances can be created
+ which can be used to generate source code or .pyi files. When the
+ real object is needed, the wrapper can simply be called.
+ """
+ def __repr__(self):
+ return f"{type(self).__name__}({self})"
+
+ def __call__(self):
+ from shibokensupport.signature.mapping import __dict__ as namespace
+ text = self if self.endswith(")") else self + "()"
+ return eval(text, namespace)
+
+
+USE_PEP563 = False
+# Note: we cannot know if this feature has been imported.
+# Otherwise it would be "sys.version_info[:2] >= (3, 7)".
+# We *can* eventually inspect sys.modules and look if
+# the calling module has this future statement set,
+# but should we do that?
+
+
+# Some types are abstract. They just show their name.
+class Virtual(_NotCalled):
+ pass
+
+
+# Other types I simply could not find.
+class Missing(_NotCalled):
+ # The string must be quoted, because the object does not exist.
+ def __repr__(self):
+ if USE_PEP563:
+ return _NotCalled.__repr__(self)
+ return f'{type(self).__name__}("{self}")'
+
+
+class Invalid(_NotCalled):
+ pass
+
+
+# Helper types
+class Default(_NotCalled):
+ pass
+
+
+class Instance(_NotCalled):
+ pass
+
+
+# Parameterized primitive variables
+class _Parameterized(object):
+ def __init__(self, type):
+ self.type = type
+ self.__name__ = self.__class__.__name__
+
+ def __repr__(self):
+ return f"{type(self).__name__}({self.type.__name__})"
+
+
+# Mark the primitive variables to be moved into the result.
+class ResultVariable(_Parameterized):
+ pass
+
+
+# Mark the primitive variables to become Sequence, Iterable or List
+# (decided in the parser).
+class ArrayLikeVariable(_Parameterized):
+ pass
+
+
+StringList = ArrayLikeVariable(str)
+
+
+class Reloader(object):
+ """
+ Reloder class
+
+ This is a singleton class which provides the update function for the
+ shiboken and PySide classes.
+ """
+ def __init__(self):
+ self.sys_module_count = 0
+
+ @staticmethod
+ def module_valid(mod):
+ if getattr(mod, "__file__", None) and not Path(mod.__file__).is_dir():
+ ending = Path(mod.__file__).suffix
+ return ending not in (".py", ".pyc", ".pyo", ".pyi")
+ return bool(hasattr(mod, "__name__") and is_builtin(mod.__name__))
+
+ def update(self):
+ """
+ 'update' imports all binary modules which are already in sys.modules.
+ The reason is to follow all user imports without introducing new ones.
+ This function is called by pyside_type_init to adapt imports
+ when the number of imported modules has changed.
+ """
+ if self.sys_module_count == len(sys.modules):
+ return
+ self.sys_module_count = len(sys.modules)
+ g = globals()
+ # PYSIDE-1009: Try to recognize unknown modules in errorhandler.py
+ candidates = list(mod_name for mod_name in sys.modules.copy()
+ if self.module_valid(sys.modules[mod_name]))
+ for mod_name in candidates:
+ # 'top' is PySide6 when we do 'import PySide.QtCore'
+ # or Shiboken if we do 'import Shiboken'.
+ # Convince yourself that these two lines below have the same
+ # global effect as "import Shiboken" or "import PySide6.QtCore".
+ top = __import__(mod_name)
+ g[top.__name__] = top
+ proc_name = "init_" + mod_name.replace(".", "_")
+ if proc_name in g:
+ # Modules are in place, we can update the type_map.
+ g.update(g.pop(proc_name)())
+
+
+def check_module(mod):
+ # During a build, there exist the modules already as directories,
+ # although the '*.so' was not yet created. This causes a problem
+ # in Python 3, because it accepts folders as namespace modules
+ # without enforcing an '__init__.py'.
+ if not Reloader.module_valid(mod):
+ mod_name = mod.__name__
+ raise ImportError(f"Module '{mod_name}' is not a binary module!")
+
+
+update_mapping = Reloader().update
+type_map = {}
+namespace = globals() # our module's __dict__
+
+type_map.update({
+ "...": ellipsis,
+ "Any": typing.Any,
+ "bool": bool,
+ "char": int,
+ "double": float,
+ "float": float,
+ "int": int,
+ "List": ArrayLikeVariable,
+ "Optional": typing.Optional,
+ "long": int,
+ "long long": int,
+ "nullptr": None,
+ "PyCallable": typing.Callable,
+ "PyObject": object,
+ "PyObject*": object,
+ "PyArrayObject": ArrayLikeVariable, # numpy
+ "PyPathLike": typing.Union[str, bytes, os.PathLike[str]],
+ "PySequence": typing.Iterable, # important for numpy
+ "PyTypeObject": type,
+ "QChar": str,
+ "QHash": typing.Dict,
+ "qint16": int,
+ "qint32": int,
+ "qint64": int,
+ "qint8": int,
+ "int16_t": int,
+ "int32_t": int,
+ "int64_t": int,
+ "int8_t": int,
+ "intptr_t": int,
+ "uintptr_t": int,
+ "qintptr": int,
+ "qsizetype": int,
+ "QFunctionPointer": int,
+ "QList": ArrayLikeVariable,
+ "qlonglong": int,
+ "QMap": typing.Dict,
+ "QMultiHash": typing.Dict,
+ "QMultiMap": typing.Dict,
+ "QPair": typing.Tuple,
+ "qptrdiff": int,
+ "qreal": float,
+ "QSet": typing.Set,
+ "QString": str,
+ "QLatin1String": str,
+ "QStringView": str,
+ "QStringList": StringList,
+ "quint16": int,
+ "quint32": int,
+ "quint32": int,
+ "quint64": int,
+ "quint8": int,
+ "uint16_t": int,
+ "uint32_t": int,
+ "uint64_t": int,
+ "uint8_t": int,
+ "Union": typing.Union,
+ "quintptr": int,
+ "qulonglong": int,
+ "QVariant": Variant,
+ "QVector": typing.List,
+ "QSharedPointer": typing.Tuple,
+ "real": float,
+ "short": int,
+ "signed char": int,
+ "signed long": int,
+ "std.list": typing.List,
+ "std.map": typing.Dict,
+ "std.nullptr_t": NoneType,
+ "std.pair": typing.Tuple,
+ "std.string": str,
+ "std.wstring": str,
+ "std.vector": typing.List,
+ "str": str,
+ "true": True,
+ "Tuple": typing.Tuple,
+ "uchar": int,
+ "uchar*": str,
+ "uint": int,
+ "ulong": int,
+ "ULONG_MAX": ulong_max,
+ "UINT64_MAX": 0xffffffff,
+ "unsigned char": int, # 5.9
+ "unsigned char*": str,
+ "unsigned int": int,
+ "unsigned long int": int, # 5.6, RHEL 6.6
+ "unsigned long long": int,
+ "unsigned long": int,
+ "unsigned short int": int, # 5.6, RHEL 6.6
+ "unsigned short": int,
+ "ushort": int,
+ "void": int, # be more specific?
+ "WId": WId,
+ "zero(bytes)": b"",
+ "zero(Char)": 0,
+ "zero(float)": 0,
+ "zero(int)": 0,
+ "zero(object)": None,
+ "zero(str)": "",
+ "zero(typing.Any)": None,
+ "zero(Any)": None,
+ # This can be refined by importing numpy.typing optionally, but better than nothing.
+ "numpy.ndarray": typing.List[typing.Any],
+ "std.array[int, 4]": typing.List[int],
+ "std.array[float, 4]": typing.List[float]
+})
+
+type_map.update({
+ # Handling variables declared as array:
+ "array double*" : ArrayLikeVariable(float),
+ "array float*" : ArrayLikeVariable(float),
+ "array GLint*" : ArrayLikeVariable(int),
+ "array GLuint*" : ArrayLikeVariable(int),
+ "array int*" : ArrayLikeVariable(int),
+ "array long long*" : ArrayLikeVariable(int),
+ "array long*" : ArrayLikeVariable(int),
+ "array short*" : ArrayLikeVariable(int),
+ "array signed char*" : typing.Union[bytes, bytearray, memoryview],
+ "array unsigned char*" : typing.Union[bytes, bytearray, memoryview],
+ "array unsigned int*" : ArrayLikeVariable(int),
+ "array unsigned short*" : ArrayLikeVariable(int),
+ # PYSIDE-1646: New macOS primitive types
+ "array int8_t*" : ArrayLikeVariable(int),
+ "array uint8_t*" : ArrayLikeVariable(int),
+ "array int16_t*" : ArrayLikeVariable(int),
+ "array uint16_t*" : ArrayLikeVariable(int),
+ "array int32_t*" : ArrayLikeVariable(int),
+ "array uint32_t*" : ArrayLikeVariable(int),
+ "array intptr_t*" : ArrayLikeVariable(int),
+})
+
+type_map.update({
+ # Special cases:
+ "char*" : typing.Union[bytes, bytearray, memoryview],
+ "QChar*" : typing.Union[bytes, bytearray, memoryview],
+ "quint32*" : int, # only for QRandomGenerator
+ "quint8*" : bytearray, # only for QCborStreamReader and QCborValue
+ "uchar*" : typing.Union[bytes, bytearray, memoryview],
+ "unsigned char*": typing.Union[bytes, bytearray, memoryview],
+})
+
+type_map.update({
+ # Handling variables that are returned, eventually as Tuples:
+ "PySide6.QtQml.atomic[bool]": ResultVariable(bool), # QmlIncubationController::incubateWhile()
+ "bool*" : ResultVariable(bool),
+ "float*" : ResultVariable(float),
+ "int*" : ResultVariable(int),
+ "long long*" : ResultVariable(int),
+ "long*" : ResultVariable(int),
+ "PStr*" : ResultVariable(str), # module sample
+ "qint32*" : ResultVariable(int),
+ "qint64*" : ResultVariable(int),
+ "qreal*" : ResultVariable(float),
+ "qsizetype*" : ResultVariable(int),
+ "QString*" : ResultVariable(str),
+ "qintptr*" : ResultVariable(int),
+ "quintptr*" : ResultVariable(int),
+ "quint16*" : ResultVariable(int),
+ "uint*" : ResultVariable(int),
+ "unsigned int*" : ResultVariable(int),
+ "QStringList*" : ResultVariable(StringList),
+})
+
+
+type_map.update({
+ # Hack, until improving the parser:
+ "[typing.Any]" : [typing.Any],
+ "[typing.Any,typing.Any]" : [typing.Any, typing.Any],
+ "None" : None,
+})
+
+
+# PYSIDE-1328: We need to handle "self" explicitly.
+type_map.update({
+ "self" : "self",
+ "cls" : "cls",
+})
+
+# PYSIDE-1538: We need to treat "std::optional" accordingly.
+type_map.update({
+ "std.optional": typing.Optional,
+ })
+
+
+# The Shiboken Part
+def init_Shiboken():
+ type_map.update({
+ "PyType": type,
+ "shiboken6.bool": bool,
+ "size_t": int,
+ })
+ return locals()
+
+
+def init_minimal():
+ type_map.update({
+ "MinBool": bool,
+ })
+ return locals()
+
+
+def init_sample():
+ import datetime
+ type_map.update({
+ "char": int,
+ "char**": typing.List[str],
+ "const char*": str,
+ "Complex": complex,
+ "double": float,
+ "ByteArray&": typing.Union[bytes, bytearray, memoryview],
+ "Foo.HANDLE": int,
+ "HANDLE": int,
+ "Null": None,
+ "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"),
+ "OddBool": bool,
+ "PStr": str,
+ "PyDate": datetime.date,
+ "PyBuffer": typing.Union[bytes, bytearray, memoryview],
+ "sample.bool": bool,
+ "sample.char": int,
+ "sample.double": float,
+ "sample.int": int,
+ "sample.ObjectType": object,
+ "sample.OddBool": bool,
+ "sample.Photon.TemplateBase[Photon.DuplicatorType]": sample.Photon.ValueDuplicator,
+ "sample.Photon.TemplateBase[Photon.IdentityType]": sample.Photon.ValueIdentity,
+ "sample.Point": Point,
+ "sample.PStr": str,
+ "SampleNamespace.InValue.ZeroIn": 0,
+ "sample.unsigned char": int,
+ "std.size_t": int,
+ "std.string": str,
+ "ZeroIn": 0,
+ 'Str("<unk")': "<unk",
+ 'Str("<unknown>")': "<unknown>",
+ 'Str("nown>")': "nown>",
+ })
+ return locals()
+
+
+def init_other():
+ import numbers
+ type_map.update({
+ "other.ExtendsNoImplicitConversion": Missing("other.ExtendsNoImplicitConversion"),
+ "other.Number": numbers.Number,
+ })
+ return locals()
+
+
+def init_smart():
+ # This missing type should be defined in module smart. We cannot set it to Missing()
+ # because it is a container type. Therefore, we supply a surrogate:
+ global SharedPtr
+
+ class SharedPtr(Generic[_S]):
+ __module__ = "smart"
+ smart.SharedPtr = SharedPtr
+ type_map.update({
+ "smart.Smart.Integer2": int,
+ })
+ return locals()
+
+
+# The PySide Part
+def init_PySide6_QtCore():
+ from PySide6.QtCore import Qt, QUrl, QDir, QKeyCombination
+ from PySide6.QtCore import QRect, QRectF, QSize, QPoint, QLocale, QByteArray
+ from PySide6.QtCore import QMarginsF # 5.9
+ from PySide6.QtCore import SignalInstance
+ try:
+ # seems to be not generated by 5.9 ATM.
+ from PySide6.QtCore import Connection
+ except ImportError:
+ pass
+ type_map.update({
+ "' '": " ",
+ "'%'": "%",
+ "'g'": "g",
+ "4294967295UL": 4294967295, # 5.6, RHEL 6.6
+ "CheckIndexOption.NoOption": Instance(
+ "PySide6.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11
+ "DescriptorType(-1)": int, # Native handle of QSocketDescriptor
+ "false": False,
+ "list of QAbstractAnimation": typing.List[PySide6.QtCore.QAbstractAnimation],
+ "long long": int,
+ "size_t": int,
+ "NULL": None, # 5.6, MSVC
+ "nullptr": None, # 5.9
+ "PyBuffer": typing.Union[bytes, bytearray, memoryview],
+ "PyByteArray": bytearray,
+ "PyBytes": typing.Union[bytes, bytearray, memoryview],
+ "PyTuple": typing.Tuple,
+ "QDeadlineTimer(QDeadlineTimer.Forever)": Instance("PySide6.QtCore.QDeadlineTimer"),
+ "PySide6.QtCore.QUrl.ComponentFormattingOptions":
+ PySide6.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why???
+ "PyUnicode": typing.Text,
+ "QByteArrayView": QByteArray,
+ "Q_NULLPTR": None,
+ "QCalendar.Unspecified": PySide6.QtCore.QCalendar.Unspecified,
+ "QCborTag(-1)": ulong_max,
+ "QDir.Filters(AllEntries | NoDotAndDotDot)": Instance(
+ "QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot)"),
+ "QDir.SortFlags(Name | IgnoreCase)": Instance(
+ "QDir.SortFlags(QDir.Name | QDir.IgnoreCase)"),
+ "QEvent.Type.None": None,
+ "QGenericArgument((0))": ellipsis, # 5.6, RHEL 6.6. Is that ok?
+ "QGenericArgument()": ellipsis,
+ "QGenericArgument(0)": ellipsis,
+ "QGenericArgument(NULL)": ellipsis, # 5.6, MSVC
+ "QGenericArgument(nullptr)": ellipsis, # 5.10
+ "QGenericArgument(Q_NULLPTR)": ellipsis,
+ "QJsonObject": typing.Dict[str, PySide6.QtCore.QJsonValue],
+ "QModelIndex()": Invalid("PySide6.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?!
+ "QModelIndexList": typing.List[PySide6.QtCore.QModelIndex],
+ "PySideSignalInstance": SignalInstance,
+ "QString()": "",
+ "Flag.Default": Instance("PySide6.QtCore.QStringConverterBase.Flags"),
+ "QStringList()": [],
+ "QStringRef": str,
+ "QStringRef": str,
+ "Qt.HANDLE": int, # be more explicit with some constants?
+ "QUrl.FormattingOptions(PrettyDecoded)": Instance(
+ "QUrl.FormattingOptions(QUrl.PrettyDecoded)"),
+ "QVariant()": Invalid(Variant),
+ "QVariant.Type": type, # not so sure here...
+ "QVariantMap": typing.Dict[str, Variant],
+ "std.chrono.seconds{5}" : ellipsis,
+ })
+ try:
+ type_map.update({
+ "PySide6.QtCore.QMetaObject.Connection": PySide6.QtCore.Connection, # wrong!
+ })
+ except AttributeError:
+ # this does not exist on 5.9 ATM.
+ pass
+
+ # special case - char* can either be 'bytes' or 'str'. The default is 'bytes'.
+ # Here we manually set it to map to 'str'.
+ type_map.update({("PySide6.QtCore.QObject.setProperty", "char*"): str})
+ type_map.update({("PySide6.QtCore.QObject.property", "char*"): str})
+
+ return locals()
+
+
+def init_PySide6_QtConcurrent():
+ type_map.update({
+ "PySide6.QtCore.QFuture[QString]":
+ PySide6.QtConcurrent.QFutureQString,
+ "PySide6.QtCore.QFuture[void]":
+ PySide6.QtConcurrent.QFutureVoid,
+ })
+ return locals()
+
+
+def init_PySide6_QtGui():
+ from PySide6.QtGui import QPageLayout, QPageSize # 5.12 macOS
+ type_map.update({
+ "0.0f": 0.0,
+ "1.0f": 1.0,
+ "GL_COLOR_BUFFER_BIT": GL_COLOR_BUFFER_BIT,
+ "GL_NEAREST": GL_NEAREST,
+ "int32_t": int,
+ "HBITMAP": int,
+ "HICON": int,
+ "HMONITOR": int,
+ "HRGN": int,
+ "QPixmap()": Default("PySide6.QtGui.QPixmap"), # can't create without qApp
+ "QPlatformSurface*": int, # a handle
+ "QVector< QTextLayout.FormatRange >()": [], # do we need more structure?
+ "uint32_t": int,
+ "uint8_t": int,
+ "USHRT_MAX": ushort_max,
+ })
+
+ # special case - char* can either be 'bytes' or 'str'. The default is 'bytes'.
+ # Here we manually set it to map to 'str'.
+ type_map.update({("PySide6.QtGui.QPixmap.save", "char*"): str})
+
+ return locals()
+
+
+def init_PySide6_QtWidgets():
+ from PySide6.QtWidgets import (QWidget, QMessageBox, QStyleOption,
+ QStyleHintReturn, QStyleOptionComplex,
+ QGraphicsItem, QStyleOptionGraphicsItem)
+ type_map.update({
+ "QMessageBox.StandardButtons(Yes | No)": Instance(
+ "QMessageBox.StandardButtons(QMessageBox.Yes | QMessageBox.No)"),
+ "QWidget.RenderFlags(DrawWindowBackground | DrawChildren)": Instance(
+ "QWidget.RenderFlags(QWidget.DrawWindowBackground | QWidget.DrawChildren)"),
+ "static_cast<Qt.MatchFlags>(Qt.MatchExactly|Qt.MatchCaseSensitive)": Instance(
+ "Qt.MatchFlags(Qt.MatchExactly | Qt.MatchCaseSensitive)"),
+ "static_cast<Qt.MatchFlag>(Qt.MatchExactly|Qt.MatchCaseSensitive)": Instance(
+ "Qt.MatchFlag(Qt.MatchExactly | Qt.MatchCaseSensitive)"),
+ "QListWidgetItem.ItemType.Type": PySide6.QtWidgets.QListWidgetItem.Type,
+ "QTableWidgetItem.ItemType.Type": PySide6.QtWidgets.QTableWidgetItem.Type,
+ "QTreeWidgetItem.ItemType.Type": PySide6.QtWidgets.QTreeWidgetItem.Type,
+ })
+ return locals()
+
+
+def init_PySide6_QtSql():
+ from PySide6.QtSql import QSqlDatabase
+ type_map.update({
+ "QLatin1StringView(QSqlDatabase.defaultConnection)": QSqlDatabase.defaultConnection,
+ "QVariant.Invalid": Invalid("Variant"), # not sure what I should create, here...
+ })
+ return locals()
+
+
+def init_PySide6_QtNetwork():
+ from PySide6.QtNetwork import QNetworkRequest, QHostAddress
+ best_structure = typing.OrderedDict if getattr(typing, "OrderedDict", None) else typing.Dict
+ type_map.update({
+ "QMultiMap[PySide6.QtNetwork.QSsl.AlternativeNameEntryType, QString]":
+ best_structure[PySide6.QtNetwork.QSsl.AlternativeNameEntryType, typing.List[str]],
+ "DefaultTransferTimeoutConstant":
+ QNetworkRequest.TransferTimeoutConstant,
+ "QNetworkRequest.DefaultTransferTimeoutConstant":
+ QNetworkRequest.TransferTimeoutConstant,
+ })
+ del best_structure
+ return locals()
+
+
+def init_PySide6_QtOpenGL():
+ type_map.update({
+ "GLbitfield": int,
+ "GLenum": int,
+ "GLfloat": float, # 5.6, MSVC 15
+ "GLint": int,
+ "GLuint": int,
+ })
+ return locals()
+
+
+def init_PySide6_QtQml():
+ type_map.update({
+ "VolatileBool": PySide6.QtQml.VolatileBool,
+ })
+ return locals()
+
+
+def init_PySide6_QtQuick():
+ type_map.update({
+ "PySide6.QtQuick.QSharedPointer[PySide6.QtQuick.QQuickItemGrabResult]":
+ PySide6.QtQuick.QQuickItemGrabResult,
+ "QSGGeometry.Type.UnsignedShortType": int,
+ })
+ return locals()
+
+
+def init_PySide6_QtTest():
+ from PySide6.QtCore import SignalInstance
+ type_map.update({
+ "PySideSignalInstance": SignalInstance,
+ "PySide6.QtTest.QTest.PySideQTouchEventSequence": PySide6.QtTest.QTest.QTouchEventSequence,
+ "PySide6.QtTest.QTouchEventSequence": PySide6.QtTest.QTest.QTouchEventSequence,
+ })
+ return locals()
+
+
+# from 5.12, macOS
+def init_PySide6_QtDataVisualization():
+ from PySide6.QtDataVisualization import (QBarDataItem, QSurfaceDataItem)
+ QBarDataRow = typing.List[QBarDataItem]
+ QBarDataArray = typing.List[QBarDataRow]
+ QSurfaceDataRow = typing.List[QSurfaceDataItem]
+ QSurfaceDataArray = typing.List[QSurfaceDataRow]
+ type_map.update({
+ "100.0f": 100.0,
+ "QBarDataArray": QBarDataArray,
+ "QBarDataArray*": QBarDataArray,
+ "QSurfaceDataArray": QSurfaceDataArray,
+ "QSurfaceDataArray*": QSurfaceDataArray,
+ })
+ return locals()
+
+
+def init_PySide6_QtBluetooth():
+ type_map.update({
+ "QVariant*": object,
+ })
+ return locals()
+
+
+def init_PySide6_QtGraphs():
+ from PySide6.QtGraphs import (QBarDataItem, QSurfaceDataItem)
+ QBarDataRow = typing.List[QBarDataItem]
+ QBarDataArray = typing.List[QBarDataRow]
+ QSurfaceDataRow = typing.List[QSurfaceDataItem]
+ QSurfaceDataArray = typing.List[QSurfaceDataRow]
+ type_map.update({
+ "100.0f": 100.0,
+ "QBarDataArray": QBarDataArray,
+ "QBarDataArray*": QBarDataArray,
+ "QSurfaceDataArray": QSurfaceDataArray,
+ "QSurfaceDataArray*": QSurfaceDataArray,
+ })
+ return locals()
+
+
+def init_PySide6_QtHttpServer():
+ type_map.update({
+ "qMakePair(1u, 1u)": (1, 1),
+ })
+ return locals()
+
+
+def init_testbinding():
+ type_map.update({
+ "testbinding.PySideCPP2.TestObjectWithoutNamespace": testbinding.TestObjectWithoutNamespace,
+ "testbinding.FlagsNamespace.Options": testbinding.Option,
+ "FlagsNamespace.Option.NoOptions": 0,
+ "StdIntList": typing.List[int],
+ 'Str("")': str(""),
+ })
+ return locals()
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
new file mode 100644
index 000000000..9b48ab442
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -0,0 +1,552 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import ast
+import enum
+import keyword
+import os
+import re
+import sys
+import typing
+import warnings
+
+from types import SimpleNamespace
+from shibokensupport.signature.mapping import (type_map, update_mapping,
+ namespace, _NotCalled, ResultVariable, ArrayLikeVariable) # noqa E:128
+from shibokensupport.signature.lib.tool import build_brace_pattern
+
+_DEBUG = False
+LIST_KEYWORDS = False
+
+"""
+parser.py
+
+This module parses the signature text and creates properties for the
+signature objects.
+
+PySide has a new function 'CppGenerator::writeSignatureInfo()'
+that extracts the gathered information about the function arguments
+and defaults as good as it can. But what PySide generates is still
+very C-ish and has many constants that Python doesn't understand.
+
+The function 'try_to_guess()' below understands a lot of PySide's
+peculiar way to assume local context. If it is able to do the guess,
+then the result is inserted into the dict, so the search happens
+not again. For everything that is not covered by these automatic
+guesses, we provide an entry in 'type_map' that resolves it.
+
+In effect, 'type_map' maps text to real Python objects.
+"""
+
+
+def _get_flag_enum_option():
+ from shiboken6 import (__version_info__ as ver, # noqa F:401
+ __minimum_python_version__ as pyminver,
+ __maximum_python_version__ as pymaxver)
+
+ # PYSIDE-1735: Use the new Enums per default if version is >= 6.4
+ # This decides between delivered vs. dev versions.
+ # When 6.4 is out, the switching mode will be gone.
+ flag = ver[:2] >= (6, 4)
+ envname = "PYSIDE6_OPTION_PYTHON_ENUM"
+ sysname = envname.lower()
+ opt = os.environ.get(envname)
+ if opt:
+ opt = opt.lower()
+ if opt in ("yes", "on", "true"):
+ flag = True
+ elif opt in ("no", "off", "false"):
+ flag = False
+ else:
+ # instead of a simple int() conversion, let's allow for "0xf" or "0b1111"
+ try:
+ flag = ast.literal_eval(opt)
+ except Exception:
+ flag = False # turn a forbidden option into an error
+ elif hasattr(sys, sysname):
+ opt2 = flag = getattr(sys, sysname)
+ if not isinstance(flag, int):
+ flag = False # turn a forbidden option into an error
+ p = f"\n *** Python is at version {'.'.join(map(str, pyminver or (0,)))} now."
+ q = f"\n *** PySide is at version {'.'.join(map(str, ver[:2]))} now."
+ # _PepUnicode_AsString: Fix a broken promise
+ if pyminver and pyminver >= (3, 10):
+ warnings.warn(f"{p} _PepUnicode_AsString can now be replaced by PyUnicode_AsUTF8! ***")
+ # PYSIDE-1960: Emit a warning when we may remove bufferprocs_py37.(cpp|h)
+ if pyminver and pyminver >= (3, 11):
+ warnings.warn(f"{p} The files bufferprocs_py37.(cpp|h) should be removed ASAP! ***")
+ # PYSIDE-1735: Emit a warning when we should maybe evict forgiveness mode
+ if ver[:2] >= (7, 0):
+ warnings.warn(f"{q} Please drop Enum forgiveness mode in `mangled_type_getattro` ***")
+ # PYSIDE-2404: Emit a warning when we should drop uppercase offset constants
+ if ver[:2] >= (7, 0):
+ warnings.warn(f"{q} Please drop uppercase type offsets in `copyOffsetEnumStream` ***")
+ # normalize the sys attribute
+ setattr(sys, sysname, flag)
+ os.environ[envname] = str(flag)
+ if int(flag) == 0:
+ raise RuntimeError(f"Old Enums are no longer supported. int({opt or opt2}) evaluates to 0)")
+ return flag
+
+
+class EnumSelect(enum.Enum):
+ # PYSIDE-1735: Here we could save object.value expressions by using IntEnum.
+ # But it is nice to use just an Enum for selecting Enum version.
+ OLD = 1
+ NEW = 2
+ SELECTION = NEW if _get_flag_enum_option() else OLD
+
+
+def dprint(*args, **kw):
+ if _DEBUG:
+ import pprint
+ for arg in args:
+ pprint.pprint(arg)
+ sys.stdout.flush()
+
+
+_cache = {}
+
+
+def _parse_arglist(argstr):
+ # The following is a split re. The string is broken into pieces which are
+ # between the recognized strings. Because the re has groups, both the
+ # strings and the separators are returned, where the strings are not
+ # interesting at all: They are just the commata.
+ key = "_parse_arglist"
+ if key not in _cache:
+ regex = build_brace_pattern(level=3, separators=",")
+ _cache[key] = re.compile(regex, flags=re.VERBOSE)
+ split = _cache[key].split
+ # Note: this list is interspersed with "," and surrounded by ""
+ return [x.strip() for x in split(argstr) if x.strip() not in ("", ",")]
+
+
+def _parse_line(line):
+ line_re = r"""
+ ((?P<multi> ([0-9]+)) : )? # the optional multi-index
+ (?P<funcname> \w+(\.\w+)*) # the function name
+ \( (?P<arglist> .*?) \) # the argument list
+ ( -> (?P<returntype> .*) )? # the optional return type
+ $
+ """
+ matches = re.match(line_re, line, re.VERBOSE)
+ if not matches:
+ raise SystemError("Error parsing line:", repr(line))
+ ret = SimpleNamespace(**matches.groupdict())
+ # PYSIDE-1095: Handle arbitrary default expressions
+ argstr = ret.arglist.replace("->", ".deref.")
+ arglist = _parse_arglist(argstr)
+ args = []
+ for idx, arg in enumerate(arglist):
+ tokens = arg.split(":")
+ if len(tokens) < 2 and idx == 0 and tokens[0] in ("self", "cls"):
+ tokens = 2 * tokens # "self: self"
+ if len(tokens) != 2:
+ # This should never happen again (but who knows?)
+ raise SystemError(f'Invalid argument "{arg}" in "{line}".')
+ name, ann = tokens
+ if name in keyword.kwlist:
+ if LIST_KEYWORDS:
+ print("KEYWORD", ret)
+ name = name + "_"
+ if "=" in ann:
+ ann, default = ann.split("=", 1)
+ tup = name, ann, default
+ else:
+ tup = name, ann
+ args.append(tup)
+ ret.arglist = args
+ multi = ret.multi
+ if multi is not None:
+ ret.multi = int(multi)
+ funcname = ret.funcname
+ parts = funcname.split(".")
+ if parts[-1] in keyword.kwlist:
+ ret.funcname = funcname + "_"
+ return vars(ret)
+
+
+def _using_snake_case():
+ # Note that this function should stay here where we use snake_case.
+ if "PySide6.QtCore" not in sys.modules:
+ return False
+ from PySide6.QtCore import QDir
+ return hasattr(QDir, "cd_up")
+
+
+def _handle_instance_fixup(thing):
+ """
+ Default expressions using instance methods like
+ (...,device=QPointingDevice.primaryPointingDevice())
+ need extra handling for snake_case. These are:
+ QPointingDevice.primaryPointingDevice()
+ QInputDevice.primaryKeyboard()
+ QKeyCombination.fromCombined(0)
+ QSslConfiguration.defaultConfiguration()
+ """
+ match = re.search(r"\w+\(", thing)
+ if not match:
+ return thing
+ start, stop = match.start(), match.end() - 1
+ pre, func, args = thing[:start], thing[start:stop], thing[stop:]
+ if func[0].isupper() or func.startswith("gl") and func[2:3].isupper():
+ return thing
+ # Now convert this string to snake case.
+ snake_func = ""
+ for idx, char in enumerate(func):
+ if char.isupper():
+ if idx and func[idx - 1].isupper():
+ # two upper chars are forbidden
+ return thing
+ snake_func += f"_{char.lower()}"
+ else:
+ snake_func += char
+ return f"{pre}{snake_func}{args}"
+
+
+def make_good_value(thing, valtype):
+ # PYSIDE-1019: Handle instance calls (which are really seldom)
+ if "(" in thing and _using_snake_case():
+ thing = _handle_instance_fixup(thing)
+ try:
+ if thing.endswith("()"):
+ thing = f'Default("{thing[:-2]}")'
+ else:
+ # PYSIDE-1735: Use explicit globals and locals because of a bug in VsCode
+ ret = eval(thing, globals(), namespace)
+ if valtype and repr(ret).startswith("<"):
+ thing = f'Instance("{thing}")'
+ return eval(thing, globals(), namespace)
+ except Exception:
+ pass
+
+
+def try_to_guess(thing, valtype):
+ if "." not in thing and "(" not in thing:
+ text = f"{valtype}.{thing}"
+ ret = make_good_value(text, valtype)
+ if ret is not None:
+ return ret
+ typewords = valtype.split(".")
+ valwords = thing.split(".")
+ braceless = valwords[0] # Yes, not -1. Relevant is the overlapped word.
+ if "(" in braceless:
+ braceless = braceless[:braceless.index("(")]
+ for idx, w in enumerate(typewords):
+ if w == braceless:
+ text = ".".join(typewords[:idx] + valwords)
+ ret = make_good_value(text, valtype)
+ if ret is not None:
+ return ret
+ return None
+
+
+def get_name(thing):
+ if isinstance(thing, type):
+ return getattr(thing, "__qualname__", thing.__name__)
+ else:
+ return thing.__name__
+
+
+def _resolve_value(thing, valtype, line):
+ if thing in ("0", "None") and valtype:
+ if valtype.startswith("PySide6.") or valtype.startswith("typing."):
+ return None
+ map = type_map[valtype]
+ # typing.Any: '_SpecialForm' object has no attribute '__name__'
+ name = get_name(map) if hasattr(map, "__name__") else str(map)
+ thing = f"zero({name})"
+ if thing in type_map:
+ return type_map[thing]
+ res = make_good_value(thing, valtype)
+ if res is not None:
+ type_map[thing] = res
+ return res
+ res = try_to_guess(thing, valtype) if valtype else None
+ if res is not None:
+ type_map[thing] = res
+ return res
+ warnings.warn(f"""pyside_type_init:_resolve_value
+
+ UNRECOGNIZED: {thing!r}
+ OFFENDING LINE: {line!r}
+ """, RuntimeWarning)
+ return thing
+
+
+def _resolve_arraytype(thing, line):
+ search = re.search(r"\[(\d*)\]$", thing)
+ thing = thing[:search.start()]
+ if thing.endswith("]"):
+ thing = _resolve_arraytype(thing, line)
+ if search.group(1):
+ # concrete array, use a tuple
+ nelem = int(search.group(1))
+ thing = ", ".join([thing] * nelem)
+ thing = "Tuple[" + thing + "]"
+ else:
+ thing = "QList[" + thing + "]"
+ return thing
+
+
+def to_string(thing):
+ # This function returns a string that creates the same object.
+ # It is absolutely crucial that str(eval(thing)) == str(thing),
+ # i.e. it must be an idempotent mapping.
+ if isinstance(thing, str):
+ return thing
+ if hasattr(thing, "__name__") and thing.__module__ != "typing":
+ m = thing.__module__
+ dot = "." in str(thing) or m not in (thing.__qualname__, "builtins")
+ name = get_name(thing)
+ ret = m + "." + name if dot else name
+ assert (eval(ret, globals(), namespace))
+ return ret
+ # Note: This captures things from the typing module:
+ return str(thing)
+
+
+matrix_pattern = "PySide6.QtGui.QGenericMatrix"
+
+
+def handle_matrix(arg):
+ n, m, typstr = tuple(map(lambda x: x.strip(), arg.split(",")))
+ assert typstr == "float"
+ result = f"PySide6.QtGui.QMatrix{n}x{m}"
+ return eval(result, globals(), namespace)
+
+
+def _resolve_type(thing, line, level, var_handler, func_name=None):
+ # manual set of 'str' instead of 'bytes'
+ if func_name:
+ new_thing = (func_name, thing)
+ if new_thing in type_map:
+ return type_map[new_thing]
+
+ # Capture total replacements, first. Happens in
+ # "PySide6.QtCore.QCborStreamReader.StringResult[PySide6.QtCore.QByteArray]"
+ if thing in type_map:
+ return type_map[thing]
+
+ # Now the nested structures are handled.
+ if "[" in thing:
+ # handle primitive arrays
+ if re.search(r"\[\d*\]$", thing):
+ thing = _resolve_arraytype(thing, line)
+ # Handle a container return type. (see PYSIDE-921 in cppgenerator.cpp)
+ contr, thing = re.match(r"(.*?)\[(.*?)\]$", thing).groups()
+ # Special case: Handle the generic matrices.
+ if contr == matrix_pattern:
+ return handle_matrix(thing)
+ contr = var_handler(_resolve_type(contr, line, level + 1, var_handler))
+ if isinstance(contr, _NotCalled):
+ raise SystemError("Container types must exist:", repr(contr))
+ contr = to_string(contr)
+ pieces = []
+ for part in _parse_arglist(thing):
+ part = var_handler(_resolve_type(part, line, level + 1, var_handler))
+ if isinstance(part, _NotCalled):
+ # fix the tag (i.e. "Missing") by repr
+ part = repr(part)
+ pieces.append(to_string(part))
+ thing = ", ".join(pieces)
+ result = f"{contr}[{thing}]"
+ # PYSIDE-1538: Make sure that the eval does not crash.
+ try:
+ return eval(result, globals(), namespace)
+ except Exception:
+ warnings.warn(f"""pyside_type_init:_resolve_type
+
+ UNRECOGNIZED: {result!r}
+ OFFENDING LINE: {line!r}
+ """, RuntimeWarning)
+ return _resolve_value(thing, None, line)
+
+
+def _handle_generic(obj, repl):
+ """
+ Assign repl if obj is an ArrayLikeVariable
+
+ This is a neat trick. Example:
+
+ obj repl result
+ ---------------------- -------- ---------
+ ArrayLikeVariable List List
+ ArrayLikeVariable(str) List List[str]
+ ArrayLikeVariable Sequence Sequence
+ ArrayLikeVariable(str) Sequence Sequence[str]
+ """
+ if isinstance(obj, ArrayLikeVariable):
+ return repl[obj.type]
+ if isinstance(obj, type) and issubclass(obj, ArrayLikeVariable):
+ # was "if obj is ArrayLikeVariable"
+ return repl
+ return obj
+
+
+def handle_argvar(obj):
+ """
+ Decide how array-like variables are resolved in arguments
+
+ Currently, the best approximation is types.Sequence.
+ We want to change that to types.Iterable in the near future.
+ """
+ return _handle_generic(obj, typing.Sequence)
+
+
+def handle_retvar(obj):
+ """
+ Decide how array-like variables are resolved in results
+
+ This will probably stay typing.List forever.
+ """
+ return _handle_generic(obj, typing.List)
+
+
+def calculate_props(line):
+ parsed = SimpleNamespace(**_parse_line(line.strip()))
+ arglist = parsed.arglist
+ annotations = {}
+ _defaults = []
+ for idx, tup in enumerate(arglist):
+ name, ann = tup[:2]
+ if ann == "...":
+ name = "*args" if name.startswith("arg_") else "*" + name
+ # copy the patched fields back
+ ann = 'nullptr' # maps to None
+ tup = name, ann
+ arglist[idx] = tup
+ annotations[name] = _resolve_type(ann, line, 0, handle_argvar, parsed.funcname)
+ if len(tup) == 3:
+ default = _resolve_value(tup[2], ann, line)
+ _defaults.append(default)
+ defaults = tuple(_defaults)
+ returntype = parsed.returntype
+ if isinstance(returntype, str) and returntype.startswith("("):
+ # PYSIDE-1588: Simplify the handling of returned tuples for now.
+ # Later we might create named tuples, instead.
+ returntype = "Tuple"
+ # PYSIDE-1383: We need to handle `None` explicitly.
+ annotations["return"] = (_resolve_type(returntype, line, 0, handle_retvar)
+ if returntype is not None else None)
+ props = SimpleNamespace()
+ props.defaults = defaults
+ props.kwdefaults = {}
+ props.annotations = annotations
+ props.varnames = tuple(tup[0] for tup in arglist)
+ funcname = parsed.funcname
+ shortname = funcname[funcname.rindex(".") + 1:]
+ props.name = shortname
+ props.multi = parsed.multi
+ fix_variables(props, line)
+ return vars(props)
+
+
+def fix_variables(props, line):
+ annos = props.annotations
+ if not any(isinstance(ann, (ResultVariable, ArrayLikeVariable))
+ for ann in annos.values()):
+ return
+ retvar = annos.get("return", None)
+ if retvar and isinstance(retvar, (ResultVariable, ArrayLikeVariable)):
+ # Special case: a ResultVariable which is the result will always be an array!
+ annos["return"] = retvar = typing.List[retvar.type]
+ varnames = list(props.varnames)
+ defaults = list(props.defaults)
+ diff = len(varnames) - len(defaults)
+
+ safe_annos = annos.copy()
+ retvars = [retvar] if retvar else []
+ deletions = []
+ for idx, name in enumerate(varnames):
+ ann = safe_annos[name]
+ if isinstance(ann, ArrayLikeVariable):
+ ann = typing.Sequence[ann.type]
+ annos[name] = ann
+ if not isinstance(ann, ResultVariable):
+ continue
+ # We move the variable to the end and remove it.
+ # PYSIDE-1409: If the variable was the first arg, we move it to the front.
+ # XXX This algorithm should probably be replaced by more introspection.
+ retvars.insert(0 if idx == 0 else len(retvars), ann.type)
+ deletions.append(idx)
+ del annos[name]
+ for idx in reversed(deletions):
+ # varnames: 0 1 2 3 4 5 6 7
+ # defaults: 0 1 2 3 4
+ # diff: 3
+ del varnames[idx]
+ if idx >= diff:
+ del defaults[idx - diff]
+ else:
+ diff -= 1
+ if retvars:
+ retvars = list(handle_retvar(rv) if isinstance(rv, ArrayLikeVariable) else rv
+ for rv in retvars)
+ if len(retvars) == 1:
+ returntype = retvars[0]
+ else:
+ retvars_str = ", ".join(map(to_string, retvars))
+ typestr = f"typing.Tuple[{retvars_str}]"
+ returntype = eval(typestr, globals(), namespace)
+ props.annotations["return"] = returntype
+ props.varnames = tuple(varnames)
+ props.defaults = tuple(defaults)
+
+
+def fixup_multilines(lines):
+ """
+ Multilines can collapse when certain distinctions between C++ types
+ vanish after mapping to Python.
+ This function fixes this by re-computing multiline-ness.
+ """
+ res = []
+ multi_lines = []
+ for line in lines:
+ multi = re.match(r"([0-9]+):", line)
+ if multi:
+ idx, rest = int(multi.group(1)), line[multi.end():]
+ multi_lines.append(rest)
+ if idx > 0:
+ continue
+ # remove duplicates
+ multi_lines = sorted(set(multi_lines))
+ # renumber or return a single line
+ nmulti = len(multi_lines)
+ if nmulti > 1:
+ for idx, line in enumerate(multi_lines):
+ res.append(f"{nmulti-idx-1}:{line}")
+ else:
+ res.append(multi_lines[0])
+ multi_lines = []
+ else:
+ res.append(line)
+ return res
+
+
+def pyside_type_init(type_key, sig_strings):
+ dprint()
+ dprint(f"Initialization of type key '{type_key}'")
+ update_mapping()
+ lines = fixup_multilines(sig_strings)
+ ret = {}
+ multi_props = []
+ for line in lines:
+ props = calculate_props(line)
+ shortname = props["name"]
+ multi = props["multi"]
+ if multi is None:
+ ret[shortname] = props
+ dprint(props)
+ else:
+ multi_props.append(props)
+ if multi > 0:
+ continue
+ multi_props = {"multi": multi_props}
+ ret[shortname] = multi_props
+ dprint(multi_props)
+ multi_props = []
+ return ret
+
+# end of file
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json
new file mode 100644
index 000000000..0f05aea8b
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "python",
+ "Name": "Python",
+ "QDocModule": "QtForPython",
+ "QtUsage": "Used for Qt for Python in the signature extension.",
+ "Description": "Qt for Python is an add-on for Python. The signature packages of PySide uses certain copied and adapted source files. See the folder sources/shiboken6/files.dir/shibokensupport .",
+ "Homepage": "http://www.python.org/",
+ "Version": "3.7.0",
+ "LicenseId": "Python-2.0",
+ "License": "Python License 2.0",
+ "LicenseFile": "PSF-3.7.0.txt",
+ "Copyright": "© Copyright 2001-2018, Python Software Foundation."
+}
diff --git a/sources/shiboken6/shibokenmodule/nothing.h b/sources/shiboken6/shibokenmodule/nothing.h
new file mode 100644
index 000000000..2f558afcb
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/nothing.h
@@ -0,0 +1,3 @@
+// This is a placeholder file for shiboken, because shiboken expects a header file listing the
+// header files whose bindings are to be created. This file is empty because shibokenmodule
+// functions are implemented directly inside the typesystem_shiboken.xml file through CPython code.
diff --git a/sources/shiboken6/shibokenmodule/py.typed.in b/sources/shiboken6/shibokenmodule/py.typed.in
new file mode 100644
index 000000000..0e76a07dc
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/py.typed.in
@@ -0,0 +1 @@
+# this is a marker file for mypy
diff --git a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp
new file mode 100644
index 000000000..5c6219885
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp
@@ -0,0 +1,119 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// @snippet isvalid
+bool isValid = Shiboken::Object::isValid(%1, false);
+%PYARG_0 = %CONVERTTOPYTHON[bool](isValid);
+// @snippet isvalid
+
+// @snippet wrapinstance
+auto *pyType = reinterpret_cast<PyTypeObject *>(%2);
+if (Shiboken::ObjectType::checkType(pyType)) {
+ auto *ptr = reinterpret_cast<void *>(%1);
+ if (auto *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(ptr)) {
+ Py_INCREF(wrapper);
+ %PYARG_0 = reinterpret_cast<PyObject *>(wrapper);
+ } else {
+ %PYARG_0 = Shiboken::Object::newObject(pyType, ptr, false, true);
+ }
+} else {
+ PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet wrapinstance
+
+// @snippet getcpppointer
+if (Shiboken::Object::checkType(%1)) {
+ std::vector<void*> ptrs = Shiboken::Object::cppPointers(reinterpret_cast<SbkObject *>(%1));
+ %PYARG_0 = PyTuple_New(ptrs.size());
+ for (std::size_t i = 0; i < ptrs.size(); ++i)
+ PyTuple_SET_ITEM(%PYARG_0, i, PyLong_FromVoidPtr(ptrs[i]));
+} else {
+ PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet getcpppointer
+
+// @snippet delete
+if (Shiboken::Object::checkType(%1)) {
+ Shiboken::Object::callCppDestructors(reinterpret_cast<SbkObject *>(%1));
+} else {
+ PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet delete
+
+// @snippet ownedbypython
+if (Shiboken::Object::checkType(%1)) {
+ bool hasOwnership = Shiboken::Object::hasOwnership(reinterpret_cast<SbkObject *>(%1));
+ %PYARG_0 = %CONVERTTOPYTHON[bool](hasOwnership);
+} else {
+ PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet ownedbypython
+
+// @snippet createdbypython
+if (Shiboken::Object::checkType(%1)) {
+ bool wasCreatedByPython = Shiboken::Object::wasCreatedByPython(reinterpret_cast<SbkObject *>(%1));
+ %PYARG_0 = %CONVERTTOPYTHON[bool](wasCreatedByPython);
+} else {
+ PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet createdbypython
+
+// @snippet disassembleframe
+Shiboken::AutoDecRef label(PyObject_Str(%1));
+const char *marker = Shiboken::String::toCString(label);
+disassembleFrame(marker);
+Py_INCREF(Py_None);
+%PYARG_0 = Py_None;
+// @snippet disassembleframe
+
+// @snippet dump
+if (!Shiboken::Object::checkType(%1)) {
+ %PYARG_0 = Shiboken::String::fromCString("Ordinary Python type.");
+} else {
+ std::string str = Shiboken::Object::info(reinterpret_cast<SbkObject *>(%1));
+ %PYARG_0 = Shiboken::String::fromCString(str.c_str());
+}
+// @snippet dump
+
+// @snippet getallvalidwrappers
+const auto setAll = Shiboken::BindingManager::instance().getAllPyObjects();
+PyObject* listAll = PyList_New(0);
+if (listAll == nullptr)
+ return nullptr;
+for (auto *o : setAll) {
+ if (o != nullptr) {
+ if (PyList_Append(listAll, o) != 0) {
+ Py_DECREF(listAll);
+ return nullptr;
+ }
+ }
+}
+return listAll;
+// @snippet getallvalidwrappers
+
+// @snippet dumptypegraph
+const bool ok = Shiboken::BindingManager::instance().dumpTypeGraph(%1);
+%PYARG_0 = %CONVERTTOPYTHON[bool](ok);
+// @snippet dumptypegraph
+
+// @snippet dumpwrappermap
+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);
+PyTuple_SET_ITEM(version, 0, PyLong_FromLong(SHIBOKEN_MAJOR_VERSION));
+PyTuple_SET_ITEM(version, 1, PyLong_FromLong(SHIBOKEN_MINOR_VERSION));
+PyTuple_SET_ITEM(version, 2, PyLong_FromLong(SHIBOKEN_MICRO_VERSION));
+PyTuple_SET_ITEM(version, 3, Shiboken::String::fromCString(SHIBOKEN_RELEASE_LEVEL));
+PyTuple_SET_ITEM(version, 4, PyLong_FromLong(SHIBOKEN_SERIAL));
+PyModule_AddObject(module, "__version_info__", version);
+PyModule_AddStringConstant(module, "__version__", SHIBOKEN_VERSION);
+VoidPtr::addVoidPtrToModule(module);
+Shiboken::initShibokenSupport(module);
+// @snippet init
diff --git a/sources/shiboken6/shibokenmodule/shibokenmodule.txt.in b/sources/shiboken6/shibokenmodule/shibokenmodule.txt.in
new file mode 100644
index 000000000..c5adc6091
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/shibokenmodule.txt.in
@@ -0,0 +1,16 @@
+[generator-project]
+
+generator-set = shiboken
+
+header-file = @CMAKE_CURRENT_SOURCE_DIR@/nothing.h
+typesystem-file = @CMAKE_CURRENT_SOURCE_DIR@/typesystem_shiboken.xml
+
+output-directory = @CMAKE_CURRENT_BINARY_DIR@
+
+# include-path = @libsample_SOURCE_DIR@
+
+typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@
+
+avoid-protected-hack
+#enable-parent-ctor-heuristic
+#use-isnull-as-nb_nonzero
diff --git a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml
new file mode 100644
index 000000000..acb522ecc
--- /dev/null
+++ b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" ?>
+<!--
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+-->
+<typesystem package="Shiboken">
+ <primitive-type name="bool" />
+ <primitive-type name="unsigned long" />
+ <primitive-type name="size_t" />
+ <add-function signature="isValid(PyObject*)" return-type="bool">
+ <inject-code file="shibokenmodule.cpp" snippet="isvalid"/>
+ </add-function>
+
+ <add-function signature="invalidate(PyObject*)">
+ <inject-code>
+ Shiboken::Object::invalidate(%1);
+ </inject-code>
+ </add-function>
+
+ <add-function signature="wrapInstance(size_t, PyTypeObject)" return-type="PyObject*">
+ <inject-code file="shibokenmodule.cpp" snippet="wrapinstance"/>
+ </add-function>
+
+ <add-function signature="getCppPointer(PyObject*)" return-type="PySequence*">
+ <inject-code file="shibokenmodule.cpp" snippet="getcpppointer"/>
+ </add-function>
+
+ <add-function signature="delete(PyObject*)">
+ <inject-code file="shibokenmodule.cpp" snippet="delete"/>
+ </add-function>
+
+ <add-function signature="ownedByPython(PyObject*)" return-type="bool">
+ <inject-code file="shibokenmodule.cpp" snippet="ownedbypython"/>
+ </add-function>
+
+ <add-function signature="createdByPython(PyObject*)" return-type="bool">
+ <inject-code file="shibokenmodule.cpp" snippet="createdbypython"/>
+ </add-function>
+
+ <add-function signature="disassembleFrame(PyObject*)" return-type="PyObject">
+ <inject-code file="shibokenmodule.cpp" snippet="disassembleframe"/>
+ </add-function>
+
+ <add-function signature="dump(PyObject*)" return-type="const char *">
+ <inject-code file="shibokenmodule.cpp" snippet="dump"/>
+ </add-function>
+
+ <add-function signature="getAllValidWrappers(void)" return-type="PySequence*">
+ <inject-code file="shibokenmodule.cpp" snippet="getallvalidwrappers"/>
+ </add-function>
+
+ <add-function signature="dumpTypeGraph(const char *@fileName@)" return-type="bool">
+ <inject-code file="shibokenmodule.cpp" snippet="dumptypegraph"/>
+ </add-function>
+
+ <add-function signature="dumpWrapperMap()">
+ <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/CMakeLists.txt b/sources/shiboken6/tests/CMakeLists.txt
new file mode 100644
index 000000000..05f6e9e60
--- /dev/null
+++ b/sources/shiboken6/tests/CMakeLists.txt
@@ -0,0 +1,92 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.18)
+
+if(BUILD_TESTS)
+ find_package(Qt${QT_MAJOR_VERSION}Test 6.0 REQUIRED)
+endif()
+
+add_subdirectory(libminimal)
+if(NOT DEFINED MINIMAL_TESTS)
+ add_subdirectory(libsample)
+ add_subdirectory(libsmart)
+ add_subdirectory(libother)
+endif()
+
+shiboken_get_debug_level(debug_level)
+
+if(WIN32 OR DEFINED AVOID_PROTECTED_HACK)
+ message(STATUS "Tests will be generated avoiding the protected hack!")
+ set(GENERATOR_EXTRA_FLAGS --avoid-protected-hack)
+else()
+ message(STATUS "Tests will be generated using the protected hack!")
+ set(GENERATOR_EXTRA_FLAGS )
+endif()
+list(APPEND GENERATOR_EXTRA_FLAGS ${SHIBOKEN_GENERATOR_EXTRA_FLAGS} ${debug_level})
+
+add_subdirectory(minimalbinding)
+if(NOT DEFINED MINIMAL_TESTS)
+ add_subdirectory(samplebinding)
+ add_subdirectory(smartbinding)
+ add_subdirectory(otherbinding)
+endif()
+
+if(DEFINED MINIMAL_TESTS)
+ file(GLOB TEST_FILES minimalbinding/*_test.py)
+else()
+ file(GLOB TEST_FILES minimalbinding/*_test.py
+ samplebinding/*_test.py
+ otherbinding/*_test.py
+ smartbinding/*_test.py
+ shibokenmodule/*_test.py)
+endif()
+list(SORT TEST_FILES)
+
+set(test_blacklist "")
+
+if(SHIBOKEN_IS_CROSS_BUILD)
+ # Python_EXECUTABLE will be empty when cross-building.
+ message(WARNING
+ "Running tests when cross-compiling is not supported because it would require running "
+ "a target python interpreter which might have a different architecture than the host."
+ )
+else()
+ find_package(
+ Python
+ ${USE_PYTHON_VERSION}
+ REQUIRED
+ COMPONENTS Interpreter Development
+ )
+endif()
+
+if(NOT CTEST_TESTING_TIMEOUT)
+ set(CTEST_TESTING_TIMEOUT 60)
+endif()
+
+get_filename_component(BUILD_DIR "${libminimal_BINARY_DIR}" DIRECTORY)
+get_filename_component(BUILD_DIR "${BUILD_DIR}" DIRECTORY)
+get_filename_component(BUILD_DIR "${BUILD_DIR}" DIRECTORY)
+foreach(test_file ${TEST_FILES})
+ string(REGEX MATCH "/([^/]+)(binding|module)/([^/]+)_test.py" tmp ${test_file})
+ set(test_name "${CMAKE_MATCH_1}_${CMAKE_MATCH_3}")
+ list(FIND test_blacklist ${test_name} expect_fail)
+ add_test(${test_name} ${Python_EXECUTABLE} ${test_file})
+ set_tests_properties(${test_name} PROPERTIES ENVIRONMENT "BUILD_DIR=${BUILD_DIR}")
+ set_tests_properties(${test_name} PROPERTIES TIMEOUT ${CTEST_TESTING_TIMEOUT})
+ if (${expect_fail} GREATER -1)
+ set_tests_properties(${test_name} PROPERTIES WILL_FAIL TRUE)
+ endif()
+endforeach()
+
+# dumpcodemodel depends on apiextractor which is not cross-built.
+if(SHIBOKEN_BUILD_TOOLS)
+ add_subdirectory(dumpcodemodel)
+endif()
+
+# FIXME Skipped until add an option to choose the generator
+# add_subdirectory(test_generator)
+
+if (NOT APIEXTRACTOR_DOCSTRINGS_DISABLED)
+ add_subdirectory(qtxmltosphinxtest)
+endif()
diff --git a/sources/shiboken6/tests/dumpcodemodel/CMakeLists.txt b/sources/shiboken6/tests/dumpcodemodel/CMakeLists.txt
new file mode 100644
index 000000000..e7dbef961
--- /dev/null
+++ b/sources/shiboken6/tests/dumpcodemodel/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+add_executable(dumpcodemodel main.cpp)
+
+target_include_directories(dumpcodemodel
+ PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../ApiExtractor
+)
+
+target_link_libraries(dumpcodemodel
+ PRIVATE
+ apiextractor
+ Qt::Core
+)
diff --git a/sources/shiboken6/tests/dumpcodemodel/main.cpp b/sources/shiboken6/tests/dumpcodemodel/main.cpp
new file mode 100644
index 000000000..eb876634c
--- /dev/null
+++ b/sources/shiboken6/tests/dumpcodemodel/main.cpp
@@ -0,0 +1,260 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <abstractmetabuilder_p.h>
+#include <parser/codemodel.h>
+#include <clangparser/compilersupport.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QCommandLineOption>
+#include <QtCore/QCommandLineParser>
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QLibraryInfo>
+#include <QtCore/QVersionNumber>
+#include <QtCore/QXmlStreamWriter>
+
+#include <iostream>
+#include <algorithm>
+#include <iterator>
+
+using namespace Qt::StringLiterals;
+
+static bool optJoinNamespaces = false;
+
+static inline QString languageLevelDescription()
+{
+ return u"C++ Language level (c++11..c++20, default="_s
+ + QLatin1StringView(clang::languageLevelOption(clang::emulatedCompilerLanguageLevel()))
+ + u')';
+}
+
+static void formatDebugOutput(const FileModelItem &dom, bool verbose)
+{
+ QString output;
+ {
+ QDebug debug(&output);
+ if (verbose)
+ debug.setVerbosity(3);
+ debug << dom.get();
+ }
+ std::cout << qPrintable(output) << '\n';
+}
+
+static const char *primitiveTypes[] = {
+ "int", "unsigned", "short", "unsigned short", "long", "unsigned long",
+ "float", "double"
+};
+
+constexpr auto nameAttribute = "name"_L1;
+
+static void formatXmlClass(QXmlStreamWriter &writer, const ClassModelItem &klass);
+
+static void formatXmlEnum(QXmlStreamWriter &writer, const EnumModelItem &en)
+{
+ writer.writeStartElement(u"enum-type"_s);
+ writer.writeAttribute(nameAttribute, en->name());
+ writer.writeEndElement();
+}
+
+static bool useClass(const ClassModelItem &c)
+{
+ return c->classType() != CodeModel::Union && c->templateParameters().isEmpty()
+ && !c->name().isEmpty(); // No anonymous structs
+}
+
+static void formatXmlScopeMembers(QXmlStreamWriter &writer, const ScopeModelItem &nsp)
+{
+ for (const auto &klass : nsp->classes()) {
+ if (useClass(klass))
+ formatXmlClass(writer, klass);
+ }
+ for (const auto &en : nsp->enums())
+ formatXmlEnum(writer, en);
+}
+
+static bool isPublicCopyConstructor(const FunctionModelItem &f)
+{
+ return f->functionType() == CodeModel::CopyConstructor
+ && f->accessPolicy() == Access::Public && !f->isDeleted();
+}
+
+static void formatXmlLocationComment(QXmlStreamWriter &writer, const CodeModelItem &i)
+{
+ QString comment;
+ QTextStream(&comment) << ' ' << i->fileName() << ':' << i->startLine() << ' ';
+ writer.writeComment(comment);
+}
+
+static void formatXmlClass(QXmlStreamWriter &writer, const ClassModelItem &klass)
+{
+ // Heuristics for value types: check on public copy constructors.
+ const auto functions = klass->functions();
+ const bool isValueType = std::any_of(functions.cbegin(), functions.cend(),
+ isPublicCopyConstructor);
+ formatXmlLocationComment(writer, klass);
+ writer.writeStartElement(isValueType ? u"value-type"_s
+ : u"object-type"_s);
+ writer.writeAttribute(nameAttribute, klass->name());
+ formatXmlScopeMembers(writer, klass);
+ writer.writeEndElement();
+}
+
+// Check whether a namespace is relevant for type system
+// output, that is, has non template classes, functions or enumerations.
+static bool hasMembers(const NamespaceModelItem &nsp)
+{
+ if (!nsp->namespaces().isEmpty() || !nsp->enums().isEmpty()
+ || !nsp->functions().isEmpty()) {
+ return true;
+ }
+ const auto classes = nsp->classes();
+ return std::any_of(classes.cbegin(), classes.cend(), useClass);
+}
+
+static void startXmlNamespace(QXmlStreamWriter &writer, const NamespaceModelItem &nsp)
+{
+ formatXmlLocationComment(writer, nsp);
+ writer.writeStartElement(u"namespace-type"_s);
+ writer.writeAttribute(nameAttribute, nsp->name());
+}
+
+static void formatXmlNamespaceMembers(QXmlStreamWriter &writer, const NamespaceModelItem &nsp)
+{
+ auto nestedNamespaces = nsp->namespaces();
+ for (auto i = nestedNamespaces.size() - 1; i >= 0; --i) {
+ if (!hasMembers(nestedNamespaces.at(i)))
+ nestedNamespaces.removeAt(i);
+ }
+ while (!nestedNamespaces.isEmpty()) {
+ auto current = nestedNamespaces.takeFirst();
+ startXmlNamespace(writer, current);
+ formatXmlNamespaceMembers(writer, current);
+ if (optJoinNamespaces) {
+ // Write out members of identical namespaces and remove
+ const QString name = current->name();
+ for (qsizetype i = 0; i < nestedNamespaces.size(); ) {
+ if (nestedNamespaces.at(i)->name() == name) {
+ formatXmlNamespaceMembers(writer, nestedNamespaces.at(i));
+ nestedNamespaces.removeAt(i);
+ } else {
+ ++i;
+ }
+ }
+ }
+ writer.writeEndElement();
+ }
+
+ for (const auto &func : nsp->functions()) {
+ const QString signature = func->typeSystemSignature();
+ if (!signature.contains(u"operator")) { // Skip free operators
+ writer.writeStartElement(u"function"_s);
+ writer.writeAttribute(u"signature"_s, signature);
+ writer.writeEndElement();
+ }
+ }
+ formatXmlScopeMembers(writer, nsp);
+}
+
+static void formatXmlOutput(const FileModelItem &dom)
+{
+ QString output;
+ QXmlStreamWriter writer(&output);
+ writer.setAutoFormatting(true);
+ writer.writeStartDocument();
+ writer.writeStartElement(u"typesystem"_s);
+ writer.writeAttribute(u"package"_s, u"insert_name"_s);
+ writer.writeComment(u"Auto-generated "_s +
+ QDateTime::currentDateTime().toString(Qt::ISODate));
+ for (auto p : primitiveTypes) {
+ writer.writeStartElement(u"primitive-type"_s);
+ writer.writeAttribute(nameAttribute, QLatin1StringView(p));
+ writer.writeEndElement();
+ }
+ formatXmlNamespaceMembers(writer, dom);
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ std::cout << qPrintable(output) << '\n';
+}
+
+static const char descriptionFormat[] = R"(
+Type system dumper
+
+Parses a C++ header and dumps out the classes found in typesystem XML syntax.
+Arguments are arguments to the compiler the last of which should be the header
+or source file.
+It is recommended to create a .hh include file including the desired headers
+and pass that along with the required include paths.
+
+Based on Qt %1 and LibClang v%2.)";
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ QCommandLineParser parser;
+ parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
+ parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments);
+ const QString description =
+ QString::fromLatin1(descriptionFormat).arg(QLatin1StringView(qVersion()),
+ clang::libClangVersion().toString());
+ parser.setApplicationDescription(description);
+ parser.addHelpOption();
+ parser.addVersionOption();
+ QCommandLineOption verboseOption(u"verbose"_s,
+ u"Display verbose output about types"_s);
+ parser.addOption(verboseOption);
+ QCommandLineOption debugOption(u"debug"_s,
+ u"Display debug output"_s);
+ parser.addOption(debugOption);
+
+ QCommandLineOption joinNamespacesOption({u"j"_s, u"join-namespaces"_s},
+ u"Join namespaces"_s);
+ parser.addOption(joinNamespacesOption);
+
+ QCommandLineOption languageLevelOption(u"std"_s,
+ languageLevelDescription(),
+ u"level"_s);
+ parser.addOption(languageLevelOption);
+ parser.addPositionalArgument(u"argument"_s,
+ u"C++ compiler argument"_s,
+ u"argument(s)"_s);
+
+ parser.process(app);
+ const QStringList &positionalArguments = parser.positionalArguments();
+ if (positionalArguments.isEmpty())
+ parser.showHelp(1);
+
+ QByteArrayList arguments;
+ std::transform(positionalArguments.cbegin(), positionalArguments.cend(),
+ std::back_inserter(arguments), QFile::encodeName);
+
+ LanguageLevel level = LanguageLevel::Default;
+ if (parser.isSet(languageLevelOption)) {
+ const QByteArray value = parser.value(languageLevelOption).toLatin1();
+ level = clang::languageLevelFromOption(value.constData());
+ if (level == LanguageLevel::Default) {
+ std::cerr << "Invalid value \"" << value.constData()
+ << "\" for language level option.\n";
+ return -2;
+ }
+ }
+
+ optJoinNamespaces = parser.isSet(joinNamespacesOption);
+
+ const FileModelItem dom = AbstractMetaBuilderPrivate::buildDom(arguments, true, level, 0);
+ if (!dom) {
+ QString message = u"Unable to parse "_s + positionalArguments.join(u' ');
+ std::cerr << qPrintable(message) << '\n';
+ return -2;
+ }
+
+ if (parser.isSet(debugOption))
+ formatDebugOutput(dom, parser.isSet(verboseOption));
+ else
+ formatXmlOutput(dom);
+
+ return 0;
+}
diff --git a/sources/shiboken6/tests/libminimal/CMakeLists.txt b/sources/shiboken6/tests/libminimal/CMakeLists.txt
new file mode 100644
index 000000000..4a10f96bf
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(libminimal)
+
+set(libminimal_SRC
+containeruser.cpp containeruser.h
+libminimalmacros.h
+listuser.cpp listuser.h
+minbool.h
+obj.cpp obj.h
+spanuser.cpp spanuser.h
+typedef.cpp typedef.h
+val.h
+)
+
+add_library(libminimal SHARED ${libminimal_SRC})
+target_include_directories(libminimal PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_compile_definitions(libminimal PRIVATE LIBMINIMAL_BUILD)
+set_property(TARGET libminimal PROPERTY PREFIX "")
+
diff --git a/sources/shiboken6/tests/libminimal/containeruser.cpp b/sources/shiboken6/tests/libminimal/containeruser.cpp
new file mode 100644
index 000000000..29af52aef
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/containeruser.cpp
@@ -0,0 +1,55 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "containeruser.h"
+
+#include <algorithm>
+#include <numeric>
+
+ContainerUser::ContainerUser() : m_intVector{1, 2, 3}, m_intArray{1, 2, 3}
+{
+}
+
+ContainerUser::~ContainerUser() = default;
+
+std::vector<int> ContainerUser::createIntVector(int num)
+{
+ std::vector<int> retval(num);
+ std::iota(retval.begin(), retval.end(), 0);
+ return retval;
+}
+
+int ContainerUser::sumIntVector(const std::vector<int> &intVector)
+{
+ return std::accumulate(intVector.cbegin(), intVector.cend(), 0);
+}
+
+std::vector<int> &ContainerUser::intVector()
+{
+ return m_intVector;
+}
+
+void ContainerUser::setIntVector(const std::vector<int> &v)
+{
+ m_intVector = v;
+}
+
+std::array<int, 3> ContainerUser::createIntArray()
+{
+ return {1, 2, 3};
+}
+
+int ContainerUser::sumIntArray(const std::array<int, 3> &intArray)
+{
+ return std::accumulate(intArray.cbegin(), intArray.cend(), 0);
+}
+
+std::array<int, 3> &ContainerUser::intArray()
+{
+ return m_intArray;
+}
+
+void ContainerUser::setIntArray(const std::array<int, 3> &a)
+{
+ m_intArray = a;
+}
diff --git a/sources/shiboken6/tests/libminimal/containeruser.h b/sources/shiboken6/tests/libminimal/containeruser.h
new file mode 100644
index 000000000..55e4020ec
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/containeruser.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CONTAINERUSER_H
+#define CONTAINERUSER_H
+
+#include "libminimalmacros.h"
+
+#include <array>
+#include <vector>
+
+/// Exercise simple, sequential containers. More advanced tests are in ListUser
+class LIBMINIMAL_API ContainerUser
+{
+public:
+ ContainerUser();
+ ~ContainerUser();
+
+ static std::vector<int> createIntVector(int num);
+ static int sumIntVector(const std::vector<int> &intVector);
+
+ std::vector<int> &intVector();
+ void setIntVector(const std::vector<int> &);
+
+ static std::array<int, 3> createIntArray();
+ static int sumIntArray(const std::array<int, 3> &intArray);
+
+ std::array<int, 3> &intArray();
+ void setIntArray(const std::array<int, 3> &);
+
+private:
+ std::vector<int> m_intVector;
+ std::array<int, 3> m_intArray;
+};
+
+#endif // CONTAINERUSER_H
diff --git a/sources/shiboken6/tests/libminimal/libminimalmacros.h b/sources/shiboken6/tests/libminimal/libminimalmacros.h
new file mode 100644
index 000000000..099c1f1de
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/libminimalmacros.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef LIBMINIMALMACROS_H
+#define LIBMINIMALMACROS_H
+
+#if defined _WIN32
+# define LIBMINIMAL_EXPORT __declspec(dllexport)
+# ifdef _MSC_VER
+# define LIBMINIMAL_IMPORT __declspec(dllimport)
+# else
+# define LIBMINIMAL_IMPORT
+# endif
+#else
+# define LIBMINIMAL_EXPORT __attribute__ ((visibility("default")))
+# define LIBMINIMAL_IMPORT
+#endif
+
+#ifdef LIBMINIMAL_BUILD
+# define LIBMINIMAL_API LIBMINIMAL_EXPORT
+#else
+# define LIBMINIMAL_API LIBMINIMAL_IMPORT
+#endif
+
+#define LIBMINIMAL_DEFAULT_COPY(Class) \
+ Class(const Class &) noexcept = default; \
+ Class &operator=(const Class &) noexcept = default;
+
+#define LIBMINIMAL_DISABLE_COPY(Class) \
+ Class(const Class &) = delete;\
+ Class &operator=(const Class &) = delete;
+
+#define LIBMINIMAL_DEFAULT_MOVE(Class) \
+ Class(Class &&) noexcept = default; \
+ Class &operator=(Class &&) noexcept = default;
+
+#define LIBMINIMAL_DEFAULT_COPY_MOVE(Class) \
+ LIBMINIMAL_DEFAULT_COPY(Class) \
+ LIBMINIMAL_DEFAULT_MOVE(Class)
+
+#define LIBMINIMAL_DISABLE_MOVE(Class) \
+ Class(Class &&) = delete; \
+ Class &operator=(Class &&) = delete;
+
+#define LIBMINIMAL_DISABLE_COPY_MOVE(Class) \
+ LIBMINIMAL_DISABLE_COPY(Class) \
+ LIBMINIMAL_DISABLE_MOVE(Class)
+
+#endif // LIBMINIMALMACROS_H
diff --git a/sources/shiboken6/tests/libminimal/listuser.cpp b/sources/shiboken6/tests/libminimal/listuser.cpp
new file mode 100644
index 000000000..93c399542
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/listuser.cpp
@@ -0,0 +1,133 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "listuser.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <numeric>
+
+std::list<int> ListUser::createIntList(int num)
+{
+ std::list<int> retval(num);
+ std::iota(retval.begin(), retval.end(), 0);
+ return retval;
+}
+
+int ListUser::sumIntList(std::list<int> intList)
+{
+ return std::accumulate(intList.begin(), intList.end(), 0);
+}
+
+int ListUser::sumIntListDefaultParamConstRef(const std::list<int> &intList)
+{
+ return sumIntList(intList);
+}
+
+int ListUser::sumIntListDefaultParam(std::list<int> intList)
+{
+ return sumIntList(intList);
+}
+
+std::list<MinBool> ListUser::createMinBoolList(MinBool mb1, MinBool mb2)
+{
+ std::list<MinBool> retval;
+ retval.push_back(mb1);
+ retval.push_back(mb2);
+ return retval;
+}
+
+MinBool ListUser::oredMinBoolList(std::list<MinBool> minBoolList)
+{
+ MinBool result(false);
+ for (const auto &m : minBoolList)
+ result |= m;
+ return result;
+}
+
+std::list<Val> ListUser::createValList(int num)
+{
+ std::list<Val> retval;
+ for (int i = 0; i < num; ++i)
+ retval.push_back(Val(i));
+ return retval;
+}
+
+int ListUser::sumValList(std::list<Val> valList)
+{
+ int total = 0;
+ for (const auto &v : valList)
+ total += v.valId();
+ return total;
+}
+std::list<Obj*> ListUser::createObjList(Obj* o1, Obj* o2)
+{
+ std::list<Obj*> retval;
+ retval.push_back(o1);
+ retval.push_back(o2);
+ return retval;
+}
+
+int ListUser::sumObjList(std::list<Obj*> objList)
+{
+ int total = 0;
+ for (const auto *obj : objList)
+ total += obj->objId();
+ return total;
+}
+
+std::list<std::list<int> > ListUser::createListOfIntLists(int num)
+{
+ std::list<std::list<int> > retval;
+ for (int i = 0; i < num; ++i)
+ retval.push_back(createIntList(num));
+ return retval;
+}
+
+int ListUser::sumListOfIntLists(std::list<std::list<int> > intListList)
+{
+ int total = 0;
+ for (const auto &list : intListList)
+ total += std::accumulate(list.begin(), list.end(), 0);
+ return total;
+}
+
+void ListUser::setStdIntList(const std::list<int> &l)
+{
+ m_stdIntList = l;
+}
+
+std::list<int> &ListUser::getIntList()
+{
+ return m_stdIntList;
+}
+
+const std::list<int> &ListUser::getConstIntList() const
+{
+ return m_stdIntList;
+}
+
+int ListUser::modifyIntListPtr(std::list<int> *list) const
+{
+ const int oldSize = int(list->size());
+ list->push_back(42);
+ return oldSize;
+}
+
+std::list<int> *ListUser::returnIntListByPtr() const
+{
+ return nullptr;
+}
+
+int ListUser::callReturnIntListByPtr() const
+{
+ auto *list = returnIntListByPtr();
+ return list != nullptr ? int(list->size()) : 0;
+}
+
+int ListUser::modifyDoubleListPtr(std::list<double> *list) const
+{
+ const int oldSize = int(list->size());
+ list->push_back(42);
+ return oldSize;
+}
diff --git a/sources/shiboken6/tests/libminimal/listuser.h b/sources/shiboken6/tests/libminimal/listuser.h
new file mode 100644
index 000000000..9904ef27d
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/listuser.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef LISTUSER_H
+#define LISTUSER_H
+
+#include "obj.h"
+#include "val.h"
+#include "minbool.h"
+
+#include "libminimalmacros.h"
+
+#include <list>
+
+struct LIBMINIMAL_API ListUser
+{
+ LIBMINIMAL_DEFAULT_COPY(ListUser)
+ LIBMINIMAL_DISABLE_MOVE(ListUser)
+
+ ListUser() noexcept = default;
+ virtual ~ListUser() = default;
+
+ // List of C++ primitive type items
+ virtual std::list<int> createIntList(int num);
+ std::list<int> callCreateIntList(int num) { return createIntList(num); }
+ virtual int sumIntList(std::list<int> intList);
+ int callSumIntList(std::list<int> intList) { return sumIntList(intList); }
+
+ int sumIntListDefaultParamConstRef(const std::list<int> &intList = {1, 2, 3});
+ int sumIntListDefaultParam(std::list<int> intList = {1, 2, 3});
+
+ // List of C++ MinBool objects used as primitives in Python
+ virtual std::list<MinBool> createMinBoolList(MinBool mb1, MinBool mb2);
+ std::list<MinBool> callCreateMinBoolList(MinBool mb1, MinBool mb2) { return createMinBoolList(mb1, mb2); }
+ virtual MinBool oredMinBoolList(std::list<MinBool> minBoolList);
+ MinBool callOredMinBoolList(std::list<MinBool> minBoolList) { return oredMinBoolList(minBoolList); }
+
+ // List of C++ value types
+ virtual std::list<Val> createValList(int num);
+ std::list<Val> callCreateValList(int num) { return createValList(num); }
+ virtual int sumValList(std::list<Val> valList);
+ int callSumValList(std::list<Val> valList) { return sumValList(valList); }
+
+ // List of C++ object types
+ virtual std::list<Obj*> createObjList(Obj* o1, Obj* o2);
+ std::list<Obj*> callCreateObjList(Obj* o1, Obj* o2) { return createObjList(o1, o2); }
+ virtual int sumObjList(std::list<Obj*> objList);
+ int callSumObjList(std::list<Obj*> objList) { return sumObjList(objList); }
+
+ // List of lists of C++ primitive type items
+ virtual std::list<std::list<int> > createListOfIntLists(int num);
+ std::list<std::list<int> > callCreateListOfIntLists(int num) { return createListOfIntLists(num); }
+ virtual int sumListOfIntLists(std::list<std::list<int> > intListList);
+ int callSumListOfIntLists(std::list<std::list<int> > intListList) { return sumListOfIntLists(intListList); }
+
+ void setStdIntList(const std::list<int> &l);
+ std::list<int> &getIntList();
+ const std::list<int> &getConstIntList() const;
+
+ int modifyIntListPtr(std::list<int> *list) const;
+
+ virtual std::list<int> *returnIntListByPtr() const;
+
+ int callReturnIntListByPtr() const;
+
+ int modifyDoubleListPtr(std::list<double> *list) const;
+
+ std::list<int> m_stdIntList;
+};
+
+#endif // LISTUSER_H
+
diff --git a/sources/shiboken6/tests/libminimal/minbool.h b/sources/shiboken6/tests/libminimal/minbool.h
new file mode 100644
index 000000000..e460f466b
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/minbool.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MINBOOL_H
+#define MINBOOL_H
+
+#include "libminimalmacros.h"
+
+class LIBMINIMAL_API MinBool
+{
+public:
+ inline explicit MinBool(bool b) : m_value(b) {}
+ bool value() const { return m_value; }
+ inline MinBool operator!() const { return MinBool(!m_value); }
+ inline MinBool& operator|=(const MinBool& other) {
+ m_value |= other.m_value;
+ return *this;
+ }
+
+private:
+ bool m_value;
+};
+
+inline bool operator==(MinBool b1, bool b2) { return (!b1).value() == !b2; }
+inline bool operator==(bool b1, MinBool b2) { return (!b1) == (!b2).value(); }
+inline bool operator==(MinBool b1, MinBool b2) { return (!b1).value() == (!b2).value(); }
+inline bool operator!=(MinBool b1, bool b2) { return (!b1).value() != !b2; }
+inline bool operator!=(bool b1, MinBool b2) { return (!b1) != (!b2).value(); }
+inline bool operator!=(MinBool b1, MinBool b2) { return (!b1).value() != (!b2).value(); }
+
+class LIBMINIMAL_API MinBoolUser
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY(MinBoolUser)
+ LIBMINIMAL_DISABLE_MOVE(MinBoolUser)
+
+ MinBoolUser() noexcept : m_minbool(MinBool(false)) {}
+ virtual ~MinBoolUser() = default;
+ inline MinBool minBool() { return m_minbool; }
+ inline void setMinBool(MinBool minBool) { m_minbool = minBool; }
+ virtual MinBool invertedMinBool() { return !m_minbool; }
+ inline MinBool callInvertedMinBool() { return invertedMinBool(); }
+
+private:
+ MinBool m_minbool;
+};
+
+#endif
diff --git a/sources/shiboken6/tests/libminimal/obj.cpp b/sources/shiboken6/tests/libminimal/obj.cpp
new file mode 100644
index 000000000..a63a9c3c9
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/obj.cpp
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "obj.h"
+
+Obj::Obj(int objId) noexcept : m_objId(objId)
+{
+}
+
+Obj::~Obj() = default;
+
+bool Obj::virtualMethod(int val)
+{
+ return !bool(val%2);
+}
+
diff --git a/sources/shiboken6/tests/libminimal/obj.h b/sources/shiboken6/tests/libminimal/obj.h
new file mode 100644
index 000000000..be0bfb52b
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/obj.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OBJ_H
+#define OBJ_H
+
+#include "libminimalmacros.h"
+
+class LIBMINIMAL_API Obj
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Obj)
+
+ explicit Obj(int objId) noexcept;
+ virtual ~Obj();
+
+ int objId() const { return m_objId; }
+ void setObjId(int objId) { m_objId = objId; }
+
+ virtual bool virtualMethod(int val);
+ bool callVirtualMethod(int val) { return virtualMethod(val); }
+
+ virtual Obj* passObjectType(Obj* obj) { return obj; }
+ Obj* callPassObjectType(Obj* obj) { return passObjectType(obj); }
+
+ virtual Obj* passObjectTypeReference(Obj& obj) { return &obj; }
+ Obj* callPassObjectTypeReference(Obj& obj) { return passObjectTypeReference(obj); }
+
+private:
+ int m_objId;
+};
+
+#endif // OBJ_H
+
diff --git a/sources/shiboken6/tests/libminimal/spanuser.cpp b/sources/shiboken6/tests/libminimal/spanuser.cpp
new file mode 100644
index 000000000..fea9cd68e
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/spanuser.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "spanuser.h"
+
+#include <numeric>
+
+SpanUser::SpanUser() = default;
+
+bool SpanUser::enabled()
+{
+#if __cplusplus >= 202002L
+ return true;
+#else
+ return false;
+#endif
+}
+
+#if __cplusplus >= 202002L
+IntSpan3 SpanUser::getIntSpan3()
+{
+ static int iv[] = {1, 2, 3};
+ return IntSpan3(iv);
+}
+
+IntSpan SpanUser::getIntSpan()
+{
+ static int iv[] = {1, 2, 3};
+ return IntSpan(iv);
+}
+
+ConstIntSpan3 SpanUser::getConstIntSpan3()
+{
+ static const int civ[] = {1, 2, 3};
+ return ConstIntSpan3(civ);
+}
+
+IntSpan3 SpanUser::getIntSpan3_OpaqueContainer()
+{
+ static int iv[] = {1, 2, 3};
+ return IntSpan3(iv);
+}
+
+int SpanUser::sumIntSpan3(IntSpan3 isp3)
+{
+ return std::accumulate(isp3.begin(), isp3.end(), 0);
+}
+
+int SpanUser::sumIntSpan(IntSpan isp)
+{
+ return std::accumulate(isp.begin(), isp.end(), 0);
+}
+
+int SpanUser::sumConstIntSpan3(ConstIntSpan3 ispc3)
+{
+ return std::accumulate(ispc3.begin(), ispc3.end(), 0);
+}
+#endif // C++ 20
diff --git a/sources/shiboken6/tests/libminimal/spanuser.h b/sources/shiboken6/tests/libminimal/spanuser.h
new file mode 100644
index 000000000..c78ba35e7
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/spanuser.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SPANUSER_H
+#define SPANUSER_H
+
+#include "libminimalmacros.h"
+
+#if __cplusplus >= 202002L
+# include <span>
+
+using IntSpan3 = std::span<int, 3>;
+using IntSpan = std::span<int>;
+using ConstIntSpan3 = std::span<const int, 3>;
+#endif
+
+struct LIBMINIMAL_API SpanUser
+{
+ SpanUser();
+
+ static bool enabled();
+
+#if __cplusplus >= 202002L
+ static IntSpan3 getIntSpan3();
+ static IntSpan getIntSpan();
+ static ConstIntSpan3 getConstIntSpan3();
+ static IntSpan3 getIntSpan3_OpaqueContainer();
+
+ static int sumIntSpan3(IntSpan3 isp3);
+ static int sumIntSpan(IntSpan isp);
+ static int sumConstIntSpan3(ConstIntSpan3 ispc3);
+#endif // C++ 20
+};
+
+#endif // SPANUSER_H
diff --git a/sources/shiboken6/tests/libminimal/typedef.cpp b/sources/shiboken6/tests/libminimal/typedef.cpp
new file mode 100644
index 000000000..115b7be0a
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/typedef.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "typedef.h"
+
+//
+// Test wrapping of a typedef
+//
+bool arrayFuncInt(std::vector<int> a)
+{
+ return a.empty();
+}
+
+bool arrayFuncIntTypedef(MyArray a)
+{
+ return arrayFuncInt(a);
+}
+
+std::vector<int> arrayFuncIntReturn(int size)
+{
+ return std::vector<int>(size);
+}
+
+MyArray arrayFuncIntReturnTypedef(int size)
+{
+ return arrayFuncIntReturn(size);
+}
+
+//
+// Test wrapping of a typedef of a typedef
+//
+bool arrayFunc(std::vector<int> a)
+{
+ return a.empty();
+}
+
+bool arrayFuncTypedef(MyArray a)
+{
+ return arrayFunc(a);
+}
+
+std::vector<int> arrayFuncReturn(int size)
+{
+ return std::vector<int>(size);
+}
+
+MyArray arrayFuncReturnTypedef(int size)
+{
+ return arrayFuncReturn(size);
+}
diff --git a/sources/shiboken6/tests/libminimal/typedef.h b/sources/shiboken6/tests/libminimal/typedef.h
new file mode 100644
index 000000000..7116db1b8
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/typedef.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPEDEF_H
+#define TYPEDEF_H
+
+#include "libminimalmacros.h"
+
+#include <vector>
+
+// Test wrapping of a typedef
+using MyArrayInt = std::vector<int>;
+
+LIBMINIMAL_API bool arrayFuncInt(std::vector<int> a);
+LIBMINIMAL_API bool arrayFuncIntTypedef(MyArrayInt a);
+
+LIBMINIMAL_API std::vector<int> arrayFuncIntReturn(int size);
+LIBMINIMAL_API MyArrayInt arrayFuncIntReturnTypedef(int size);
+
+// Test wrapping of a typedef of a typedef
+using MyArray = MyArrayInt;
+
+LIBMINIMAL_API bool arrayFunc(std::vector<int> a);
+LIBMINIMAL_API bool arrayFuncTypedef(MyArray a);
+
+LIBMINIMAL_API std::vector<int> arrayFuncReturn(int size);
+LIBMINIMAL_API MyArray arrayFuncReturnTypedef(int size);
+
+#endif
diff --git a/sources/shiboken6/tests/libminimal/val.h b/sources/shiboken6/tests/libminimal/val.h
new file mode 100644
index 000000000..50f090a7d
--- /dev/null
+++ b/sources/shiboken6/tests/libminimal/val.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef VAL_H
+#define VAL_H
+
+#include "libminimalmacros.h"
+
+class LIBMINIMAL_API Val
+{
+public:
+ explicit Val(int valId) noexcept : m_valId(valId) {}
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Val)
+
+ virtual ~Val() = default;
+
+ int valId() const { return m_valId; }
+ void setValId(int valId) { m_valId = valId; }
+
+ virtual Val passValueType(Val val) { return val; }
+ Val callPassValueType(Val val) { return passValueType(val); }
+
+ virtual Val* passValueTypePointer(Val* val) { return val; }
+ Val* callPassValueTypePointer(Val* val) { return passValueTypePointer(val); }
+
+ virtual Val* passValueTypeReference(Val& val) { return &val; }
+ Val* callPassValueTypeReference(Val& val) { return passValueTypeReference(val); }
+
+ enum ValEnum { One, Other };
+ ValEnum oneOrTheOtherEnumValue(ValEnum enumValue) { return enumValue == One ? Other : One; }
+private:
+ int m_valId;
+};
+
+#endif // VAL_H
+
diff --git a/sources/shiboken6/tests/libother/CMakeLists.txt b/sources/shiboken6/tests/libother/CMakeLists.txt
new file mode 100644
index 000000000..0379d740b
--- /dev/null
+++ b/sources/shiboken6/tests/libother/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(libother)
+
+set(libother_SRC
+extendsnoimplicitconversion.h
+libothermacros.h
+number.cpp number.h
+otherderived.cpp otherderived.h
+othermultiplederived.cpp othermultiplederived.h
+otherobjecttype.cpp otherobjecttype.h
+othertypesystypedef.cpp othertypesystypedef.h
+smartptrtester.cpp smartptrtester.h
+)
+
+add_library(libother SHARED ${libother_SRC})
+target_include_directories(libother PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_compile_definitions(libother PRIVATE LIBOTHER_BUILD)
+target_link_libraries(libother PUBLIC libsample libsmart)
+set_property(TARGET libother PROPERTY PREFIX "")
+
+
diff --git a/sources/shiboken6/tests/libother/extendsnoimplicitconversion.h b/sources/shiboken6/tests/libother/extendsnoimplicitconversion.h
new file mode 100644
index 000000000..36d503fe8
--- /dev/null
+++ b/sources/shiboken6/tests/libother/extendsnoimplicitconversion.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef EXTENDSNOIMPLICITCONVERSION_H
+#define EXTENDSNOIMPLICITCONVERSION_H
+
+#include "libothermacros.h"
+#include "noimplicitconversion.h"
+
+class ExtendsNoImplicitConversion
+{
+public:
+ explicit ExtendsNoImplicitConversion(int objId) : m_objId(objId) {};
+ inline int objId() const { return m_objId; }
+ inline operator NoImplicitConversion() const { return NoImplicitConversion(m_objId); }
+
+private:
+ int m_objId;
+};
+
+#endif // EXTENDSNOIMPLICITCONVERSION_H
diff --git a/sources/shiboken6/tests/libother/libothermacros.h b/sources/shiboken6/tests/libother/libothermacros.h
new file mode 100644
index 000000000..567757abd
--- /dev/null
+++ b/sources/shiboken6/tests/libother/libothermacros.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef LIBOTHERMACROS_H
+#define LIBOTHERMACROS_H
+
+#include "../libminimal/libminimalmacros.h"
+
+#define LIBOTHER_EXPORT LIBMINIMAL_EXPORT
+#define LIBOTHER_IMPORT LIBMINIMAL_IMPORT
+
+#ifdef LIBOTHER_BUILD
+# define LIBOTHER_API LIBOTHER_EXPORT
+#else
+# define LIBOTHER_API LIBOTHER_IMPORT
+#endif
+
+#endif // LIBOTHERMACROS_H
diff --git a/sources/shiboken6/tests/libother/number.cpp b/sources/shiboken6/tests/libother/number.cpp
new file mode 100644
index 000000000..fbf50dc4a
--- /dev/null
+++ b/sources/shiboken6/tests/libother/number.cpp
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "number.h"
+
+#include <sstream>
+
+Str Number::toStr() const
+{
+ std::ostringstream in;
+ in << m_value;
+ return in.str().c_str();
+}
+
+Point operator*(const Point &p, const Number &n)
+{
+ return {p.x() * n.value(), p.y() * n.value()};
+}
+
+Complex Number::toComplex() const
+{
+ return Complex(m_value);
+}
+
+Number Number::fromComplex(Complex cpx)
+{
+ return Number(cpx.real());
+}
diff --git a/sources/shiboken6/tests/libother/number.h b/sources/shiboken6/tests/libother/number.h
new file mode 100644
index 000000000..2c480e7f2
--- /dev/null
+++ b/sources/shiboken6/tests/libother/number.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef NUMBER_H
+#define NUMBER_H
+
+#include "libothermacros.h"
+#include "str.h"
+#include "point.h"
+#include "complex.h"
+
+class LIBOTHER_API Number
+{
+public:
+ explicit Number(int value) : m_value(value) {};
+ inline int value() const { return m_value; }
+
+ Str toStr() const;
+ inline operator Str() const { return toStr(); }
+
+ friend LIBOTHER_API Point operator*(const Point &, const Number &);
+
+ Complex toComplex() const;
+ static Number fromComplex(Complex cpx);
+
+private:
+ int m_value;
+};
+
+LIBOTHER_API Point operator*(const Point &, const Number &);
+
+#endif // NUMBER_H
diff --git a/sources/shiboken6/tests/libother/otherderived.cpp b/sources/shiboken6/tests/libother/otherderived.cpp
new file mode 100644
index 000000000..93a18876e
--- /dev/null
+++ b/sources/shiboken6/tests/libother/otherderived.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "otherderived.h"
+
+OtherDerived::OtherDerived(int id) : Abstract(id)
+{
+}
+
+OtherDerived::~OtherDerived() = default;
+
+Abstract *OtherDerived::createObject()
+{
+ static int id = 100;
+ return new OtherDerived(id++);
+}
+
+void OtherDerived::pureVirtual()
+{
+}
+
+void *OtherDerived::pureVirtualReturningVoidPtr()
+{
+ return nullptr;
+}
+
+void OtherDerived::unpureVirtual()
+{
+}
+
+void OtherDerived::pureVirtualPrivate()
+{
+}
diff --git a/sources/shiboken6/tests/libother/otherderived.h b/sources/shiboken6/tests/libother/otherderived.h
new file mode 100644
index 000000000..d6bde8808
--- /dev/null
+++ b/sources/shiboken6/tests/libother/otherderived.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OTHERDERIVED_H
+#define OTHERDERIVED_H
+
+#include "libothermacros.h"
+#include "abstract.h"
+#include "derived.h"
+#include "objecttype.h"
+#include "complex.h"
+
+class ObjectType;
+
+class LIBOTHER_API OtherDerived : public Abstract
+{
+public:
+ OtherDerived(int id = -1);
+ ~OtherDerived() override;
+ void pureVirtual() override;
+ void *pureVirtualReturningVoidPtr() override;
+ void unpureVirtual() override;
+ PrintFormat returnAnEnum() override { return Short; }
+
+ inline void useObjectTypeFromOtherModule(ObjectType *) {}
+ inline Event useValueTypeFromOtherModule(const Event &e) { return e; }
+ inline Complex useValueTypeFromOtherModule(const Complex &c) { return c; }
+ inline void useEnumTypeFromOtherModule(OverloadedFuncEnum) {}
+
+ // factory method
+ static Abstract *createObject();
+
+ void hideFunction(HideType*) override {}
+
+protected:
+ inline const char *getClassName() { return className(); }
+ const char *className() const override { return "OtherDerived"; }
+
+private:
+ void pureVirtualPrivate() override;
+};
+
+#endif // OTHERDERIVED_H
diff --git a/sources/shiboken6/tests/libother/othermultiplederived.cpp b/sources/shiboken6/tests/libother/othermultiplederived.cpp
new file mode 100644
index 000000000..cfbbfb2c2
--- /dev/null
+++ b/sources/shiboken6/tests/libother/othermultiplederived.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "othermultiplederived.h"
+
+VirtualMethods OtherMultipleDerived::returnUselessClass()
+{
+ return VirtualMethods();
+}
+
+Base1 *OtherMultipleDerived::createObject(const std::string &objName)
+{
+ if (objName == "Base1")
+ return new Base1;
+ if (objName == "MDerived1")
+ return new MDerived1;
+ if (objName == "SonOfMDerived1")
+ return new SonOfMDerived1;
+ if (objName == "MDerived3")
+ return new MDerived3;
+ if (objName == "OtherMultipleDerived")
+ return new OtherMultipleDerived;
+ return nullptr;
+}
diff --git a/sources/shiboken6/tests/libother/othermultiplederived.h b/sources/shiboken6/tests/libother/othermultiplederived.h
new file mode 100644
index 000000000..cd9910687
--- /dev/null
+++ b/sources/shiboken6/tests/libother/othermultiplederived.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OTHERMULTIPLEDERIVED_H
+#define OTHERMULTIPLEDERIVED_H
+
+#include "libothermacros.h"
+#include "multiple_derived.h"
+#include "virtualmethods.h"
+
+class ObjectType;
+
+class LIBOTHER_API OtherMultipleDerived : public OtherBase, public MDerived1
+{
+public:
+ // this will use CppCopier from other module (bug#142)
+ VirtualMethods returnUselessClass();
+ static Base1 *createObject(const std::string &objName);
+};
+
+#endif // OTHERMULTIPLEDERIVED_H
diff --git a/sources/shiboken6/tests/libother/otherobjecttype.cpp b/sources/shiboken6/tests/libother/otherobjecttype.cpp
new file mode 100644
index 000000000..eaaa231be
--- /dev/null
+++ b/sources/shiboken6/tests/libother/otherobjecttype.cpp
@@ -0,0 +1,20 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "otherobjecttype.h"
+
+Collector &operator<<(Collector &collector, const OtherObjectType &obj)
+{
+ collector << obj.identifier() * 2;
+ return collector;
+}
+
+int OtherObjectType::enumAsInt(SampleNamespace::SomeClass::PublicScopedEnum value)
+{
+ return static_cast<int>(value);
+}
+
+int OtherObjectType::enumAsIntForInvisibleNamespace(RemovedNamespace1::RemovedNamespace1_Enum value)
+{
+ return static_cast<int>(value);
+}
diff --git a/sources/shiboken6/tests/libother/otherobjecttype.h b/sources/shiboken6/tests/libother/otherobjecttype.h
new file mode 100644
index 000000000..844795118
--- /dev/null
+++ b/sources/shiboken6/tests/libother/otherobjecttype.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OTHEROBJECTTYPE_H
+#define OTHEROBJECTTYPE_H
+
+#include "libothermacros.h"
+#include "objecttype.h"
+#include "collector.h"
+#include "samplenamespace.h"
+#include "removednamespaces.h"
+
+class LIBOTHER_API OtherObjectType : public ObjectType
+{
+public:
+ static int enumAsInt(SampleNamespace::SomeClass::PublicScopedEnum value);
+ static int enumAsIntForInvisibleNamespace(RemovedNamespace1::RemovedNamespace1_Enum value);
+};
+
+LIBOTHER_API Collector &operator<<(Collector &, const OtherObjectType &);
+
+#endif // OTHEROBJECTTYPE_H
diff --git a/sources/shiboken6/tests/libother/othertypesystypedef.cpp b/sources/shiboken6/tests/libother/othertypesystypedef.cpp
new file mode 100644
index 000000000..1a50c4edf
--- /dev/null
+++ b/sources/shiboken6/tests/libother/othertypesystypedef.cpp
@@ -0,0 +1,19 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "othertypesystypedef.h"
+
+OtherValueWithUnitUser::OtherValueWithUnitUser() = default;
+
+
+ValueWithUnit<double, LengthUnit::Inch>
+ OtherValueWithUnitUser::doubleMillimeterToInch(ValueWithUnit<double, LengthUnit::Millimeter> v)
+{
+ return ValueWithUnit<double, LengthUnit::Inch>(v.value() / 254);
+}
+
+ValueWithUnit<int, LengthUnit::Inch>
+ OtherValueWithUnitUser::intMillimeterToInch(ValueWithUnit<int, LengthUnit::Millimeter> v)
+{
+ return ValueWithUnit<int, LengthUnit::Inch>(v.value() / 254);
+}
diff --git a/sources/shiboken6/tests/libother/othertypesystypedef.h b/sources/shiboken6/tests/libother/othertypesystypedef.h
new file mode 100644
index 000000000..999b71fd3
--- /dev/null
+++ b/sources/shiboken6/tests/libother/othertypesystypedef.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OTHERTYPESYSTYPEDEF_H
+#define OTHERTYPESYSTYPEDEF_H
+
+#include "libothermacros.h"
+
+#include <typesystypedef.h>
+
+class LIBOTHER_API OtherValueWithUnitUser
+{
+public:
+ OtherValueWithUnitUser();
+
+ static ValueWithUnit<double, LengthUnit::Inch> doubleMillimeterToInch(ValueWithUnit<double, LengthUnit::Millimeter>);
+
+ static ValueWithUnit<int, LengthUnit::Inch> intMillimeterToInch(ValueWithUnit<int, LengthUnit::Millimeter>);
+};
+
+#endif // OTHERTYPESYSTYPEDEF_H
diff --git a/sources/shiboken6/tests/libother/smartptrtester.cpp b/sources/shiboken6/tests/libother/smartptrtester.cpp
new file mode 100644
index 000000000..1c6496b1a
--- /dev/null
+++ b/sources/shiboken6/tests/libother/smartptrtester.cpp
@@ -0,0 +1,30 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "smartptrtester.h"
+
+SharedPtr<Str> SmartPtrTester::createSharedPtrStr(const char *what)
+{
+ return {new Str(what)};
+}
+
+std::string SmartPtrTester::valueOfSharedPtrStr(const SharedPtr<Str> &str)
+{
+ return str->cstring();
+}
+
+SharedPtr<Integer> SmartPtrTester::createSharedPtrInteger(int v)
+{
+ auto i = SharedPtr<Integer>(new Integer);
+ i->m_int = v;
+ return i;
+}
+
+int SmartPtrTester::valueOfSharedPtrInteger(const SharedPtr<Integer> &v)
+{
+ return v->m_int;
+}
+
+void SmartPtrTester::fiddleInt(const SharedPtr<int> &) // no binding, should not cause errors
+{
+}
diff --git a/sources/shiboken6/tests/libother/smartptrtester.h b/sources/shiboken6/tests/libother/smartptrtester.h
new file mode 100644
index 000000000..6d7991c06
--- /dev/null
+++ b/sources/shiboken6/tests/libother/smartptrtester.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SMARTPTRTESTER_H
+#define SMARTPTRTESTER_H
+
+#include "libothermacros.h"
+
+#include <smart.h>
+#include <str.h>
+
+class LIBOTHER_API SmartPtrTester
+{
+public:
+ SharedPtr<Str> createSharedPtrStr(const char *what);
+ std::string valueOfSharedPtrStr(const SharedPtr<Str> &);
+
+ SharedPtr<Integer> createSharedPtrInteger(int v);
+ int valueOfSharedPtrInteger(const SharedPtr<Integer> &);
+
+ void fiddleInt(const SharedPtr<int> &);
+};
+
+#endif // SMARTPTRTESTER_H
diff --git a/sources/shiboken6/tests/libsample/CMakeLists.txt b/sources/shiboken6/tests/libsample/CMakeLists.txt
new file mode 100644
index 000000000..926972340
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/CMakeLists.txt
@@ -0,0 +1,95 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(libsample)
+
+set(libsample_SRC
+abstract.cpp abstract.h
+blackbox.cpp blackbox.h
+bucket.cpp bucket.h
+bytearray.cpp bytearray.h
+collector.cpp collector.h
+complex.cpp complex.h
+ctorconvrule.h
+ctparam.cpp ctparam.h
+cvlist.h
+derived.cpp derived.h
+derivedusingct.cpp derivedusingct.h
+echo.cpp echo.h
+exceptiontest.cpp exceptiontest.h
+expression.cpp expression.h
+filter.cpp filter.h
+functions.cpp functions.h
+handle.cpp handle.h
+implicitconv.cpp implicitconv.h
+injectcode.cpp injectcode.h
+intwrapper.cpp intwrapper.h
+libsamplemacros.h
+list.h
+listuser.cpp listuser.h
+mapuser.cpp mapuser.h
+modelindex.h
+modifications.cpp modifications.h
+modified_constructor.cpp modified_constructor.h
+multiple_derived.cpp multiple_derived.h
+noimplicitconversion.h
+nondefaultctor.h
+nontypetemplate.h
+null.h
+objectmodel.cpp objectmodel.h
+objecttype.cpp objecttype.h
+objecttypebyvalue.h
+objecttypeholder.cpp objecttypeholder.h
+objecttypelayout.cpp objecttypelayout.h
+objecttypeoperators.cpp objecttypeoperators.h
+objectview.cpp objectview.h
+oddbool.cpp oddbool.h
+onlycopy.cpp onlycopy.h
+overload.cpp overload.h
+overloadsort.cpp overloadsort.h
+pairuser.cpp pairuser.h
+pen.cpp pen.h
+photon.cpp photon.h
+point.cpp point.h
+pointerholder.h
+pointf.cpp pointf.h
+polygon.cpp polygon.h
+privatector.h
+privatedtor.h
+protected.cpp protected.h
+rect.h
+reference.cpp reference.h
+removednamespaces.h
+renaming.cpp renaming.h
+sample.cpp sample.h
+samplenamespace.cpp samplenamespace.h
+sbkdate.cpp sbkdate.h
+stdcomplex.cpp stdcomplex.h
+simplefile.cpp simplefile.h
+size.cpp size.h
+snakecasetest.cpp snakecasetest.h
+sometime.cpp sometime.h
+str.cpp str.h
+strlist.cpp strlist.h
+templateptr.cpp templateptr.h
+transform.cpp transform.h
+typesystypedef.cpp typesystypedef.h
+valueandvirtual.h
+virtualmethods.cpp virtualmethods.h
+voidholder.h
+)
+
+# Includes windows.h which is causing clashes between class Polygon and
+# wingdi.h's Polygon() function.
+
+if(WIN32)
+ set_source_files_properties(
+ bucket.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON
+ )
+endif()
+
+add_library(libsample SHARED ${libsample_SRC})
+target_include_directories(libsample PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_compile_definitions(libsample PRIVATE LIBSAMPLE_BUILD)
+set_property(TARGET libsample PROPERTY PREFIX "")
+
diff --git a/sources/shiboken6/tests/libsample/abstract.cpp b/sources/shiboken6/tests/libsample/abstract.cpp
new file mode 100644
index 000000000..0d67d8630
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/abstract.cpp
@@ -0,0 +1,71 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstract.h"
+
+#include <iostream>
+
+const int Abstract::staticPrimitiveField = 0;
+
+Abstract::Abstract(int id) noexcept : m_id(id)
+{
+ bitField = 0;
+}
+
+Abstract::~Abstract() = default;
+
+void Abstract::unpureVirtual()
+{
+}
+
+void Abstract::callUnpureVirtual()
+{
+ this->unpureVirtual();
+}
+
+void Abstract::callPureVirtual()
+{
+ this->pureVirtual();
+}
+
+void Abstract::show(PrintFormat format) const
+{
+ std::cout << '<';
+ switch(format) {
+ case Short:
+ std::cout << this;
+ break;
+ case Verbose:
+ std::cout << "class " << className() << " | cptr: " << this
+ << ", id: " << m_id;
+ break;
+ case OnlyId:
+ std::cout << "id: " << m_id;
+ break;
+ case ClassNameAndId:
+ std::cout << className() << " - id: " << m_id;
+ break;
+ }
+ std::cout << '>';
+}
+
+void Abstract::virtualWithOutParameter(int &x) const
+{
+ x = 42;
+}
+
+int Abstract::callVirtualWithOutParameter() const
+{
+ int x;
+ virtualWithOutParameter(x);
+ return x;
+}
+
+void Abstract::callVirtualGettingEnum(PrintFormat p)
+{
+ virtualGettingAEnum(p);
+}
+
+void Abstract::virtualGettingAEnum(Abstract::PrintFormat)
+{
+}
diff --git a/sources/shiboken6/tests/libsample/abstract.h b/sources/shiboken6/tests/libsample/abstract.h
new file mode 100644
index 000000000..4c1b98d90
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/abstract.h
@@ -0,0 +1,91 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ABSTRACT_H
+#define ABSTRACT_H
+
+#include "libsamplemacros.h"
+#include "point.h"
+#include "complex.h"
+
+class ObjectType;
+
+// this class is not exported to python
+class HideType
+{
+};
+
+class LIBSAMPLE_API Abstract
+{
+private:
+ enum PrivateEnum {
+ PrivValue0,
+ PrivValue1,
+ PrivValue2 = PrivValue1 + 2
+ };
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Abstract)
+
+ enum PrintFormat {
+ Short,
+ Verbose,
+ OnlyId,
+ ClassNameAndId,
+ DummyItemToTestPrivateEnum1 = Abstract::PrivValue1,
+ DummyItemToTestPrivateEnum2 = PrivValue2,
+ };
+
+ enum Type {
+ TpAbstract, TpDerived
+ };
+
+ static const int staticPrimitiveField;
+ int primitiveField = 123;
+ Complex userPrimitiveField;
+ Point valueTypeField{12, 34};
+ ObjectType *objectTypeField = nullptr;
+ int toBeRenamedField = 123;
+ int readOnlyField = 123;
+
+ explicit Abstract(int id = -1) noexcept;
+ virtual ~Abstract();
+
+ inline int id() const { return m_id; }
+
+ // factory method
+ inline static Abstract *createObject() { return nullptr; }
+
+ // method that receives an Object Type
+ inline static int getObjectId(Abstract *obj) { return obj->id(); }
+
+ virtual void pureVirtual() = 0;
+ virtual void *pureVirtualReturningVoidPtr() = 0;
+ virtual void unpureVirtual();
+
+ virtual PrintFormat returnAnEnum() = 0;
+ void callVirtualGettingEnum(PrintFormat p);
+ virtual void virtualGettingAEnum(PrintFormat p);
+
+ void callPureVirtual();
+ void callUnpureVirtual();
+
+ void show(PrintFormat format = Verbose) const;
+ virtual Type type() const { return TpAbstract; }
+
+ virtual void hideFunction(HideType *arg) = 0;
+
+ virtual void virtualWithOutParameter(int &x) const;
+ int callVirtualWithOutParameter() const;
+
+protected:
+ virtual const char *className() const { return "Abstract"; }
+
+ // Protected bit-field structure member.
+ unsigned int bitField: 1;
+
+private:
+ virtual void pureVirtualPrivate() = 0;
+ int m_id;
+};
+
+#endif // ABSTRACT_H
diff --git a/sources/shiboken6/tests/libsample/blackbox.cpp b/sources/shiboken6/tests/libsample/blackbox.cpp
new file mode 100644
index 000000000..2ac435d3d
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/blackbox.cpp
@@ -0,0 +1,81 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "blackbox.h"
+
+BlackBox::~BlackBox()
+{
+ // Free all maps.
+ for (const auto &p :m_objects)
+ delete p.second;
+ for (const auto &p : m_points)
+ delete p.second;
+}
+
+int BlackBox::keepObjectType(ObjectType *object)
+{
+ ++m_ticket;
+ m_objects.insert({m_ticket, object});
+ object->setParent(nullptr);
+
+ return m_ticket;
+}
+
+ObjectType *BlackBox::retrieveObjectType(int ticket)
+{
+ const auto it = m_objects.find(ticket);
+ if (it != m_objects.end()) {
+ ObjectType *second = it->second;
+ m_objects.erase(it);
+ return second;
+ }
+ return nullptr;
+}
+
+void BlackBox::disposeObjectType(int ticket)
+{
+ delete retrieveObjectType(ticket);
+}
+
+int BlackBox::keepPoint(Point *point)
+{
+ ++m_ticket;
+ m_points.insert({m_ticket, point});
+ return m_ticket;
+}
+
+Point *BlackBox::retrievePoint(int ticket)
+{
+ const auto it = m_points.find(ticket);
+ if (it != m_points.end()) {
+ Point *second = it->second;
+ m_points.erase(it);
+ return second;
+ }
+ return nullptr;
+}
+
+void BlackBox::disposePoint(int ticket)
+{
+ delete retrievePoint(ticket);
+}
+
+std::list<ObjectType*> BlackBox::objects()
+{
+ std::list<ObjectType*> l;
+
+ for (const auto &p : m_objects)
+ l.push_back(p.second);
+
+ return l;
+}
+
+std::list<Point*> BlackBox::points()
+{
+ std::list<Point*> l;
+
+ for (const auto &p : m_points)
+ l.push_back(p.second);
+
+ return l;
+}
diff --git a/sources/shiboken6/tests/libsample/blackbox.h b/sources/shiboken6/tests/libsample/blackbox.h
new file mode 100644
index 000000000..9d32670dd
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/blackbox.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef BLACKBOX_H
+#define BLACKBOX_H
+
+#include "libsamplemacros.h"
+#include "objecttype.h"
+#include "point.h"
+
+#include <list>
+#include <map>
+
+class LIBSAMPLE_API BlackBox
+{
+public:
+ using ObjectTypeMap = std::map<int, ObjectType*>;
+ using PointMap = std::map<int, Point*>;
+
+ LIBMINIMAL_DEFAULT_COPY_MOVE(BlackBox)
+ BlackBox() noexcept = default;
+ ~BlackBox();
+
+ int keepObjectType(ObjectType *object);
+ ObjectType *retrieveObjectType(int ticket);
+ void disposeObjectType(int ticket);
+
+ int keepPoint(Point *point);
+ Point *retrievePoint(int ticket);
+ void disposePoint(int ticket);
+
+ std::list<ObjectType*> objects();
+ std::list<Point*> points();
+
+ inline void referenceToValuePointer(Point*&) {}
+ inline void referenceToObjectPointer(ObjectType*&) {}
+
+private:
+ ObjectTypeMap m_objects;
+ PointMap m_points;
+ int m_ticket = -1;
+};
+
+#endif // BLACKBOX_H
diff --git a/sources/shiboken6/tests/libsample/bucket.cpp b/sources/shiboken6/tests/libsample/bucket.cpp
new file mode 100644
index 000000000..cafd382a9
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/bucket.cpp
@@ -0,0 +1,59 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "bucket.h"
+
+#include <iostream>
+
+#ifdef _WIN32 // _WIN32 is defined by all Windows 32 and 64 bit compilers, but not by others.
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# define SLEEP(x) Sleep(x)
+#else
+# include <unistd.h>
+# define SLEEP(x) usleep(x)
+#endif
+
+void Bucket::push(int x)
+{
+ m_data.push_back(x);
+}
+
+int Bucket::pop(void)
+{
+ int x = 0;
+
+ if (!m_data.empty()) {
+ x = m_data.front();
+ m_data.pop_front();
+ }
+
+ return x;
+}
+
+bool Bucket::empty()
+{
+ return m_data.empty();
+}
+
+void Bucket::lock()
+{
+ m_locked = true;
+ while (m_locked) {
+ SLEEP(300);
+ }
+}
+
+void Bucket::unlock()
+{
+ m_locked = false;
+}
+
+bool Bucket::virtualBlockerMethod()
+{
+ lock();
+ // The return value was added just for diversity sake.
+ return true;
+}
diff --git a/sources/shiboken6/tests/libsample/bucket.h b/sources/shiboken6/tests/libsample/bucket.h
new file mode 100644
index 000000000..73e8edd78
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/bucket.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef BUCKET_H
+#define BUCKET_H
+
+#include "libsamplemacros.h"
+#include "objecttype.h"
+
+#include <list>
+
+class ObjectType;
+
+class LIBSAMPLE_API Bucket : public ObjectType
+{
+public:
+ Bucket() = default;
+ void push(int);
+ int pop();
+ bool empty();
+ void lock();
+ inline bool locked() { return m_locked; }
+ void unlock();
+
+ virtual bool virtualBlockerMethod();
+ inline bool callVirtualBlockerMethodButYouDontKnowThis() { return virtualBlockerMethod(); }
+
+private:
+ std::list<int> m_data;
+
+ volatile bool m_locked = false;
+};
+
+#endif // BUCKET_H
diff --git a/sources/shiboken6/tests/libsample/bytearray.cpp b/sources/shiboken6/tests/libsample/bytearray.cpp
new file mode 100644
index 000000000..78d5162b0
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/bytearray.cpp
@@ -0,0 +1,166 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "bytearray.h"
+
+#include <algorithm>
+#include <iterator>
+#include <cstring>
+
+ByteArray::ByteArray() : m_data(1, '\0')
+{
+}
+
+ByteArray::ByteArray(char c)
+{
+ m_data = std::vector<char>(2);
+ m_data[0] = c;
+ m_data[1] = '\0';
+}
+
+ByteArray::ByteArray(const char *data)
+{
+ size_t len = std::strlen(data);
+ m_data = std::vector<char>(len + 1);
+ memcpy(&m_data[0], data, len);
+ m_data[len] = '\0';
+}
+
+ByteArray::ByteArray(const char *data, int len)
+{
+ m_data = std::vector<char>(len + 1);
+ memcpy(&m_data[0], data, len);
+ m_data[len] = '\0';
+}
+
+int ByteArray::size() const
+{
+ return m_data.size() - 1;
+}
+
+char ByteArray::at(int pos) const
+{
+ return m_data[pos];
+}
+
+const char *ByteArray::data() const
+{
+ return &(m_data[0]);
+}
+
+ByteArray &ByteArray::append(char c)
+{
+ m_data.pop_back();
+ m_data.push_back(c);
+ m_data.push_back('\0');
+ return *this;
+}
+
+ByteArray &ByteArray::append(const char *data)
+{
+ m_data.pop_back();
+ std::copy(data, data + strlen(data), std::back_inserter(m_data));
+ m_data.push_back('\0');
+ return *this;
+}
+
+ByteArray &ByteArray::append(const char *data, int len)
+{
+ m_data.pop_back();
+ std::copy(data, data + len, std::back_inserter(m_data));
+ m_data.push_back('\0');
+ return *this;
+}
+
+ByteArray &ByteArray::append(const ByteArray &other)
+{
+ m_data.pop_back();
+ std::copy(other.m_data.begin(), other.m_data.end(), std::back_inserter(m_data));
+ return *this;
+}
+
+static bool compare(const std::vector<char> &mine, const char *other)
+{
+ for (int i = 0; i < (int)mine.size() - 1; ++i) {
+ if (mine[i] != other[i])
+ return false;
+ }
+ return true;
+}
+
+bool ByteArray::operator==(const ByteArray &other) const
+{
+ return m_data == other.m_data;
+}
+bool operator==(const ByteArray &ba1, const char *ba2)
+{
+ return compare(ba1.m_data, ba2);
+}
+
+bool operator==(const char *ba1, const ByteArray &ba2)
+{
+ return compare(ba2.m_data, ba1);
+}
+
+bool ByteArray::operator!=(const ByteArray &other) const
+{
+ return m_data != other.m_data;
+}
+
+bool operator!=(const ByteArray &ba1, const char *ba2)
+{
+ return !(ba1 == ba2);
+}
+
+bool operator!=(const char *ba1, const ByteArray &ba2)
+{
+ return !(ba1 == ba2);
+}
+
+ByteArray &ByteArray::operator+=(char c)
+{
+ return append(c);
+}
+
+ByteArray &ByteArray::operator+=(const char *data)
+{
+ return append(data);
+}
+
+ByteArray &ByteArray::operator+=(const ByteArray &other)
+{
+ return append(other);
+}
+
+ByteArray operator+(const ByteArray &ba1, const ByteArray &ba2)
+{
+ return ByteArray(ba1) += ba2;
+}
+
+ByteArray operator+(const ByteArray &ba1, const char *ba2)
+{
+ return ByteArray(ba1) += ByteArray(ba2);
+}
+
+ByteArray operator+(const char *ba1, const ByteArray &ba2)
+{
+ return ByteArray(ba1) += ba2;
+}
+
+ByteArray operator+(const ByteArray &ba1, char ba2)
+{
+ return ByteArray(ba1) += ByteArray(ba2);
+}
+
+ByteArray operator+(char ba1, const ByteArray &ba2)
+{
+ return ByteArray(ba1) += ba2;
+}
+
+unsigned int ByteArray::hash(const ByteArray &byteArray)
+{
+ unsigned int result = 0;
+ for (char c : byteArray.m_data)
+ result = 5U * result + unsigned(c);
+ return result;
+}
diff --git a/sources/shiboken6/tests/libsample/bytearray.h b/sources/shiboken6/tests/libsample/bytearray.h
new file mode 100644
index 000000000..35ff22367
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/bytearray.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef BYTEARRAY_H
+#define BYTEARRAY_H
+
+#include "str.h"
+#include "libsamplemacros.h"
+
+#include <vector>
+
+class LIBSAMPLE_API ByteArray
+{
+public:
+ ByteArray();
+ explicit ByteArray(char data);
+ explicit ByteArray(const char *data);
+ explicit ByteArray(const char *data, int len);
+
+ int size() const;
+ char at(int i) const;
+ char operator[](int i) const;
+
+ const char *data() const;
+
+ ByteArray &append(char c);
+ ByteArray &append(const char *data);
+ ByteArray &append(const char *data, int len);
+ ByteArray &append(const ByteArray &other);
+
+ bool operator==(const ByteArray &other) const;
+ bool operator!=(const ByteArray &other) const;
+
+ ByteArray &operator+=(char c);
+ ByteArray &operator+=(const char *data);
+ ByteArray &operator+=(const ByteArray &other);
+
+ static unsigned int hash(const ByteArray &byteArray);
+private:
+ std::vector<char> m_data;
+ friend LIBSAMPLE_API bool operator==(const ByteArray &ba1, const char *ba2);
+ friend LIBSAMPLE_API bool operator==(const char *ba1, const ByteArray &ba2);
+ friend LIBSAMPLE_API bool operator!=(const ByteArray &ba1, const char *ba2);
+ friend LIBSAMPLE_API bool operator!=(const char *ba1, const ByteArray &ba2);
+
+ friend LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, const ByteArray &ba2);
+ friend LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, const char *ba2);
+ friend LIBSAMPLE_API ByteArray operator+(const char *ba1, const ByteArray &ba2);
+ friend LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, char ba2);
+ friend LIBSAMPLE_API ByteArray operator+(char ba1, const ByteArray &ba2);
+};
+
+LIBSAMPLE_API bool operator==(const ByteArray &ba1, const char *ba2);
+LIBSAMPLE_API bool operator==(const char *ba1, const ByteArray &ba2);
+LIBSAMPLE_API bool operator!=(const ByteArray &ba1, const char *ba2);
+LIBSAMPLE_API bool operator!=(const char *ba1, const ByteArray &ba2);
+
+LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, const ByteArray &ba2);
+LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, const char *ba2);
+LIBSAMPLE_API ByteArray operator+(const char *ba1, const ByteArray &ba2);
+LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, char ba2);
+LIBSAMPLE_API ByteArray operator+(char ba1, const ByteArray &ba2);
+
+#endif // BYTEARRAY_H
diff --git a/sources/shiboken6/tests/libsample/collector.cpp b/sources/shiboken6/tests/libsample/collector.cpp
new file mode 100644
index 000000000..579239bcb
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/collector.cpp
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "collector.h"
+
+void Collector::clear()
+{
+ m_items.clear();
+}
+
+Collector &Collector::operator<<(ObjectType::Identifier item)
+{
+ m_items.push_back(item);
+ return *this;
+}
+
+Collector &Collector::operator<<(const ObjectType *obj)
+{
+ m_items.push_back(obj->identifier());
+ return *this;
+}
+
+std::list<ObjectType::Identifier> Collector::items()
+{
+ return m_items;
+}
+
+int Collector::size() const
+{
+ return int(m_items.size());
+}
+
+Collector &operator<<(Collector &s, const IntWrapper &w)
+{
+ s << w.toInt();
+ return s;
+}
diff --git a/sources/shiboken6/tests/libsample/collector.h b/sources/shiboken6/tests/libsample/collector.h
new file mode 100644
index 000000000..26766847a
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/collector.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef COLLECTOR_H
+#define COLLECTOR_H
+
+#include "libsamplemacros.h"
+#include "intwrapper.h"
+#include "objecttype.h"
+
+#include <list>
+
+class LIBSAMPLE_API Collector
+{
+public:
+ Collector() noexcept = default;
+ virtual ~Collector() = default;
+ LIBMINIMAL_DISABLE_COPY_MOVE(Collector)
+
+ void clear();
+
+ Collector &operator<<(ObjectType::Identifier item);
+
+ Collector &operator<<(const ObjectType *);
+
+ std::list<ObjectType::Identifier> items();
+ int size() const;
+
+private:
+ std::list<ObjectType::Identifier> m_items;
+};
+
+/* Helper for testing external operators */
+LIBSAMPLE_API Collector &operator<<(Collector &, const IntWrapper &);
+
+#endif // COLLECTOR_H
+
diff --git a/sources/shiboken6/tests/libsample/complex.cpp b/sources/shiboken6/tests/libsample/complex.cpp
new file mode 100644
index 000000000..e3bec9aae
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/complex.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "complex.h"
+
+#include <iostream>
+
+Complex::Complex(double real, double imag) noexcept
+ : m_real(real), m_imag(imag)
+{
+}
+
+Complex Complex::operator+(const Complex &other)
+{
+ Complex result;
+ result.setReal(m_real + other.real());
+ result.setImaginary(m_imag + other.imag());
+ return result;
+}
+
+void Complex::show() const
+{
+ std::cout << "(real: " << m_real << ", imag: " << m_imag << ")";
+}
diff --git a/sources/shiboken6/tests/libsample/complex.h b/sources/shiboken6/tests/libsample/complex.h
new file mode 100644
index 000000000..168fe5c44
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/complex.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef COMPLEX_H
+#define COMPLEX_H
+
+#include "libsamplemacros.h"
+
+class LIBSAMPLE_API Complex
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Complex)
+
+ explicit Complex(double real = 0.0, double imag = 0.0) noexcept;
+ ~Complex() = default;
+
+ inline double real() const { return m_real; }
+ inline void setReal(double real) { m_real = real; }
+ inline double imag() const { return m_imag; }
+ inline void setImaginary(double imag) { m_imag = imag; }
+
+ Complex operator+(const Complex &other);
+
+ void show() const;
+
+private:
+ double m_real;
+ double m_imag;
+};
+
+#endif // COMPLEX_H
+
diff --git a/sources/shiboken6/tests/libsample/ctorconvrule.h b/sources/shiboken6/tests/libsample/ctorconvrule.h
new file mode 100644
index 000000000..a5411b749
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/ctorconvrule.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CTORCONVRULE_H
+#define CTORCONVRULE_H
+
+#include "libsamplemacros.h"
+
+class CtorConvRule
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(CtorConvRule)
+
+ explicit CtorConvRule(long value) noexcept : m_value(value) {}
+ virtual ~CtorConvRule() = default;
+ virtual void dummyVirtualMethod() {}
+ long value() { return m_value; }
+private:
+ long m_value;
+};
+
+#endif
diff --git a/sources/shiboken6/tests/libsample/ctparam.cpp b/sources/shiboken6/tests/libsample/ctparam.cpp
new file mode 100644
index 000000000..9bbbcfc3f
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/ctparam.cpp
@@ -0,0 +1,20 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "ctparam.h"
+
+namespace SampleNamespace
+{
+
+CtParam::CtParam(int value) : m_value(value)
+{
+}
+
+CtParam::~CtParam() = default;
+
+int CtParam::value() const
+{
+ return m_value;
+}
+
+} // namespace SampleNamespace
diff --git a/sources/shiboken6/tests/libsample/ctparam.h b/sources/shiboken6/tests/libsample/ctparam.h
new file mode 100644
index 000000000..fa241b587
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/ctparam.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CTPARAM_H
+#define CTPARAM_H
+
+#include "libsamplemacros.h"
+
+namespace SampleNamespace
+{
+
+class LIBSAMPLE_API CtParam
+{
+public:
+ explicit CtParam(int value);
+ virtual ~CtParam();
+
+ int value() const;
+
+private:
+ int m_value;
+};
+
+} // namespace SampleNamespace
+
+#endif // CTPARAM_H
diff --git a/sources/shiboken6/tests/libsample/cvlist.h b/sources/shiboken6/tests/libsample/cvlist.h
new file mode 100644
index 000000000..e09c7d943
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/cvlist.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CONSTVALUELIST_H
+#define CONSTVALUELIST_H
+
+#include <list>
+#include "libsamplemacros.h"
+
+class CVValueType
+{
+ CVValueType();
+};
+
+using const_ptr_value_list = std::list<const CVValueType*>;
+
+// This tests binding generation for a container of a const value type. The
+// class doesn't need to do anything; this is just to verify that the generated
+// binding code (the container conversion in particular) is const-valid.
+
+class CVListUser
+{
+public:
+ static const_ptr_value_list produce() { return {}; }
+ static void consume(const const_ptr_value_list &l) { (void)l; }
+};
+
+#endif // LIST_H
diff --git a/sources/shiboken6/tests/libsample/derived.cpp b/sources/shiboken6/tests/libsample/derived.cpp
new file mode 100644
index 000000000..d20880431
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/derived.cpp
@@ -0,0 +1,88 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "derived.h"
+
+#include <iostream>
+
+Derived::Derived(int id) noexcept : Abstract(id)
+{
+}
+
+Derived::~Derived() = default;
+
+Abstract *Derived::createObject()
+{
+ static int id = 100;
+ return new Derived(id++);
+}
+
+void Derived::pureVirtual()
+{
+}
+
+void *Derived::pureVirtualReturningVoidPtr()
+{
+ return nullptr;
+}
+
+void Derived::unpureVirtual()
+{
+}
+
+bool Derived::singleArgument(bool b)
+{
+ return !b;
+}
+
+double
+Derived::defaultValue(int n)
+{
+ return ((double) n) + 0.1;
+}
+
+OverloadedFuncEnum Derived::overloaded(int, int)
+{
+ return OverloadedFunc_ii;
+}
+
+OverloadedFuncEnum Derived::overloaded(double)
+{
+ return OverloadedFunc_d;
+}
+
+Derived::OtherOverloadedFuncEnum Derived::otherOverloaded(int, int, bool, double)
+{
+ return OtherOverloadedFunc_iibd;
+}
+
+Derived::OtherOverloadedFuncEnum Derived::otherOverloaded(int, double)
+{
+ return OtherOverloadedFunc_id;
+}
+
+struct SecretClass : public Abstract {
+ void pureVirtual() override {}
+ void *pureVirtualReturningVoidPtr() override { return nullptr; }
+ PrintFormat returnAnEnum() override { return Short; }
+ void hideFunction(HideType*) override {};
+private:
+ void pureVirtualPrivate() override {}
+};
+
+Abstract *Derived::triggerImpossibleTypeDiscovery()
+{
+ return new SecretClass;
+}
+
+struct AnotherSecretClass : public Derived {
+};
+
+Abstract *Derived::triggerAnotherImpossibleTypeDiscovery()
+{
+ return new AnotherSecretClass;
+}
+
+void Derived::pureVirtualPrivate()
+{
+}
diff --git a/sources/shiboken6/tests/libsample/derived.h b/sources/shiboken6/tests/libsample/derived.h
new file mode 100644
index 000000000..cf95cb601
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/derived.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DERIVED_H
+#define DERIVED_H
+
+#include "libsamplemacros.h"
+#include "abstract.h"
+
+enum OverloadedFuncEnum {
+ OverloadedFunc_ii,
+ OverloadedFunc_d
+};
+
+class LIBSAMPLE_API Derived : public Abstract
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Derived)
+
+ enum OtherOverloadedFuncEnum {
+ OtherOverloadedFunc_iibd,
+ OtherOverloadedFunc_id
+ };
+
+ class SomeInnerClass {
+ public:
+ void uselessMethod() {}
+ SomeInnerClass operator+(const SomeInnerClass &other) { return other; }
+ bool operator==(const SomeInnerClass &) const { return true; }
+ };
+
+ explicit Derived(int id = -1) noexcept;
+ ~Derived() override;
+ void pureVirtual() override;
+ void *pureVirtualReturningVoidPtr() override;
+ void unpureVirtual() override;
+
+ PrintFormat returnAnEnum() override { return Short; }
+ Type type() const override { return TpDerived; }
+
+ // factory method
+ static Abstract *createObject();
+
+ // single argument
+ bool singleArgument(bool b);
+
+ // method with default value
+ double defaultValue(int n = 0);
+
+ // overloads
+ OverloadedFuncEnum overloaded(int i = 0, int d = 0);
+ OverloadedFuncEnum overloaded(double n);
+
+ // more overloads
+ OtherOverloadedFuncEnum otherOverloaded(int a, int b, bool c, double d);
+ OtherOverloadedFuncEnum otherOverloaded(int a, double b);
+
+ inline SomeInnerClass returnMyParameter(const SomeInnerClass &s) { return s; }
+
+ static Abstract *triggerImpossibleTypeDiscovery();
+ static Abstract *triggerAnotherImpossibleTypeDiscovery();
+
+ void hideFunction(HideType*) override {}
+protected:
+ const char *getClassName() { return className(); }
+ virtual const char *className() const override { return "Derived"; }
+
+private:
+ void pureVirtualPrivate() override;
+};
+#endif // DERIVED_H
+
diff --git a/sources/shiboken6/tests/libsample/derivedusingct.cpp b/sources/shiboken6/tests/libsample/derivedusingct.cpp
new file mode 100644
index 000000000..720d0ed96
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/derivedusingct.cpp
@@ -0,0 +1,9 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "derivedusingct.h"
+
+void DerivedUsingCt::foo()
+{
+ delete new DerivedUsingCt(42);
+}
diff --git a/sources/shiboken6/tests/libsample/derivedusingct.h b/sources/shiboken6/tests/libsample/derivedusingct.h
new file mode 100644
index 000000000..6bc026d08
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/derivedusingct.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DERIVEDUSINGCT_H
+#define DERIVEDUSINGCT_H
+
+#include "libsamplemacros.h"
+#include "ctparam.h"
+
+class LIBSAMPLE_API DerivedUsingCt : public SampleNamespace::CtParam
+{
+public:
+ using CtParam::CtParam;
+
+ void foo();
+};
+#endif // DERIVEDUSINGCT_H
diff --git a/sources/shiboken6/tests/libsample/echo.cpp b/sources/shiboken6/tests/libsample/echo.cpp
new file mode 100644
index 000000000..7fa8433d3
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/echo.cpp
@@ -0,0 +1,4 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "echo.h"
diff --git a/sources/shiboken6/tests/libsample/echo.h b/sources/shiboken6/tests/libsample/echo.h
new file mode 100644
index 000000000..01b11a4a6
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/echo.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ECHO_H
+#define ECHO_H
+
+#include "libsamplemacros.h"
+#include "str.h"
+
+class ObjectType;
+
+class Echo
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Echo)
+
+ Echo() noexcept = default;
+ ~Echo() = default;
+
+ void doNothingWithConstBool(const bool hi);
+ void methodWithNamedArg(const Str &string = Str{});
+
+ Str operator()(const Str &s, const int i) { return s + i; }
+
+ // These method are here just for compilation test purposes
+ Echo &operator<<(unsigned int item);
+ Echo &operator<<(signed int item);
+ Echo &operator<<(const ObjectType *item);
+ Echo &operator<<(Str str);
+};
+
+inline void Echo::doNothingWithConstBool(const bool)
+{
+}
+
+inline void Echo::methodWithNamedArg(const Str &)
+{
+}
+
+inline Echo &Echo::operator<<(unsigned int)
+{
+ return *this;
+}
+
+inline Echo &Echo::operator<<(signed int)
+{
+ return *this;
+}
+
+inline Echo &Echo::operator<<(const ObjectType *)
+{
+ return *this;
+}
+
+inline Echo &Echo::operator<<(Str)
+{
+ return *this;
+}
+
+#endif // ECHO_H
diff --git a/sources/shiboken6/tests/libsample/exceptiontest.cpp b/sources/shiboken6/tests/libsample/exceptiontest.cpp
new file mode 100644
index 000000000..56144e086
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/exceptiontest.cpp
@@ -0,0 +1,46 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "exceptiontest.h"
+
+class TestException : public std::exception
+{
+public:
+ const char *what() const noexcept override
+ { return "TestException"; }
+};
+
+ExceptionTest::ExceptionTest() = default;
+
+int ExceptionTest::intThrowStdException(bool doThrow)
+{
+ if (doThrow)
+ throw TestException();
+ return 1;
+}
+
+void ExceptionTest::voidThrowStdException(bool doThrow)
+{
+ if (doThrow)
+ throw TestException();
+}
+
+int ExceptionTest::intThrowInt(bool doThrow)
+{
+ if (doThrow)
+ throw 42;
+ return 1;
+}
+
+void ExceptionTest::voidThrowInt(bool doThrow)
+{
+ if (doThrow)
+ throw 42;
+}
+
+ExceptionTest *ExceptionTest::create(bool doThrow)
+{
+ if (doThrow)
+ throw TestException();
+ return new ExceptionTest;
+}
diff --git a/sources/shiboken6/tests/libsample/exceptiontest.h b/sources/shiboken6/tests/libsample/exceptiontest.h
new file mode 100644
index 000000000..b5812a090
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/exceptiontest.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef EXCEPTIONTEST_H
+#define EXCEPTIONTEST_H
+
+#include "libsamplemacros.h"
+
+#include <exception>
+
+class LIBSAMPLE_API ExceptionTest
+{
+ public:
+ ExceptionTest();
+
+ int intThrowStdException(bool doThrow);
+ void voidThrowStdException(bool doThrow);
+
+ int intThrowInt(bool doThrow);
+ void voidThrowInt(bool doThrow);
+
+ static ExceptionTest *create(bool doThrow);
+};
+
+#endif // EXCEPTIONTEST_H
diff --git a/sources/shiboken6/tests/libsample/expression.cpp b/sources/shiboken6/tests/libsample/expression.cpp
new file mode 100644
index 000000000..6f3c5fdc5
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/expression.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+#include "expression.h"
+
+#include <sstream>
+
+Expression::Expression() noexcept = default;
+
+Expression::Expression(int number) noexcept : m_value(number)
+{
+}
+
+Expression Expression::operator+(const Expression &other)
+{
+ Expression expr;
+ expr.m_operation = Add;
+ expr.m_operand1 = std::make_shared<Expression>(*this);
+ expr.m_operand2 = std::make_shared<Expression>(other);
+ return expr;
+}
+
+Expression Expression::operator-(const Expression &other)
+{
+ Expression expr;
+ expr.m_operation = Add;
+ expr.m_operand1 = std::make_shared<Expression>(*this);
+ expr.m_operand2 = std::make_shared<Expression>(other);
+ return expr;
+}
+
+Expression Expression::operator<(const Expression &other)
+{
+ Expression expr;
+ expr.m_operation = LessThan;
+ expr.m_operand1 = std::make_shared<Expression>(*this);
+ expr.m_operand2 = std::make_shared<Expression>(other);
+ return expr;
+}
+
+Expression Expression::operator>(const Expression &other)
+{
+ Expression expr;
+ expr.m_operation = GreaterThan;
+ expr.m_operand1 = std::make_shared<Expression>(*this);
+ expr.m_operand2 = std::make_shared<Expression>(other);
+ return expr;
+}
+
+std::string Expression::toString() const
+{
+ std::ostringstream s;
+ if (m_operation == None) {
+ s << m_value;
+ return s.str();
+ }
+
+ s << '(' << m_operand1->toString();
+ switch (m_operation) {
+ case Add:
+ s << '+';
+ break;
+ case Sub:
+ s << '-';
+ break;
+ case LessThan:
+ s << '<';
+ break;
+ case GreaterThan:
+ s << '<';
+ break;
+ default:
+ s << '?';
+ break;
+ }
+ s << m_operand2->toString() << ')';
+ return s.str();
+}
diff --git a/sources/shiboken6/tests/libsample/expression.h b/sources/shiboken6/tests/libsample/expression.h
new file mode 100644
index 000000000..e7c5b7306
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/expression.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+#ifndef EXPRESSION_H
+#define EXPRESSION_H
+
+#include "libsamplemacros.h"
+
+#include <memory>
+#include <string>
+
+class LIBSAMPLE_API Expression
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Expression)
+
+ enum Operation {
+ None, Add, Sub, LessThan, GreaterThan
+ };
+
+ explicit Expression(int number) noexcept;
+ ~Expression() = default;
+
+ Expression operator>(const Expression &other);
+ Expression operator<(const Expression &other);
+ Expression operator+(const Expression &other);
+ Expression operator-(const Expression &other);
+
+ std::string toString() const;
+private:
+ int m_value = 0;
+ Operation m_operation = None;
+ std::shared_ptr<Expression> m_operand1;
+ std::shared_ptr<Expression> m_operand2;
+
+ Expression() noexcept;
+};
+
+#endif // EXPRESSION_H
diff --git a/sources/shiboken6/tests/libsample/filter.cpp b/sources/shiboken6/tests/libsample/filter.cpp
new file mode 100644
index 000000000..950847985
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/filter.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "filter.h"
+
+Data::Data(Field field, std::string value)
+ : m_field(field), m_value(value)
+{
+}
+
+Union::Union(const Data &filter)
+{
+ m_filters.push_back(filter);
+}
+
+Union::Union(const Intersection &filter)
+{
+ m_filters.push_back(filter);
+}
+
+Intersection::Intersection(const Data &filter)
+{
+ m_filters.push_back(filter);
+}
+
+Intersection::Intersection(const Union &filter)
+{
+ m_filters.push_back(filter);
+}
+
+Intersection operator&(const Intersection &a, const Intersection &b)
+{
+ Intersection filter;
+ filter.addFilter(a);
+ filter.addFilter(b);
+
+ return filter;
+}
diff --git a/sources/shiboken6/tests/libsample/filter.h b/sources/shiboken6/tests/libsample/filter.h
new file mode 100644
index 000000000..d82d38eb8
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/filter.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef FILTER_H
+#define FILTER_H
+
+#include "libsamplemacros.h"
+
+#include <string>
+#include <list>
+
+class Intersection;
+
+class LIBSAMPLE_API Filter
+{
+};
+
+class LIBSAMPLE_API Data : public Filter
+{
+public:
+ enum Field {
+ Name,
+ Album,
+ Year
+ };
+
+ explicit Data(Field field, std::string value);
+
+ Field field() const { return m_field; }
+ std::string value() const { return m_value; }
+
+private:
+ Field m_field;
+ std::string m_value;
+};
+
+class LIBSAMPLE_API Union : public Filter
+{
+public:
+
+ Union(const Data &);
+ Union(const Intersection &);
+ Union() = default;
+
+ std::list<Filter> filters() const { return m_filters; }
+ void addFilter(const Filter &data) { m_filters.push_back(data); }
+
+private:
+ std::list<Filter> m_filters;
+};
+
+class LIBSAMPLE_API Intersection : public Filter
+{
+public:
+ Intersection(const Data &);
+ Intersection(const Union &);
+ Intersection() = default;
+
+ std::list<Filter> filters() const { return m_filters; }
+ void addFilter(const Filter &data) { m_filters.push_back(data); }
+
+private:
+ std::list<Filter> m_filters;
+};
+
+LIBSAMPLE_API Intersection operator&(const Intersection &a, const Intersection &b);
+
+#endif // FILTER_H
+
+
diff --git a/sources/shiboken6/tests/libsample/functions.cpp b/sources/shiboken6/tests/libsample/functions.cpp
new file mode 100644
index 000000000..ad2f4dd5a
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/functions.cpp
@@ -0,0 +1,232 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "functions.h"
+#include "polygon.h"
+
+#include <cstring>
+#include <algorithm>
+#include <iostream>
+#include <numeric>
+
+void printSomething()
+{
+ std::cout << __FUNCTION__ << std::endl;
+}
+
+int gimmeInt()
+{
+ static int val = 2;
+ val = val * 1.3;
+ return val;
+}
+
+double gimmeDouble()
+{
+ static double val = 7.77;
+ val = val * 1.3;
+ return val;
+}
+
+std::list<Complex> gimmeComplexList()
+{
+ std::list<Complex> lst;
+ lst.push_back(Complex());
+ lst.push_back(Complex(1.1, 2.2));
+ lst.push_back(Complex(1.3, 2.4));
+ return lst;
+}
+
+Complex sumComplexPair(std::pair<Complex, Complex> cpx_pair)
+{
+ return cpx_pair.first + cpx_pair.second;
+}
+
+double multiplyPair(std::pair<double, double> pair)
+{
+ return pair.first * pair.second;
+}
+
+int countCharacters(const char *text)
+{
+ return text != nullptr ? int(std::strlen(text)) : -1;
+}
+
+char *makeCString()
+{
+ char *string = new char[std::strlen(__FUNCTION__) + 1];
+ std::strcpy(string, __FUNCTION__);
+ return string;
+}
+
+const char *returnCString()
+{
+ return __FUNCTION__;
+}
+
+GlobalOverloadFuncEnum overloadedFunc(int)
+{
+ return GlobalOverloadFunc_i;
+}
+
+GlobalOverloadFuncEnum overloadedFunc(double)
+{
+ return GlobalOverloadFunc_d;
+}
+
+char *returnNullPrimitivePointer()
+{
+ return nullptr;
+}
+
+ObjectType *returnNullObjectTypePointer()
+{
+ return nullptr;
+}
+
+Event *returnNullValueTypePointer()
+{
+ return nullptr;
+}
+
+unsigned int doubleUnsignedInt(unsigned int value)
+{
+ return value * 2;
+}
+
+long long doubleLongLong(long long value)
+{
+ return value * 2;
+}
+
+unsigned long long doubleUnsignedLongLong(unsigned long long value)
+{
+ return value * 2;
+}
+
+short doubleShort(short value)
+{
+ return value * 2;
+}
+
+int acceptInt(int x)
+{
+ return x;
+}
+
+const int *acceptIntReturnPtr(int x)
+{
+ return new int(x);
+}
+
+unsigned int acceptUInt(unsigned int x)
+{
+ return x;
+}
+
+long acceptLong(long x)
+{
+ return x;
+}
+
+unsigned long acceptULong(unsigned long x)
+{
+ return x;
+}
+
+double acceptDouble(double x)
+{
+ return x;
+}
+
+int acceptIntReference(int &x)
+{
+ return x;
+}
+
+OddBool acceptOddBoolReference(OddBool &x)
+{
+ return x;
+}
+
+int sumIntArray(int array[4])
+{
+ return std::accumulate(array, array + 4, 0);
+}
+
+double sumDoubleArray(double array[4])
+{
+ return std::accumulate(array, array + 4, double(0));
+}
+
+int sumIntMatrix(int m[2][3])
+{
+ int result = 0;
+ for (int r = 0; r < 2; ++r) {
+ for (int c = 0; c < 3; ++c)
+ result += m[r][c];
+ }
+ return result;
+}
+
+double sumDoubleMatrix(double m[2][3])
+{
+ double result = 0;
+ for (int r = 0; r < 2; ++r) {
+ for (int c = 0; c < 3; ++c)
+ result += m[r][c];
+ }
+ return result;
+}
+
+ArrayModifyTest::ArrayModifyTest() = default;
+
+int ArrayModifyTest::sumIntArray(int n, int *array)
+{
+ return std::accumulate(array, array + n, 0);
+}
+
+ClassWithFunctionPointer::ClassWithFunctionPointer()
+{
+ callFunctionPointer(0, &ClassWithFunctionPointer::doNothing);
+}
+
+void ClassWithFunctionPointer::callFunctionPointer(int dummy, void (*fp)(void *))
+{
+ size_t a = dummy;
+ fp(reinterpret_cast<void *>(a));
+}
+
+void ClassWithFunctionPointer::doNothing(void *operand)
+{
+ (void) operand;
+}
+
+std::string addStdStrings(const std::string &s1, const std::string &s2)
+{
+ return s1 + s2;
+}
+
+std::wstring addStdWStrings(const std::wstring &s1, const std::wstring &s2)
+{
+ return s1 + s2;
+}
+
+void testNullPtrT(std::nullptr_t)
+{
+ std::cout << __FUNCTION__ << '\n';
+}
+
+int takePolygon(Polygon &&p)
+{
+ auto p2 = std::move(p);
+ std::cout << __FUNCTION__ << ' ' << p2.points().size() << " points\n";
+ return int(p2.points().size());
+}
+
+int takeObjectType(ObjectType &&o)
+{
+ auto o2 = std::move(o);
+ std::cout << __FUNCTION__ << ' ' << o2.objectName().cstring() << '\n';
+ return o2.objectName().size();
+}
diff --git a/sources/shiboken6/tests/libsample/functions.h b/sources/shiboken6/tests/libsample/functions.h
new file mode 100644
index 000000000..b745aed6b
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/functions.h
@@ -0,0 +1,91 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef FUNCTIONS_H
+#define FUNCTIONS_H
+
+#include "libsamplemacros.h"
+#include "oddbool.h"
+#include "complex.h"
+#include "objecttype.h"
+
+#include <list>
+#include <utility>
+
+class Polygon;
+
+enum GlobalEnum {
+ NoThing,
+ FirstThing,
+ SecondThing,
+ ThirdThing
+};
+
+enum GlobalOverloadFuncEnum {
+ GlobalOverloadFunc_i,
+ GlobalOverloadFunc_d
+};
+
+LIBSAMPLE_API void printSomething();
+LIBSAMPLE_API int gimmeInt();
+LIBSAMPLE_API double gimmeDouble();
+LIBSAMPLE_API double multiplyPair(std::pair<double, double> pair);
+LIBSAMPLE_API std::list<Complex> gimmeComplexList();
+LIBSAMPLE_API Complex sumComplexPair(std::pair<Complex, Complex> cpx_pair);
+
+LIBSAMPLE_API int countCharacters(const char *text);
+LIBSAMPLE_API char *makeCString();
+LIBSAMPLE_API const char *returnCString();
+
+LIBSAMPLE_API char *returnNullPrimitivePointer();
+LIBSAMPLE_API ObjectType *returnNullObjectTypePointer();
+LIBSAMPLE_API Event *returnNullValueTypePointer();
+
+// Tests overloading on functions (!methods)
+LIBSAMPLE_API GlobalOverloadFuncEnum overloadedFunc(int val);
+LIBSAMPLE_API GlobalOverloadFuncEnum overloadedFunc(double val);
+
+LIBSAMPLE_API unsigned int doubleUnsignedInt(unsigned int value);
+LIBSAMPLE_API long long doubleLongLong(long long value);
+LIBSAMPLE_API unsigned long long doubleUnsignedLongLong(unsigned long long value);
+LIBSAMPLE_API short doubleShort(short value);
+
+LIBSAMPLE_API int acceptInt(int x);
+LIBSAMPLE_API const int *acceptIntReturnPtr(int x);
+LIBSAMPLE_API unsigned int acceptUInt(unsigned int x);
+LIBSAMPLE_API long acceptLong(long x);
+LIBSAMPLE_API unsigned long acceptULong(unsigned long x);
+LIBSAMPLE_API double acceptDouble(double x);
+
+LIBSAMPLE_API int acceptIntReference(int &x);
+LIBSAMPLE_API OddBool acceptOddBoolReference(OddBool &x);
+
+LIBSAMPLE_API int sumIntArray(int array[4]);
+LIBSAMPLE_API double sumDoubleArray(double array[4]);
+LIBSAMPLE_API int sumIntMatrix(int m[2][3]);
+LIBSAMPLE_API double sumDoubleMatrix(double m[2][3]);
+
+LIBSAMPLE_API std::string addStdStrings(const std::string &s1, const std::string &s2);
+LIBSAMPLE_API std::wstring addStdWStrings(const std::wstring &s1, const std::wstring &s2);
+
+LIBSAMPLE_API void testNullPtrT(std::nullptr_t);
+
+LIBSAMPLE_API int takePolygon(Polygon &&p);
+LIBSAMPLE_API int takeObjectType(ObjectType &&o);
+
+class LIBSAMPLE_API ArrayModifyTest
+{
+public:
+ ArrayModifyTest();
+ int sumIntArray(int n, int *array);
+};
+
+class LIBSAMPLE_API ClassWithFunctionPointer
+{
+public:
+ explicit ClassWithFunctionPointer();
+ void callFunctionPointer(int dummy, void (*fp)(void *));
+ static void doNothing(void *operand);
+};
+
+#endif // FUNCTIONS_H
diff --git a/sources/shiboken6/tests/libsample/handle.cpp b/sources/shiboken6/tests/libsample/handle.cpp
new file mode 100644
index 000000000..93c2abe47
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/handle.cpp
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "handle.h"
+
+SAMPLE_HANDLE HandleHolder::createHandle()
+{
+ return (SAMPLE_HANDLE) new OBJ;
+}
+
+bool HandleHolder::compare(HandleHolder *other)
+{
+ return other->m_handle == m_handle;
+}
+
+bool HandleHolder::compare2(HandleHolder *other)
+{
+ return other->m_handle2 == m_handle2;
+}
diff --git a/sources/shiboken6/tests/libsample/handle.h b/sources/shiboken6/tests/libsample/handle.h
new file mode 100644
index 000000000..07fc89d15
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/handle.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef HANDLE_H
+#define HANDLE_H
+
+#include "libsamplemacros.h"
+
+/* See http://bugs.pyside.org/show_bug.cgi?id=1105. */
+namespace Foo {
+ using SAMPLE_HANDLE = unsigned long;
+}
+
+class LIBSAMPLE_API OBJ
+{
+};
+
+using SAMPLE_HANDLE = OBJ *;
+
+class LIBSAMPLE_API HandleHolder
+{
+public:
+ explicit HandleHolder(SAMPLE_HANDLE ptr = nullptr) : m_handle(ptr) {}
+ explicit HandleHolder(Foo::SAMPLE_HANDLE val): m_handle2(val) {}
+
+ void set(SAMPLE_HANDLE ptr);
+ inline void set(const Foo::SAMPLE_HANDLE &val) { m_handle2 = val; }
+ inline SAMPLE_HANDLE handle() const { return m_handle; }
+ inline Foo::SAMPLE_HANDLE handle2() const { return m_handle2; }
+
+ static SAMPLE_HANDLE createHandle();
+ bool compare(HandleHolder *other);
+ bool compare2(HandleHolder *other);
+
+private:
+ SAMPLE_HANDLE m_handle = nullptr;
+ Foo::SAMPLE_HANDLE m_handle2 = 0;
+};
+
+inline void HandleHolder::set(SAMPLE_HANDLE)
+{
+ SAMPLE_HANDLE tmp = m_handle;
+ m_handle = tmp;
+}
+
+struct LIBSAMPLE_API PrimitiveStruct {};
+using PrimitiveStructPtr = struct PrimitiveStruct *;
+struct LIBSAMPLE_API PrimitiveStructPointerHolder
+{
+ PrimitiveStructPtr primitiveStructPtr;
+};
+
+#endif // HANDLE_H
diff --git a/sources/shiboken6/tests/libsample/implicitconv.cpp b/sources/shiboken6/tests/libsample/implicitconv.cpp
new file mode 100644
index 000000000..887fa6b1c
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/implicitconv.cpp
@@ -0,0 +1,39 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "implicitconv.h"
+
+ImplicitConv::ImplicitConv(const Null &) :
+ m_ctorEnum(CtorPrimitiveType)
+{
+}
+
+ImplicitConv ImplicitConv::implicitConvCommon(ImplicitConv implicit)
+{
+ return implicit;
+}
+
+ImplicitConv ImplicitConv::implicitConvDefault(ImplicitConv implicit)
+{
+ return implicit;
+}
+
+ImplicitConv::ICOverloadedFuncEnum ImplicitConv::implicitConvOverloading(ImplicitConv, int)
+{
+ return ImplicitConv::OverFunc_Ii;
+}
+
+ImplicitConv::ICOverloadedFuncEnum ImplicitConv::implicitConvOverloading(ImplicitConv, bool)
+{
+ return ImplicitConv::OverFunc_Ib;
+}
+
+ImplicitConv::ICOverloadedFuncEnum ImplicitConv::implicitConvOverloading(int)
+{
+ return ImplicitConv::OverFunc_i;
+}
+
+ImplicitConv::ICOverloadedFuncEnum ImplicitConv::implicitConvOverloading(CtorEnum)
+{
+ return ImplicitConv::OverFunc_C;
+}
diff --git a/sources/shiboken6/tests/libsample/implicitconv.h b/sources/shiboken6/tests/libsample/implicitconv.h
new file mode 100644
index 000000000..5d69eb487
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/implicitconv.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef IMPLICITCONV_H
+#define IMPLICITCONV_H
+
+#include "libsamplemacros.h"
+#include "null.h"
+
+class ObjectType;
+
+class LIBSAMPLE_API ImplicitConv
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(ImplicitConv)
+
+ enum CtorEnum {
+ CtorNone,
+ CtorOne,
+ CtorTwo,
+ CtorThree,
+ CtorObjectTypeReference,
+ CtorPrimitiveType
+ };
+
+ enum ICOverloadedFuncEnum {
+ OverFunc_Ii,
+ OverFunc_Ib,
+ OverFunc_i,
+ OverFunc_C
+ };
+
+ ImplicitConv() noexcept = default;
+ ImplicitConv(int objId) noexcept : m_ctorEnum(CtorOne), m_objId(objId) {}
+ ImplicitConv(CtorEnum ctorEnum) : m_ctorEnum(ctorEnum) {}
+ ImplicitConv(ObjectType&) : m_ctorEnum(CtorObjectTypeReference) {}
+ ImplicitConv(double value, bool=true) : m_ctorEnum(CtorNone), m_value(value) {}
+ ImplicitConv(const Null &null);
+ ~ImplicitConv() = default;
+
+ inline CtorEnum ctorEnum() const { return m_ctorEnum; }
+ inline int objId() const { return m_objId; }
+ inline double value() const { return m_value; }
+
+ static ImplicitConv implicitConvCommon(ImplicitConv implicit);
+
+ static ImplicitConv implicitConvDefault(ImplicitConv implicit = CtorTwo);
+
+ static ICOverloadedFuncEnum implicitConvOverloading(ImplicitConv implicit, int dummyArg);
+ static ICOverloadedFuncEnum implicitConvOverloading(ImplicitConv implicit, bool dummyArg);
+ static ICOverloadedFuncEnum implicitConvOverloading(int dummyArg);
+ static ICOverloadedFuncEnum implicitConvOverloading(CtorEnum dummyArg);
+
+private:
+ CtorEnum m_ctorEnum = CtorNone;
+ int m_objId = -1;
+ double m_value = -1.0;
+};
+
+#endif // IMPLICITCONV_H
diff --git a/sources/shiboken6/tests/libsample/injectcode.cpp b/sources/shiboken6/tests/libsample/injectcode.cpp
new file mode 100644
index 000000000..707d14ed8
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/injectcode.cpp
@@ -0,0 +1,78 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "injectcode.h"
+
+#include <sstream>
+
+InjectCode::InjectCode() noexcept = default;
+
+InjectCode::~InjectCode() = default;
+
+template<typename T>
+const char *InjectCode::toStr(const T &value)
+{
+ std::ostringstream s;
+ s << value;
+ m_valueHolder = s.str();
+ return m_valueHolder.c_str();
+}
+
+const char *InjectCode::simpleMethod1(int arg0, int arg1)
+{
+ return toStr(arg0 + arg1);
+}
+
+const char *InjectCode::simpleMethod2()
+{
+ return "_";
+}
+
+const char *InjectCode::simpleMethod3(int argc, char **argv)
+{
+ for (int i = 0; i < argc; ++i)
+ m_valueHolder += argv[i];
+ return m_valueHolder.c_str();
+}
+
+const char *InjectCode::overloadedMethod(int arg0, bool arg1)
+{
+ toStr(arg0);
+ m_valueHolder += arg1 ? "true" : "false";
+ return m_valueHolder.c_str();
+}
+
+const char *InjectCode::overloadedMethod(int arg0, double arg1)
+{
+ return toStr(arg0 + arg1);
+}
+
+const char *InjectCode::overloadedMethod(int argc, char **argv)
+{
+ return simpleMethod3(argc, argv);
+}
+
+const char *InjectCode::virtualMethod(int arg)
+{
+ return toStr(arg);
+}
+
+int InjectCode::arrayMethod(int count, int *values) const
+{
+ int ret = 0;
+ for (int i=0; i < count; i++)
+ ret += values[i];
+ return ret;
+}
+
+int InjectCode::sumArrayAndLength(int *values) const
+{
+ int sum = 0;
+
+ while (*values) {
+ sum = sum + *values + 1;
+ ++values;
+ }
+
+ return sum;
+}
diff --git a/sources/shiboken6/tests/libsample/injectcode.h b/sources/shiboken6/tests/libsample/injectcode.h
new file mode 100644
index 000000000..74046dad5
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/injectcode.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef INJECTCODE_H
+#define INJECTCODE_H
+
+#include "libsamplemacros.h"
+
+#include <utility>
+#include <string>
+
+class LIBSAMPLE_API InjectCode
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(InjectCode)
+
+ InjectCode() noexcept;
+ virtual ~InjectCode();
+
+ const char *simpleMethod1(int arg0, int arg1);
+ const char *simpleMethod2();
+ const char *simpleMethod3(int argc, char **argv);
+
+ const char *overloadedMethod(int argc, char **argv);
+ const char *overloadedMethod(int arg0, double arg1);
+ const char *overloadedMethod(int arg0, bool arg1);
+
+ virtual int arrayMethod(int count, int *values) const;
+ inline int callArrayMethod(int count, int *values) const { return arrayMethod(count, values); }
+ virtual const char *virtualMethod(int arg);
+ int sumArrayAndLength(int *values) const;
+
+private:
+ // This attr is just to retain the memory pointed by all return values,
+ // So, the memory returned by all methods will be valid until someone call
+ // another method of this class.
+ std::string m_valueHolder;
+
+ template<typename T>
+ const char *toStr(const T &value);
+};
+
+#endif // INJECTCODE_H
+
diff --git a/sources/shiboken6/tests/libsample/intwrapper.cpp b/sources/shiboken6/tests/libsample/intwrapper.cpp
new file mode 100644
index 000000000..0eaf30465
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/intwrapper.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+#include "intwrapper.h"
+
+int IntWrapper::toInt() const
+{
+ return m_number;
+}
+
+IntWrapper &IntWrapper::operator ++()
+{
+ ++m_number;
+ return *this;
+}
+
+IntWrapper IntWrapper::operator++(int)
+{
+ IntWrapper result(*this);
+ ++m_number;
+ return result;
+}
+
+IntWrapper &IntWrapper::operator--()
+{
+ --m_number;
+ return *this;
+}
+
+IntWrapper IntWrapper::operator--(int)
+{
+ IntWrapper result(*this);
+ --m_number;
+ return result;
+}
diff --git a/sources/shiboken6/tests/libsample/intwrapper.h b/sources/shiboken6/tests/libsample/intwrapper.h
new file mode 100644
index 000000000..cfda5adc7
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/intwrapper.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef INTWRAPPER_H
+#define INTWRAPPER_H
+
+#include "libsamplemacros.h"
+
+// Wrapper around int for testing operators
+class LIBSAMPLE_API IntWrapper
+{
+public:
+ constexpr explicit IntWrapper(int i) noexcept : m_number(i) {}
+ int toInt() const;
+
+ IntWrapper &operator++();
+ IntWrapper operator++(int); // Postfix
+
+ IntWrapper &operator--();
+ IntWrapper operator--(int); // Postfix
+
+ friend constexpr inline bool operator==(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number == rhs.m_number; }
+ friend constexpr inline bool operator!=(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number != rhs.m_number; }
+ friend constexpr inline bool operator<(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number < rhs.m_number; }
+ friend constexpr inline bool operator>(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number > rhs.m_number; }
+ friend constexpr inline bool operator<=(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number <= rhs.m_number; }
+ friend constexpr inline bool operator>=(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return lhs.m_number >= rhs.m_number; }
+
+ constexpr inline IntWrapper &operator+=(IntWrapper i);
+ constexpr inline IntWrapper &operator-=(const IntWrapper i);
+
+ friend constexpr inline IntWrapper operator+(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return IntWrapper(lhs.m_number + rhs.m_number); }
+ friend constexpr inline IntWrapper operator-(IntWrapper lhs, IntWrapper rhs) noexcept
+ { return IntWrapper(lhs.m_number - rhs.m_number); }
+
+ // FIXME: Test spaceship operator with C++ 20:
+ // auto operator<=>(IntWrapper) const = default;
+
+private:
+ int m_number;
+};
+
+constexpr inline IntWrapper &IntWrapper::operator+=(IntWrapper i)
+{
+ m_number += i.m_number;
+ return *this;
+}
+
+constexpr inline IntWrapper &IntWrapper::operator-=(const IntWrapper i)
+{
+ m_number -= i.m_number;
+ return *this;
+}
+
+#endif // INTWRAPPER_H
diff --git a/sources/shiboken6/tests/libsample/libsamplemacros.h b/sources/shiboken6/tests/libsample/libsamplemacros.h
new file mode 100644
index 000000000..93e549bfb
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/libsamplemacros.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef LIBSAMPLEMACROS_H
+#define LIBSAMPLEMACROS_H
+
+#include "../libminimal/libminimalmacros.h"
+
+#define LIBSAMPLE_EXPORT LIBMINIMAL_EXPORT
+#define LIBSAMPLE_IMPORT LIBMINIMAL_IMPORT
+
+#ifdef LIBSAMPLE_BUILD
+# define LIBSAMPLE_API LIBSAMPLE_EXPORT
+#else
+# define LIBSAMPLE_API LIBSAMPLE_IMPORT
+#endif
+
+#endif // LIBSAMPLEMACROS_H
diff --git a/sources/shiboken6/tests/libsample/list.h b/sources/shiboken6/tests/libsample/list.h
new file mode 100644
index 000000000..5e06d2a66
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/list.h
@@ -0,0 +1,99 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef LIST_H
+#define LIST_H
+
+#include <list>
+#include "libsamplemacros.h"
+#include "point.h"
+
+class ObjectType;
+
+template<class T>
+class List : public std::list<T>
+{
+};
+
+class IntList : public List<int>
+{
+public:
+ LIBMINIMAL_DEFAULT_MOVE(IntList)
+
+ enum CtorEnum {
+ NoParamsCtor,
+ IntCtor,
+ CopyCtor,
+ ListOfIntCtor
+ };
+
+ inline IntList() noexcept : m_ctorUsed(NoParamsCtor) {}
+ inline explicit IntList(int val) : m_ctorUsed(IntCtor) { push_back(val); }
+ inline IntList(const List<int> &lst) : List<int>(lst), m_ctorUsed(ListOfIntCtor) {}
+ ~IntList() = default;
+
+ inline IntList(const IntList &lst) : List<int>(lst), m_ctorUsed(CopyCtor) {}
+ IntList &operator=(const IntList &) = default;
+
+ inline void append(int v) { insert(end(), v); }
+ CtorEnum constructorUsed() { return m_ctorUsed; }
+private:
+ CtorEnum m_ctorUsed;
+};
+
+class PointValueList : public List<Point>
+{
+public:
+ LIBMINIMAL_DEFAULT_MOVE(PointValueList)
+
+ enum CtorEnum {
+ NoParamsCtor,
+ PointCtor,
+ CopyCtor,
+ ListOfPointValuesCtor
+ };
+
+ inline PointValueList() noexcept : m_ctorUsed(NoParamsCtor) {}
+ inline explicit PointValueList(Point val) : m_ctorUsed(PointCtor) { push_back(val); }
+ inline PointValueList(const List<Point> &lst) : List<Point>(lst), m_ctorUsed(ListOfPointValuesCtor) {}
+
+ inline PointValueList(const PointValueList &lst) : List<Point>(lst), m_ctorUsed(CopyCtor) {}
+ PointValueList &operator=(const PointValueList &) = default;
+ ~PointValueList() = default;
+
+ inline void append(Point v) { insert(end(), v); }
+ CtorEnum constructorUsed() { return m_ctorUsed; }
+private:
+ CtorEnum m_ctorUsed;
+};
+
+class ObjectTypePtrList : public List<ObjectType*>
+{
+public:
+ LIBMINIMAL_DEFAULT_MOVE(ObjectTypePtrList)
+
+ enum CtorEnum {
+ NoParamsCtor,
+ ObjectTypeCtor,
+ CopyCtor,
+ ListOfObjectTypePtrCtor
+ };
+
+ inline ObjectTypePtrList() = default;
+ inline ObjectTypePtrList(const ObjectTypePtrList &lst) :
+ List<ObjectType*>(lst), m_ctorUsed(CopyCtor) {}
+ inline explicit ObjectTypePtrList(ObjectType *val) :
+ m_ctorUsed(ObjectTypeCtor) { push_back(val); }
+ inline ObjectTypePtrList(const List<ObjectType*> &lst) :
+ List<ObjectType*>(lst), m_ctorUsed(ListOfObjectTypePtrCtor) {}
+ ~ObjectTypePtrList() = default;
+
+ ObjectTypePtrList &operator=(const ObjectTypePtrList &) = default;
+
+ inline void append(ObjectType *v) { insert(end(), v); }
+ CtorEnum constructorUsed() { return m_ctorUsed; }
+private:
+ CtorEnum m_ctorUsed = NoParamsCtor;
+};
+
+#endif // LIST_H
diff --git a/sources/shiboken6/tests/libsample/listuser.cpp b/sources/shiboken6/tests/libsample/listuser.cpp
new file mode 100644
index 000000000..9bb7f7798
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/listuser.cpp
@@ -0,0 +1,63 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "listuser.h"
+
+#include <numeric>
+#include <cstdlib>
+
+std::list<int> ListUser::callCreateList()
+{
+ return createList();
+}
+
+ListUser::ListUser() = default;
+ListUser::ListUser(const ListUser &other) = default;
+ListUser::ListUser(ListUser &&other) noexcept = default;
+ListUser &ListUser::operator=(const ListUser &other) = default;
+ListUser &ListUser::operator=(ListUser &&other) noexcept = default;
+ListUser::~ListUser() = default;
+
+std::list<int> ListUser::createList()
+{
+ std::list<int> retval;
+ for (int i = 0; i < 4; i++)
+ retval.push_front(rand());
+ return retval;
+}
+
+std::list<Complex> ListUser::createComplexList(Complex cpx0, Complex cpx1)
+{
+ std::list<Complex> retval;
+ retval.push_back(cpx0);
+ retval.push_back(cpx1);
+ return retval;
+}
+
+double ListUser::sumList(std::list<int> vallist)
+{
+ return std::accumulate(vallist.begin(), vallist.end(), 0.0);
+}
+
+double ListUser::sumList(std::list<double> vallist)
+{
+ return std::accumulate(vallist.begin(), vallist.end(), 0.0);
+}
+
+ListUser::ListOfSomething ListUser::listOfPoints(const std::list<Point> &)
+{
+ return ListOfPoint;
+}
+
+ListUser::ListOfSomething ListUser::listOfPoints(const std::list<PointF> &)
+{
+ return ListOfPointF;
+}
+
+void ListUser::multiplyPointList(PointList &points, double multiplier)
+{
+ for (auto *point : points) {
+ point->setX(point->x() * multiplier);
+ point->setY(point->y() * multiplier);
+ }
+}
diff --git a/sources/shiboken6/tests/libsample/listuser.h b/sources/shiboken6/tests/libsample/listuser.h
new file mode 100644
index 000000000..96781ed16
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/listuser.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef LISTUSER_H
+#define LISTUSER_H
+
+#include "complex.h"
+#include "point.h"
+#include "pointf.h"
+
+#include "libsamplemacros.h"
+
+#include <list>
+
+class LIBSAMPLE_API ListUser
+{
+public:
+ using PointList = std::list<Point *>;
+
+ enum ListOfSomething {
+ ListOfPoint,
+ ListOfPointF
+ };
+
+ ListUser();
+ ListUser(const ListUser &other);
+ ListUser(ListUser &&other) noexcept;
+ ListUser &operator=(const ListUser &other);
+ ListUser &operator=(ListUser &&other) noexcept;
+ virtual ~ListUser();
+
+ virtual std::list<int> createList();
+ std::list<int> callCreateList();
+
+ static std::list<Complex> createComplexList(Complex cpx0, Complex cpx1);
+
+ double sumList(std::list<int> vallist);
+ double sumList(std::list<double> vallist);
+
+ static ListOfSomething listOfPoints(const std::list<Point> &pointlist);
+ static ListOfSomething listOfPoints(const std::list<PointF> &pointlist);
+
+ static void multiplyPointList(PointList &points, double multiplier);
+
+ inline void setList(std::list<int> lst) { m_lst = lst; }
+ inline std::list<int> getList() const { return m_lst; }
+
+private:
+ std::list<int> m_lst;
+};
+
+#endif // LISTUSER_H
+
diff --git a/sources/shiboken6/tests/libsample/main.cpp b/sources/shiboken6/tests/libsample/main.cpp
new file mode 100644
index 000000000..1b44642ae
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/main.cpp
@@ -0,0 +1,209 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <iostream>
+#include <list>
+#include "abstract.h"
+#include "derived.h"
+#include "kindergarten.h"
+#include "complex.h"
+#include "point.h"
+#include "size.h"
+#include "listuser.h"
+#include "samplenamespace.h"
+
+int
+main(int argv, char **argc)
+{
+ std::cout << std::endl;
+
+ Derived derived;
+
+ std::cout << std::endl;
+
+ derived.unpureVirtual();
+ derived.pureVirtual();
+ derived.callPureVirtual();
+
+ std::cout << std::endl;
+ auto *abs = Abstract::createObject();
+ std::cout << "Abstract::createObject(): " << abs << std::endl << std::endl;
+ delete abs;
+
+ abs = Derived::createObject();
+ std::cout << "Derived::createObject() : ";
+ abs->show();
+ std::cout << std::endl;
+ delete abs;
+ std::cout << std::endl;
+
+ abs = Derived::createObject();
+ std::cout << "Derived::createObject() : ";
+ abs->show();
+ std::cout << std::endl;
+ delete abs;
+ std::cout << std::endl;
+
+ std::cout << "\n-----------------------------------------\n";
+
+ KinderGarten kg;
+ Derived *d[] = { 0, 0, 0 };
+
+ for (int i = 0; i < 3; i++) {
+ d[i] = new Derived(i);
+ d[i]->show();
+ std::cout << std::endl;
+ kg.addChild(d[i]);
+ }
+
+ kg.show();
+ std::cout << std::endl;
+
+ std::cout << "\n* kill child ";
+ d[2]->show();
+ std::cout << " ----------------\n";
+ kg.killChild(d[2]);
+ kg.show();
+ std::cout << std::endl;
+
+ std::cout << "\n* release child ";
+ d[1]->show();
+ std::cout << " -------------\n";
+ Abstract *released = kg.releaseChild(d[1]);
+ std::cout << "released: ";
+ released->show();
+ std::cout << std::endl;
+ kg.show();
+ std::cout << "\n\n* kill children ------------------------------------\n";
+ kg.killChildren();
+ kg.show();
+ std::cout << "\n\n-----------------------------------------\n";
+ ListUser lu;
+ std::cout << "ListUser::createList()\n";
+ std::list<int> intlist = lu.createList();
+ for (std::list<int>::iterator it = intlist.begin(); it != intlist.end(); it++)
+ std::cout << "* " << *it << std::endl;
+
+ std::cout << "ListUser::createComplexList\n";
+ std::list<Complex> cpxlist = ListUser::createComplexList(Complex(1.1, 2.2), Complex(3.3, 4.4));
+ for (std::list<Complex>::iterator it = cpxlist.begin(); it != cpxlist.end(); it++) {
+ std::cout << "* ";
+ (*it).show();
+ std::cout << std::endl;
+ }
+ std::cout << "\n-----------------------------------------\n"
+ << "SampleNamespace\n";
+
+ std::cout << "SampleNamespace::RandomNumber: ";
+ std::cout << SampleNamespace::getNumber(SampleNamespace::RandomNumber);
+ std::cout << std::endl;
+ std::cout << "SampleNamespace::UnixTime: ";
+ std::cout << SampleNamespace::getNumber(SampleNamespace::UnixTime);
+ std::cout << std::endl;
+ double val_d = 1.3;
+ std::cout << "SampleNamespace::powerOfTwo(" << val_d << "): ";
+ std::cout << SampleNamespace::powerOfTwo(val_d) << std::endl;
+ int val_i = 7;
+ std::cout << "SampleNamespace::powerOfTwo(" << val_i << "): ";
+ std::cout << SampleNamespace::powerOfTwo(val_i) << std::endl;
+ std::cout << std::endl;
+
+ std::cout << "-----------------------------------------" << std::endl;
+ std::cout << "Point" << std::endl;
+
+ Point p1(1.1, 2.2);
+ std::cout << "p1: ";
+ p1.show();
+ std::cout << std::endl;
+
+ Point p2(3.4, 5.6);
+ std::cout << "p2: ";
+ p2.show();
+ std::cout << std::endl;
+
+ std::cout << "p1 + p2 == ";
+ (p1 + p2).show();
+ std::cout << std::endl;
+
+ std::cout << "p1 * 2.0 == ";
+ (p1 * 2.0).show();
+ std::cout << std::endl;
+
+ std::cout << "1.5 * p2 == ";
+ (1.5 * p2).show();
+ std::cout << std::endl;
+
+ std::cout << "p1: ";
+ p1.show();
+ std::cout << std::endl << "p2: ";
+ p2.show();
+ std::cout << std::endl << "p1 += p2" << std::endl;
+ p1 += p2;
+ std::cout << "p1: ";
+ p1.show();
+ std::cout << std::endl;
+
+ std::cout << "p1 == p2 ? " << ((p1 == p2) ? "true" : "false") << std::endl;
+ std::cout << "p1 == p1 ? " << ((p1 == p1) ? "true" : "false") << std::endl;
+ std::cout << "p2 == p2 ? " << ((p2 == p2) ? "true" : "false") << std::endl;
+
+ std::cout << "-----------------------------------------" << std::endl;
+ std::cout << "Size" << std::endl;
+
+ Size s1(2, 2);
+ std::cout << "s1: ";
+ s1.show();
+ std::cout << ", area: " << s1.calculateArea();
+ std::cout << std::endl;
+
+ Size s2(3, 5);
+ std::cout << "s2: ";
+ s2.show();
+ std::cout << ", area: " << s2.calculateArea();
+ std::cout << std::endl;
+
+ std::cout << std::endl;
+
+ std::cout << "s1 == s2 ? " << ((s1 == s2) ? "true" : "false") << std::endl;
+ std::cout << "s1 != s2 ? " << ((s1 != s2) ? "true" : "false") << std::endl;
+
+ std::cout << "s1 < s2 ? " << ((s1 < s2) ? "true" : "false") << std::endl;
+ std::cout << "s1 <= s2 ? " << ((s1 <= s2) ? "true" : "false") << std::endl;
+ std::cout << "s1 > s2 ? " << ((s1 > s2) ? "true" : "false") << std::endl;
+ std::cout << "s1 >= s2 ? " << ((s1 >= s2) ? "true" : "false") << std::endl;
+
+ std::cout << "s1 < 10 ? " << ((s1 < 10) ? "true" : "false") << std::endl;
+ std::cout << "s1 <= 10 ? " << ((s1 <= 10) ? "true" : "false") << std::endl;
+ std::cout << "s1 > 10 ? " << ((s1 > 10) ? "true" : "false") << std::endl;
+ std::cout << "s1 >= 10 ? " << ((s1 >= 10) ? "true" : "false") << std::endl;
+ std::cout << "s2 < 10 ? " << ((s2 < 10) ? "true" : "false") << std::endl;
+ std::cout << "s2 <= 10 ? " << ((s2 <= 10) ? "true" : "false") << std::endl;
+ std::cout << "s2 > 10 ? " << ((s2 > 10) ? "true" : "false") << std::endl;
+ std::cout << "s2 >= 10 ? " << ((s2 >= 10) ? "true" : "false") << std::endl;
+ std::cout << std::endl;
+
+ std::cout << "s1: ";
+ s1.show();
+ std::cout << std::endl << "s2: ";
+ s2.show();
+ std::cout << std::endl << "s1 += s2" << std::endl;
+ s1 += s2;
+ std::cout << "s1: ";
+ s1.show();
+ std::cout << std::endl;
+
+ std::cout << std::endl;
+
+ std::cout << "s1: ";
+ s1.show();
+ std::cout << std::endl << "s1 *= 2.0" << std::endl;
+ s1 *= 2.0;
+ std::cout << "s1: ";
+ s1.show();
+ std::cout << std::endl;
+
+ std::cout << std::endl;
+
+ return 0;
+}
+
diff --git a/sources/shiboken6/tests/libsample/mapuser.cpp b/sources/shiboken6/tests/libsample/mapuser.cpp
new file mode 100644
index 000000000..40059bbcd
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/mapuser.cpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "mapuser.h"
+
+#include <iostream>
+
+std::map<std::string, std::pair<Complex, int> > MapUser::callCreateMap()
+{
+ return createMap();
+}
+
+std::map<std::string, std::pair<Complex, int> > MapUser::createMap()
+{
+ std::map<std::string, std::pair<Complex, int> > retval;
+
+ std::pair<Complex, int> value{Complex(1.2, 3.4), 2};
+ retval.insert({"zero", value});
+
+ value = {Complex(5.6, 7.8), 3};
+ retval.insert({"one", value});
+
+ value = {Complex(9.1, 2.3), 5};
+ retval.insert({"two", value});
+
+ return retval;
+}
+
+void MapUser::showMap(std::map<std::string, int> mapping)
+{
+ std::cout << __FUNCTION__ << std::endl;
+ for (const auto &p : mapping)
+ std::cout << p.first << " => " << p.second << std::endl;
+}
+
+void MapUser::pointerToMap(std::map<std::string, std::string> *)
+{
+}
+
+void MapUser::referenceToMap(std::map<std::string, std::string> &)
+{
+}
+
+std::map<int, std::list<std::list<double> > > MapUser::foo() const
+{
+ std::map<int, std::list<std::list<double> > > result;
+ return result;
+}
diff --git a/sources/shiboken6/tests/libsample/mapuser.h b/sources/shiboken6/tests/libsample/mapuser.h
new file mode 100644
index 000000000..1677a4bfb
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/mapuser.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MAPUSER_H
+#define MAPUSER_H
+
+#include "libsamplemacros.h"
+
+#include "complex.h"
+#include "bytearray.h"
+
+#include <map>
+#include <list>
+#include <utility>
+#include <string>
+
+class LIBSAMPLE_API MapUser
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(MapUser)
+
+ MapUser() noexcept = default;
+ virtual ~MapUser() = default;
+
+ virtual std::map<std::string, std::pair<Complex, int> > createMap();
+ std::map<std::string, std::pair<Complex, int> > callCreateMap();
+
+ void showMap(std::map<std::string, int> mapping);
+
+ inline void setMap(std::map<std::string, std::list<int> > map) { m_map = map; }
+ inline std::map<std::string, std::list<int> > getMap() { return m_map; }
+
+ // Compile test
+ static void pointerToMap(std::map<std::string, std::string> *arg);
+ static void referenceToMap(std::map<std::string, std::string> &arg);
+
+ inline const std::map<int, ByteArray> &passMapIntValueType(const std::map<int, ByteArray>& arg) { return arg; }
+
+ std::map<int, std::list<std::list<double> > > foo() const;
+
+private:
+ std::map<std::string, std::list<int> > m_map;
+};
+
+#endif // MAPUSER_H
diff --git a/sources/shiboken6/tests/libsample/modelindex.h b/sources/shiboken6/tests/libsample/modelindex.h
new file mode 100644
index 000000000..48e1b7de3
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/modelindex.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MODELINDEX_H
+#define MODELINDEX_H
+
+class ModelIndex
+{
+public:
+ ModelIndex() = default;
+
+ inline void setValue(int value) { m_value = value; }
+ inline int value() const { return m_value; }
+ static int getValue(const ModelIndex &index) { return index.value(); }
+
+private:
+ int m_value = 0;
+};
+
+class ReferentModelIndex
+{
+public:
+ ReferentModelIndex() = default;
+
+ explicit ReferentModelIndex(const ModelIndex &index) : m_index(index) {}
+
+ inline void setValue(int value) { m_index.setValue(value); }
+ inline int value() const { return m_index.value(); }
+ operator const ModelIndex&() const { return m_index; }
+
+private:
+ ModelIndex m_index;
+};
+
+class PersistentModelIndex
+{
+public:
+ PersistentModelIndex() = default;
+
+ explicit PersistentModelIndex(const ModelIndex &index) : m_index(index) {}
+
+ inline void setValue(int value) { m_index.setValue(value); }
+ inline int value() const { return m_index.value(); }
+ operator ModelIndex() const { return m_index; }
+
+private:
+ ModelIndex m_index;
+};
+
+#endif // MODELINDEX_H
diff --git a/sources/shiboken6/tests/libsample/modifications.cpp b/sources/shiboken6/tests/libsample/modifications.cpp
new file mode 100644
index 000000000..6d627c4c1
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/modifications.cpp
@@ -0,0 +1,207 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "modifications.h"
+#include "objecttype.h"
+
+#include <iostream>
+
+Modifications::Modifications()
+ : m_object(new ObjectType())
+{
+ m_object->setObjectName("MyObject");
+}
+
+Modifications::~Modifications()
+{
+ delete m_object;
+}
+
+Modifications::OverloadedModFunc Modifications::overloaded(int, bool, Point, Point)
+{
+ return Overloaded_ibPP;
+}
+
+Modifications::OverloadedModFunc Modifications::overloaded(int, bool, int, int)
+{
+ return Overloaded_ibii;
+}
+
+Modifications::OverloadedModFunc Modifications::overloaded(int, bool, int, Point)
+{
+ return Overloaded_ibiP;
+}
+
+Modifications::OverloadedModFunc Modifications::overloaded(int, bool, int, bool)
+{
+ return Overloaded_ibib;
+}
+
+Modifications::OverloadedModFunc Modifications::overloaded(int, bool, int, double)
+{
+ return Overloaded_ibid;
+}
+
+void Modifications::argRemoval0(int, bool, int, int)
+{
+}
+
+void Modifications::argRemoval0(int, bool, int, bool)
+{
+}
+
+void Modifications::argRemoval1(int, bool, Point, Point, int)
+{
+}
+
+void Modifications::argRemoval1(int, bool, int, bool)
+{
+}
+
+void Modifications::argRemoval2(int, bool, Point, Point, int)
+{
+}
+
+void Modifications::argRemoval3(int, Point, bool, Point, int)
+{
+}
+
+void Modifications::argRemoval4(int, Point, bool, Point, int)
+{
+}
+
+void Modifications::argRemoval5(int, bool, Point, Point, int)
+{
+}
+
+void Modifications::argRemoval5(int, bool, int, bool)
+{
+}
+
+std::pair<double, double> Modifications::pointToPair(Point pt, bool *ok)
+{
+ std::pair<double, double> retval(pt.x(), pt.y());
+ *ok = true;
+ return retval;
+}
+
+double Modifications::multiplyPointCoordsPlusValue(bool *ok, Point pt, double value)
+{
+ double retval = (pt.x() * pt.y()) + value;
+ *ok = true;
+ return retval;
+}
+
+int Modifications::doublePlus(int value, int plus)
+{
+ return (2 * value) + plus;
+}
+
+int Modifications::power(int base, int exponent)
+{
+ if (exponent == 0)
+ return 1;
+ int retval = base;
+ for (int i = 1; i < exponent; i++)
+ retval = retval * base;
+ return retval;
+}
+
+int Modifications::timesTen(int number)
+{
+ return number * 10;
+}
+
+int Modifications::increment(int number)
+{
+ return ++number;
+}
+
+void Modifications::exclusiveCppStuff()
+{
+ std::cout << __FUNCTION__ << std::endl;
+}
+
+int Modifications::cppMultiply(int a, int b)
+{
+ return a * b;
+}
+
+const char *Modifications::className()
+{
+ return "Modifications";
+}
+
+Point Modifications::sumPointArray(int arraySize, const Point pointArray[])
+{
+ Point point;
+ for (int i = 0; i < arraySize; ++i)
+ point = point + pointArray[i];
+ return point;
+}
+
+int Modifications::getSize(const void *data, int size)
+{
+ (void)data;
+ return size;
+}
+
+int Modifications::sumPointCoordinates(const Point *point)
+{
+ return point->x() + point->y();
+}
+
+double Modifications::differenceOfPointCoordinates(const Point *pt, bool *ok)
+{
+ if (!pt) {
+ *ok = false;
+ return 0.0;
+ }
+ *ok = true;
+ double result = pt->x() - pt->y();
+ if (result < 0)
+ result = result * -1.0;
+ return result;
+}
+
+bool Modifications::nonConversionRuleForArgumentWithDefaultValue(ObjectType **object)
+{
+ if (object)
+ *object = m_object;
+ return true;
+}
+
+void Modifications::setEnumValue(TestEnum e)
+{
+ m_enumValue = e;
+}
+
+Modifications::TestEnum Modifications::enumValue() const
+{
+ return m_enumValue;
+}
+
+Modifications::TestEnum Modifications::defaultEnumValue() const
+{
+ return TestEnumValue2;
+}
+
+bool Modifications::wasGetAttroCalled() const
+{
+ return m_getAttroCalled;
+}
+
+void Modifications::notifyGetAttroCalled()
+{
+ m_getAttroCalled = true;
+}
+
+bool Modifications::wasSetAttroCalled() const
+{
+ return m_setAttroCalled;
+}
+
+void Modifications::notifySetAttroCalled()
+{
+ m_setAttroCalled = true;
+}
diff --git a/sources/shiboken6/tests/libsample/modifications.h b/sources/shiboken6/tests/libsample/modifications.h
new file mode 100644
index 000000000..5bd1bac47
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/modifications.h
@@ -0,0 +1,145 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MODIFICATIONS_H
+#define MODIFICATIONS_H
+
+#include "libsamplemacros.h"
+#include "point.h"
+#include "oddbool.h"
+
+#include <utility>
+
+class ObjectType;
+
+class LIBSAMPLE_API Modifications
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Modifications)
+
+ Modifications();
+ virtual ~Modifications();
+
+ enum OverloadedModFunc {
+ OverloadedNone,
+ Overloaded_ibid,
+ Overloaded_ibib,
+ Overloaded_ibiP,
+ Overloaded_ibii,
+ Overloaded_ibPP
+ };
+
+ enum TestEnum {
+ TestEnumValue1,
+ TestEnumValue2
+ };
+
+ // those overloaded methods should be heavily modified
+ // to push the overload decisor to its limits
+ OverloadedModFunc overloaded(int a0, bool b0, int c0, double d0);
+ OverloadedModFunc overloaded(int a1, bool b1, int c1, bool d1);
+ OverloadedModFunc overloaded(int a2, bool b2, int c2, Point d2);
+ OverloadedModFunc overloaded(int a3, bool b3, int c3 = 123, int d3 = 456);
+ OverloadedModFunc overloaded(int a4, bool b4, Point c4, Point d4);
+
+ void argRemoval0(int a0, bool a1, int a2 = 123, int a3 = 456);
+ void argRemoval0(int a0, bool a1, int a2, bool a3);
+
+ void argRemoval1(int a0, bool a1, Point a2 = Point(1, 2), Point a3 = Point(3, 4),
+ int a4 = 333);
+ void argRemoval1(int a0, bool a1, int a2, bool a3);
+
+ void argRemoval2(int a0, bool a1, Point a2 = Point(1, 2), Point a3 = Point(3, 4),
+ int a4 = 333);
+
+ void argRemoval3(int a0, Point a1 = Point(1, 2), bool a2 = true, Point a3 = Point(3, 4),
+ int a4 = 333);
+
+ void argRemoval4(int a0, Point a1, bool a2, Point a3 = Point(3, 4), int a4 = 333);
+
+ void argRemoval5(int a0, bool a1, Point a2 = Point(1, 2), Point a3 = Point(3, 4),
+ int a4 = 333);
+ void argRemoval5(int a0, bool a1, int a2, bool a3);
+
+ // 'ok' must be removed and the return value will be changed
+ // to a tuple (PyObject*) containing the expected result plus
+ // the 'ok' value as a Python boolean
+ std::pair<double, double> pointToPair(Point pt, bool *ok);
+
+ // same as 'pointToPair' except that this time 'ok' is the first argument
+ double multiplyPointCoordsPlusValue(bool *ok, Point pt, double value);
+
+ // completely remove 'plus' from the Python side
+ int doublePlus(int value, int plus = 0);
+
+ // the default value for both arguments must be changed in Python
+ int power(int base = 1, int exponent = 0);
+
+ // in Python set argument default value to 10
+ int timesTen(int number);
+
+ // in Python remove the argument default value
+ int increment(int number = 0);
+
+ // don't export this method to Python
+ void exclusiveCppStuff();
+
+ // change the name of this regular method
+ int cppMultiply(int a, int b);
+
+ // change the name of this virtual method
+ virtual const char *className();
+
+ Point sumPointArray(int arraySize, const Point pointArray[]);
+
+ // Replace 'const void*' by 'ByteArray&'.
+ int getSize(const void *data, int size);
+
+ // Mark the argument with a <no-null-pointer/> tag;
+ // the test implementation must expect point never to be null.
+ int sumPointCoordinates(const Point *point);
+
+ // Modify the return value of a virtual method.
+ virtual double differenceOfPointCoordinates(const Point *pt, bool *ok);
+ double callDifferenceOfPointCoordinates(const Point *pt, bool *ok)
+ { return differenceOfPointCoordinates(pt, ok); }
+
+ // Sets an ObjectType in the argument and returns true.
+ bool nonConversionRuleForArgumentWithDefaultValue(ObjectType **object = nullptr);
+ ObjectType *getObject() const { return m_object; }
+
+ // Inject code with a %CONVERTTOPYTHON that receives an user's primitive type.
+ static inline OddBool passOddBool(OddBool ob) { return ob; }
+
+ void setEnumValue(TestEnum e = TestEnumValue1);
+ TestEnum enumValue() const;
+ TestEnum defaultEnumValue() const;
+
+ bool wasGetAttroCalled() const;
+ void notifyGetAttroCalled();
+
+ bool wasSetAttroCalled() const;
+ void notifySetAttroCalled();
+
+private:
+ ObjectType *m_object;
+ TestEnum m_enumValue = TestEnumValue1;
+ bool m_getAttroCalled = false;
+ bool m_setAttroCalled = false;
+};
+
+class LIBSAMPLE_API AbstractModifications : public Modifications
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(AbstractModifications)
+
+ AbstractModifications() noexcept = default;
+ ~AbstractModifications() override = default;
+
+ inline bool invert(bool value) { return !value; }
+
+ // completely remove this method in Python
+ virtual void pointlessPureVirtualMethod() = 0;
+};
+
+#endif // MODIFICATIONS_H
diff --git a/sources/shiboken6/tests/libsample/modified_constructor.cpp b/sources/shiboken6/tests/libsample/modified_constructor.cpp
new file mode 100644
index 000000000..c39c97738
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/modified_constructor.cpp
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "modified_constructor.h"
+
+ModifiedConstructor::ModifiedConstructor(int first_arg)
+{
+ m_stored_value = first_arg;
+}
+
+int ModifiedConstructor::retrieveValue() const
+{
+ return m_stored_value;
+}
+
+
diff --git a/sources/shiboken6/tests/libsample/modified_constructor.h b/sources/shiboken6/tests/libsample/modified_constructor.h
new file mode 100644
index 000000000..a27899f3f
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/modified_constructor.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MODIFIEDCONSTRUCTOR_H
+#define MODIFIEDCONSTRUCTOR_H
+
+#include "libsamplemacros.h"
+
+class LIBSAMPLE_API ModifiedConstructor
+{
+public:
+
+ explicit ModifiedConstructor(int first_arg);
+ int retrieveValue() const;
+
+private:
+ int m_stored_value;
+};
+
+#endif // MODIFIEDCONSTRUCTOR_H
+
diff --git a/sources/shiboken6/tests/libsample/multiple_derived.cpp b/sources/shiboken6/tests/libsample/multiple_derived.cpp
new file mode 100644
index 000000000..be535c62f
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/multiple_derived.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "multiple_derived.h"
+
+MDerived1::MDerived1() noexcept = default;
+
+MDerived2::MDerived2() noexcept = default;
+
+MDerived3::MDerived3() noexcept = default;
+
+MDerived4::MDerived4() noexcept = default;
+
+MDerived5::MDerived5() noexcept = default;
+
+MDerived1 *MDerived1::transformFromBase1(Base1 *self)
+{
+ return dynamic_cast<MDerived1*>(self);
+}
+
+MDerived1 *MDerived1::transformFromBase2(Base2 *self)
+{
+ return dynamic_cast<MDerived1*>(self);
+}
diff --git a/sources/shiboken6/tests/libsample/multiple_derived.h b/sources/shiboken6/tests/libsample/multiple_derived.h
new file mode 100644
index 000000000..8c2143ed6
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/multiple_derived.h
@@ -0,0 +1,202 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MDERIVED_H
+#define MDERIVED_H
+
+#include "libsamplemacros.h"
+
+#include <string>
+
+class Base1
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Base1)
+
+ Base1() noexcept = default;
+ virtual ~Base1() = default;
+
+ virtual int base1Method() { return m_value; }
+
+ virtual void publicMethod() {};
+
+private:
+ int m_value = 1;
+};
+
+class Base2
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Base2)
+
+ Base2() noexcept = default;
+ virtual ~Base2() = default;
+ virtual int base2Method() { return m_value; }
+
+private:
+ int m_value = 2;
+};
+
+class LIBSAMPLE_API MDerived1 : public Base1, public Base2
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(MDerived1)
+
+ MDerived1() noexcept;
+ ~MDerived1() override = default;
+
+ int mderived1Method() { return m_value; }
+ int base1Method () override { return Base1::base1Method() * 10; }
+ int base2Method() override { return Base2::base2Method() * 10; }
+
+ inline Base1 *castToBase1() { return (Base1*) this; }
+ inline Base2 *castToBase2() { return (Base2*) this; }
+
+ static MDerived1 *transformFromBase1(Base1 *self);
+ static MDerived1 *transformFromBase2(Base2 *self);
+
+private:
+ void publicMethod() override {}
+ int m_value = 100;
+};
+
+class SonOfMDerived1 : public MDerived1
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(SonOfMDerived1)
+
+ SonOfMDerived1() noexcept = default;
+ ~SonOfMDerived1() = default;
+
+ inline MDerived1 *castToMDerived1() { return this; }
+
+ int sonOfMDerived1Method() { return m_value; }
+
+private:
+ int m_value = 0;
+};
+
+class Base3
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Base3)
+
+ explicit Base3(int val = 3) noexcept : m_value(val) {}
+ virtual ~Base3() = default;
+ int base3Method() { return m_value; }
+
+private:
+ int m_value;
+};
+
+class Base4
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Base4)
+
+ Base4() noexcept = default;
+ virtual ~Base4() = default;
+ int base4Method() { return m_value; }
+
+private:
+ int m_value = 4;
+};
+
+class Base5
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Base5)
+
+ Base5() noexcept = default;
+ virtual ~Base5() = default;
+ virtual int base5Method() { return m_value; }
+
+private:
+ int m_value = 5;
+};
+
+class Base6
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Base6)
+
+ Base6() noexcept = default;
+ virtual ~Base6() = default;
+ virtual int base6Method() { return m_value; }
+
+private:
+ int m_value = 6;
+};
+
+class LIBSAMPLE_API MDerived2 : public Base3, public Base4, public Base5, public Base6
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(MDerived2)
+
+ MDerived2() noexcept;
+ virtual ~MDerived2() = default;
+
+ inline int base4Method() { return Base3::base3Method() * 10; }
+ inline int mderived2Method() { return m_value; }
+
+ inline Base3 *castToBase3() { return this; }
+ inline Base4 *castToBase4() { return this; }
+ inline Base5 *castToBase5() { return this; }
+ inline Base6 *castToBase6() { return this; }
+
+private:
+ int m_value = 200;
+};
+
+class LIBSAMPLE_API MDerived3 : public MDerived1, public MDerived2
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(MDerived3)
+
+ MDerived3() noexcept;
+ virtual ~MDerived3() = default;
+
+ inline virtual int mderived3Method() { return m_value; }
+
+ inline MDerived1 *castToMDerived1() { return this; }
+ inline MDerived2 *castToMDerived2() { return this; }
+
+ inline Base3 *castToBase3() { return (Base3*) this; }
+
+private:
+ int m_value = 3000;
+};
+
+class LIBSAMPLE_API MDerived4 : public Base3, public Base4
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(MDerived4)
+
+ MDerived4() noexcept;
+ ~MDerived4() = default;
+
+ inline int mderived4Method() { return 0; }
+ inline int justDummyMethod() { return m_value; }
+
+ inline Base3 *castToBase3() { return this; }
+ inline Base4 *castToBase4() { return this; }
+
+private:
+ int m_value;
+};
+
+class LIBSAMPLE_API MDerived5 : public Base3, public Base4
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(MDerived5)
+
+ MDerived5() noexcept;
+ virtual ~MDerived5() = default;
+
+ virtual int mderived5Method() { return 0; }
+
+ inline Base3 *castToBase3() { return this; }
+ inline Base4 *castToBase4() { return this; }
+};
+
+#endif // MDERIVED_H
diff --git a/sources/shiboken6/tests/libsample/noimplicitconversion.h b/sources/shiboken6/tests/libsample/noimplicitconversion.h
new file mode 100644
index 000000000..a0b91380b
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/noimplicitconversion.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef NOIMPLICITCONVERSION_H
+#define NOIMPLICITCONVERSION_H
+
+#include "libsamplemacros.h"
+
+// This class must not have implicit conversions AND
+// no conversion operators should be defined in its own module.
+class NoImplicitConversion
+{
+public:
+ explicit NoImplicitConversion(int objId) : m_objId(objId) {}
+ inline int objId() const { return m_objId; }
+ inline static int receivesNoImplicitConversionByValue(NoImplicitConversion arg)
+ { return arg.m_objId; }
+ inline static int receivesNoImplicitConversionByPointer(NoImplicitConversion *arg)
+ { return arg->m_objId; }
+ inline static int receivesNoImplicitConversionByReference(NoImplicitConversion &arg)
+ { return arg.m_objId; }
+private:
+ int m_objId;
+};
+
+#endif // NOIMPLICITCONVERSION_H
+
diff --git a/sources/shiboken6/tests/libsample/nondefaultctor.h b/sources/shiboken6/tests/libsample/nondefaultctor.h
new file mode 100644
index 000000000..fa97b8859
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/nondefaultctor.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef NONDEFAULTCTOR_H
+#define NONDEFAULTCTOR_H
+
+#include "libsamplemacros.h"
+
+class NonDefaultCtor
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(NonDefaultCtor)
+
+ explicit NonDefaultCtor(int value) noexcept : m_value(value)
+ {
+ }
+
+ virtual ~NonDefaultCtor() = default;
+
+ inline int value() const
+ {
+ return m_value;
+ }
+
+ inline NonDefaultCtor returnMyself()
+ {
+ return *this;
+ }
+
+ inline NonDefaultCtor returnMyself(int)
+ {
+ return *this;
+ }
+
+ inline NonDefaultCtor returnMyself(int, NonDefaultCtor)
+ {
+ return *this;
+ }
+
+ virtual NonDefaultCtor returnMyselfVirtual()
+ {
+ return *this;
+ }
+
+ inline NonDefaultCtor callReturnMyselfVirtual()
+ {
+ return returnMyselfVirtual();
+ }
+
+private:
+ int m_value;
+};
+
+#endif // NONDEFAULTCTOR_H
diff --git a/sources/shiboken6/tests/libsample/nontypetemplate.h b/sources/shiboken6/tests/libsample/nontypetemplate.h
new file mode 100644
index 000000000..e41c21604
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/nontypetemplate.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef NONTYPETEMPLATE_H
+#define NONTYPETEMPLATE_H
+
+#include "libsamplemacros.h"
+
+#include <algorithm>
+#include <numeric>
+
+template <int Size> class IntArray
+{
+public:
+ explicit IntArray(const int *data) { std::copy(data, data + Size, m_array); }
+ explicit IntArray(int v) { std::fill(m_array, m_array + Size, v); }
+
+ int sum() const { return std::accumulate(m_array, m_array + Size, int(0)); }
+
+private:
+ int m_array[Size];
+};
+
+using IntArray2 = IntArray<2>;
+using IntArray3 = IntArray<3>;
+
+#endif // NONTYPETEMPLATE_H
diff --git a/sources/shiboken6/tests/libsample/null.h b/sources/shiboken6/tests/libsample/null.h
new file mode 100644
index 000000000..945a89fa2
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/null.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef NULL_H
+#define NULL_H
+
+class Null
+{
+public:
+ Null(bool value) : m_isNull(value) {}
+ Null() = default;
+
+ void setIsNull(bool flag) { m_isNull = flag; }
+
+private:
+ bool m_isNull = false;
+};
+
+#endif // NULL_H
diff --git a/sources/shiboken6/tests/libsample/objectmodel.cpp b/sources/shiboken6/tests/libsample/objectmodel.cpp
new file mode 100644
index 000000000..56ed86577
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objectmodel.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "objectmodel.h"
+
+void ObjectModel::setData(ObjectType *data)
+{
+ m_data = data;
+}
+
+ObjectType *ObjectModel::data() const
+{
+ return m_data;
+}
+
+ObjectModel::MethodCalled ObjectModel::receivesObjectTypeFamily(const ObjectModel &)
+{
+ return ObjectModel::ObjectModelCalled;
+}
+
+ObjectModel::MethodCalled ObjectModel::receivesObjectTypeFamily(const ObjectType &)
+{
+ return ObjectModel::ObjectTypeCalled;
+}
diff --git a/sources/shiboken6/tests/libsample/objectmodel.h b/sources/shiboken6/tests/libsample/objectmodel.h
new file mode 100644
index 000000000..6d2f97aee
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objectmodel.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OBJECTMODEL_H
+#define OBJECTMODEL_H
+
+#include "objecttype.h"
+#include "libsamplemacros.h"
+
+class LIBSAMPLE_API ObjectModel : public ObjectType
+{
+public:
+ explicit ObjectModel(ObjectType *parent = nullptr)
+ : ObjectType(parent) {}
+
+ void setData(ObjectType *data);
+ virtual ObjectType *data() const;
+
+ // The MethodCalled enum and related static methods were created to
+ // test bug #630 [http://bugs.openbossa.org/show_bug.cgi?id=630]
+ enum MethodCalled { ObjectTypeCalled, ObjectModelCalled };
+ static MethodCalled receivesObjectTypeFamily(const ObjectType &object);
+ static MethodCalled receivesObjectTypeFamily(const ObjectModel &object);
+
+private:
+ // The model holds only one piece of data.
+ // (This is just a test after all.)
+ ObjectType *m_data = nullptr;
+};
+
+#endif // OBJECTMODEL_H
diff --git a/sources/shiboken6/tests/libsample/objecttype.cpp b/sources/shiboken6/tests/libsample/objecttype.cpp
new file mode 100644
index 000000000..fa3e7357c
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objecttype.cpp
@@ -0,0 +1,264 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "objecttype.h"
+#include "objecttypelayout.h"
+
+#include <algorithm>
+#include <iostream>
+#include <string>
+#include <assert.h>
+
+ObjectType::ObjectType(ObjectType *parent)
+{
+ setParent(parent);
+}
+
+ObjectType::ObjectType(ObjectType &&) noexcept = default;
+ObjectType &ObjectType::operator=(ObjectType &&) noexcept = default;
+
+ObjectType::~ObjectType()
+{
+ for (auto *o : m_children)
+ delete o;
+}
+
+ObjectType *ObjectType::createWithChild()
+{
+ ObjectType *parent = create();
+ ObjectType *child = create();
+ child->setObjectName("child");
+ child->setParent(parent);
+ return parent;
+}
+
+void ObjectType::removeChild(ObjectType *child)
+{
+ if (!child)
+ return;
+
+ auto child_iter = std::find(m_children.begin(), m_children.end(), child);
+ if (child_iter != m_children.end()) {
+ m_children.erase(child_iter);
+ child->m_parent = nullptr;
+ }
+}
+
+ObjectType *ObjectType::takeChild(ObjectType *child)
+{
+ if (!child)
+ return nullptr;
+
+ auto child_iter = std::find(m_children.begin(), m_children.end(), child);
+ if (child_iter != m_children.end()) {
+ m_children.erase(child_iter);
+ child->m_parent = nullptr;
+ return child;
+ }
+ return nullptr;
+}
+
+ObjectType *ObjectType::takeChild(const Str &name)
+{
+ return takeChild(findChild(name));
+
+}
+
+ObjectTypeList::iterator ObjectType::findChildByName(const Str &name)
+{
+ return std::find_if(m_children.begin(), m_children.end(),
+ [&name](const ObjectType *o) {
+ return o->objectName() == name;
+ });
+}
+
+ObjectType *ObjectType::findChild(const Str &name)
+{
+ auto it = findChildByName(name);
+ return it != m_children.end() ? *it : nullptr;
+}
+
+void ObjectType::killChild(const Str &name)
+{
+ auto it = findChildByName(name);
+ if (it != m_children.end()) {
+ ObjectType *child = *it;
+ removeChild(child);
+ delete child;
+ }
+}
+
+void ObjectType::setParent(ObjectType *parent)
+{
+ if (m_parent == parent)
+ return;
+
+ if (m_parent)
+ m_parent->removeChild(this);
+
+ m_parent = parent;
+ if (m_parent)
+ m_parent->m_children.push_back(this);
+}
+
+void ObjectType::setObjectName(const Str &name)
+{
+ m_objectName = name;
+}
+
+Str ObjectType::objectName() const
+{
+ return m_objectName;
+}
+
+bool ObjectType::causeEvent(Event::EventType eventType)
+{
+ Event e(eventType);
+ return event(&e);
+}
+
+bool ObjectType::event(Event *)
+{
+ return true;
+}
+
+int ObjectType::processEvent(ObjectTypeList objects, Event *event)
+{
+ return std::count_if(objects.begin(), objects.end(),
+ [event] (ObjectType *o) {
+ return o->event(event);
+ });
+}
+
+void ObjectType::callInvalidateEvent(Event *event)
+{
+ invalidateEvent(event);
+}
+
+void ObjectType::invalidateEvent(Event *)
+{
+}
+
+void ObjectType::setLayout(ObjectTypeLayout *l)
+{
+ if (!l) {
+ std::cerr << "[WARNING] ObjectType::setLayout: Cannot set layout to 0.\n";
+ return;
+ }
+
+ if (layout()) {
+ if (layout() != l) {
+ std::cerr << "[WARNING] ObjectType::setLayout: Attempting to set ObjectTypeLayout '"
+ << l->objectName().cstring()
+ << "' on ObjectType '" << objectName().cstring()
+ << "', which already has a layout.\n";
+ }
+ return;
+ }
+
+ ObjectType *oldParent = l->parent();
+ if (oldParent && oldParent != this) {
+ if (oldParent->isLayoutType()) {
+ std::cerr << "[WARNING] ObjectType::setLayout: Attempting to set ObjectTypeLayout '"
+ << l->objectName().cstring()
+ << "' on ObjectType '" << objectName().cstring()
+ << "', when the ObjectTypeLayout already has a parent layout.\n";
+ return;
+ }
+ // Steal the layout from an ObjectType parent.
+ oldParent->takeLayout();
+ }
+
+ m_layout = l;
+ if (oldParent != this) {
+ l->setParent(this);
+ l->reparentChildren(this);
+ }
+}
+
+ObjectTypeLayout *ObjectType::takeLayout()
+{
+ ObjectTypeLayout *l = layout();
+ if (!l)
+ return nullptr;
+ m_layout = nullptr;
+ l->setParent(nullptr);
+ return l;
+}
+
+unsigned int objectTypeHash(const ObjectType *objectType)
+{
+ return reinterpret_cast<std::size_t>(objectType);
+}
+
+unsigned char ObjectType::callWithEnum(const Str &, Event::EventType, unsigned char value)
+{
+ return value * value;
+}
+
+unsigned char ObjectType::callWithEnum(const Str &, unsigned char value)
+{
+ return value;
+}
+
+void ObjectType::setObjectSplittedName(const char *, const Str &prefix, const Str &suffix)
+{
+ std::string result(prefix.cstring());
+ result += suffix.cstring();
+ m_objectName = result.c_str();
+}
+
+void ObjectType::setObjectNameWithSize(const char *, int size, const Str &name)
+{
+ std::string result(name.cstring(), size);
+ m_objectName = result.c_str();
+}
+
+void ObjectType::setObjectNameWithSize(const Str &name, int size)
+{
+ setObjectNameWithSize("", size, name);
+}
+
+void ObjectType::setObject(ObjectType *)
+{
+ m_call_id = 0;
+}
+
+void ObjectType::setObject(const Null&)
+{
+ m_call_id = 1;
+}
+
+int ObjectType::callId() const
+{
+ return m_call_id;
+}
+
+void ObjectType::callVirtualCreateChild()
+{
+ auto *fake_parent = new ObjectType();
+ ObjectType *fake_child = createChild(fake_parent);
+ assert(fake_child->isPython());
+ (void)fake_child;
+ delete fake_parent;
+}
+
+ObjectType *ObjectType::createChild(ObjectType *parent)
+{
+ return new ObjectType(parent);
+}
+
+std::size_t ObjectType::createObjectType()
+{
+ void *addr = new ObjectType();
+ return (std::size_t) addr;
+}
+
+OtherBase::~OtherBase() = default;
+
+ObjectTypeDerived::~ObjectTypeDerived() = default;
+
+bool ObjectTypeDerived::event(Event *)
+{
+ return true;
+}
diff --git a/sources/shiboken6/tests/libsample/objecttype.h b/sources/shiboken6/tests/libsample/objecttype.h
new file mode 100644
index 000000000..498556459
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objecttype.h
@@ -0,0 +1,166 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OBJECTTYPE_H
+#define OBJECTTYPE_H
+
+#include "str.h"
+#include "null.h"
+
+#include "libsamplemacros.h"
+
+#include <list>
+
+struct Event
+{
+ enum EventType {
+ NO_EVENT,
+ BASIC_EVENT,
+ SOME_EVENT,
+ ANY_EVENT
+ };
+
+ enum class EventTypeClass {
+ Value1,
+ Value2
+ };
+
+ explicit Event(EventType eventType) : m_eventType(eventType) {}
+ EventType eventType() const { return m_eventType; }
+
+ void setEventType(EventType et) { m_eventType = et; }
+ void setEventTypeByConstRef(const EventType &et) { m_eventType = et; }
+ void setEventTypeByConstPtr(const EventType *etPtr) { m_eventType = *etPtr; }
+
+private:
+ EventType m_eventType;
+};
+
+class ObjectTypeLayout;
+class ObjectType;
+using ObjectTypeList = std::list<ObjectType*>;
+
+class LIBSAMPLE_API ObjectType
+{
+public:
+ // ### Fixme: Use uintptr_t in C++ 11
+ using Identifier = size_t;
+
+ explicit ObjectType(ObjectType *parent = nullptr);
+ virtual ~ObjectType();
+ ObjectType(const ObjectType &) = delete;
+ ObjectType &operator=(const ObjectType &) = delete;
+ ObjectType(ObjectType &&) noexcept;
+ ObjectType &operator=(ObjectType &&) noexcept;
+
+ // factory method
+ inline static ObjectType *create() { return new ObjectType(); }
+ static ObjectType *createWithChild();
+
+ void setParent(ObjectType *parent);
+ inline ObjectType *parent() const { return m_parent; }
+ inline const ObjectTypeList &children() const { return m_children; }
+ void killChild(const Str &name);
+ void removeChild(ObjectType *child);
+ ObjectType *takeChild(ObjectType *child);
+ virtual ObjectType *takeChild(const Str &name);
+ ObjectType *findChild(const Str &name);
+
+ Str objectName() const;
+ void setObjectName(const Str &name);
+
+ inline Identifier identifier() const { return reinterpret_cast<Identifier>(this); }
+
+ bool causeEvent(Event::EventType eventType);
+
+ // Returns true if the event is processed.
+ virtual bool event(Event *event);
+ static int processEvent(ObjectTypeList objects, Event *event);
+
+ void callInvalidateEvent(Event *event);
+ virtual void invalidateEvent(Event *event);
+
+ // This nonsense method emulate QWidget.setLayout method
+ // All layout objects will became children of this object.
+ void setLayout(ObjectTypeLayout *layout);
+ inline ObjectTypeLayout *layout() const { return m_layout; }
+
+ // This method should be reimplemented by ObjectTypeLayout.
+ virtual bool isLayoutType() { return false; }
+
+ unsigned char callWithEnum(const Str &prefix, Event::EventType type,
+ unsigned char value=80);
+ unsigned char callWithEnum(const Str &prefix, unsigned char value=0);
+
+ //Functions used in test with named arguments
+ void setObjectSplittedName(const char *, const Str &prefix = Str("<unk"),
+ const Str &suffix = Str("nown>"));
+ void setObjectNameWithSize(const char *, int size=9,
+ const Str &name = Str("<unknown>"));
+ void setObjectNameWithSize(const Str &name = Str("<unknown>"), int size = 9);
+
+ //Function used to confuse the generator when two values accept Null as arg
+ void setObject(ObjectType *);
+ void setObject(const Null &);
+ int callId() const;
+
+ //Function used to create a parent from C++
+ virtual bool isPython() { return false; }
+ void callVirtualCreateChild();
+ virtual ObjectType *createChild(ObjectType *parent);
+ static std::size_t createObjectType();
+
+ //return a parent from C++
+ ObjectType *getCppParent() {
+ if (!m_parent) {
+ ObjectType *parent = new ObjectType();
+ setParent(parent);
+ }
+ return m_parent;
+ }
+
+ void destroyCppParent() {
+ delete m_parent;
+ }
+
+ //Deprecated test
+ bool deprecatedFunction() { return true; }
+
+ // nextInFocusChain simply returns the parent to test object cycles; the parent
+ // may be returned by the QWidget's implementation but isn't always returned
+ ObjectType *nextInFocusChain() { return m_parent; }
+
+private:
+ ObjectTypeLayout *takeLayout();
+ ObjectTypeList::iterator findChildByName(const Str &name);
+
+ Str m_objectName;
+ ObjectType *m_parent = nullptr;
+ ObjectTypeList m_children;
+
+ ObjectTypeLayout *m_layout = nullptr;
+ //used on overload null test
+ int m_call_id = -1;
+};
+
+LIBSAMPLE_API unsigned int objectTypeHash(const ObjectType *objectType);
+
+class LIBSAMPLE_API OtherBase {
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(OtherBase)
+
+ OtherBase() noexcept = default;
+ virtual ~OtherBase();
+};
+
+class LIBSAMPLE_API ObjectTypeDerived: public ObjectType, public OtherBase {
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(ObjectTypeDerived)
+
+ ObjectTypeDerived() noexcept = default;
+
+ bool event(Event *event) override;
+ ~ObjectTypeDerived() override;
+};
+
+#endif // OBJECTTYPE_H
diff --git a/sources/shiboken6/tests/libsample/objecttypebyvalue.h b/sources/shiboken6/tests/libsample/objecttypebyvalue.h
new file mode 100644
index 000000000..7b12ff945
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objecttypebyvalue.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OBJECTTYPEBYVALUE_H
+#define OBJECTTYPEBYVALUE_H
+
+#include "protected.h"
+
+#include <list>
+
+class ObjectTypeByValue
+{
+public:
+ ObjectTypeByValue returnSomeKindOfMe() { return {}; }
+ void acceptKindOfMeAsValue(ObjectTypeByValue kindOfMe);
+
+ void acceptListOfObjectTypeByValue(std::list<ObjectTypeByValue> listOfMe);
+
+ // prop used to check for segfaults
+ ProtectedProperty prop;
+};
+
+inline void ObjectTypeByValue::acceptKindOfMeAsValue(ObjectTypeByValue)
+{
+}
+
+inline void ObjectTypeByValue::acceptListOfObjectTypeByValue(std::list<ObjectTypeByValue>)
+{
+}
+
+#endif // OBJECTTYPEBYVALUE_H
diff --git a/sources/shiboken6/tests/libsample/objecttypeholder.cpp b/sources/shiboken6/tests/libsample/objecttypeholder.cpp
new file mode 100644
index 000000000..c0950d09c
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objecttypeholder.cpp
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "objecttypeholder.h"
+
+ObjectTypeHolder::ObjectTypeHolder(const char *objectName)
+{
+ auto *object = new ObjectType();
+ object->setObjectName(objectName);
+ m_objectType = object;
+}
+
+ObjectTypeHolder::ObjectTypeHolder(const ObjectType *object) noexcept :
+ m_objectType(object)
+{
+}
+
+ObjectTypeHolder::~ObjectTypeHolder()
+{
+ delete m_objectType;
+}
+
+Str ObjectTypeHolder::passObjectTypeAsReference(const ObjectType &objectType)
+{
+ return objectType.objectName();
+}
+
+Str ObjectTypeHolder::callPassObjectTypeAsReference()
+{
+ return passObjectTypeAsReference(*m_objectType);
+}
diff --git a/sources/shiboken6/tests/libsample/objecttypeholder.h b/sources/shiboken6/tests/libsample/objecttypeholder.h
new file mode 100644
index 000000000..190664608
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objecttypeholder.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OBJECTTYPEHOLDER_H
+#define OBJECTTYPEHOLDER_H
+
+#include "libsamplemacros.h"
+#include "objecttype.h"
+#include "str.h"
+
+class LIBSAMPLE_API ObjectTypeHolder
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(ObjectTypeHolder)
+
+ explicit ObjectTypeHolder(const char *objectName);
+ explicit ObjectTypeHolder(const ObjectType *object) noexcept;
+ virtual ~ObjectTypeHolder();
+
+ const ObjectType *getObjectType() const { return m_objectType; }
+
+ virtual Str passObjectTypeAsReference(const ObjectType &objectType);
+ Str callPassObjectTypeAsReference();
+
+private:
+ const ObjectType *m_objectType;
+};
+
+#endif // OBJECTTYPEHOLDER_H
diff --git a/sources/shiboken6/tests/libsample/objecttypelayout.cpp b/sources/shiboken6/tests/libsample/objecttypelayout.cpp
new file mode 100644
index 000000000..3fa02917c
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objecttypelayout.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "objecttypelayout.h"
+
+#include <iostream>
+
+void ObjectTypeLayout::addObject(ObjectType *obj)
+{
+ if (obj->isLayoutType()) {
+ auto *l = reinterpret_cast<ObjectTypeLayout*>(obj);
+ if (l->parent()) {
+ std::cerr << "[WARNING] ObjectTypeLayout::addObject: layout '"
+ << l->objectName().cstring() << "' already has a parent.\n";
+ return;
+ }
+
+ l->setParent(this);
+
+ if (parent() && !parent()->isLayoutType())
+ l->reparentChildren(parent());
+ }
+
+ m_objects.push_back(obj);
+}
+
+std::list<ObjectType*> ObjectTypeLayout::objects() const
+{
+ return m_objects;
+}
+
+void ObjectTypeLayout::reparentChildren(ObjectType *parent)
+{
+ for (auto *o : m_objects) {
+ if (o->isLayoutType())
+ reinterpret_cast<ObjectTypeLayout *>(o)->reparentChildren(parent);
+ else
+ o->setParent(parent);
+ }
+}
diff --git a/sources/shiboken6/tests/libsample/objecttypelayout.h b/sources/shiboken6/tests/libsample/objecttypelayout.h
new file mode 100644
index 000000000..0aa9fad6e
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objecttypelayout.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OBJECTTYPELAYOUT_H
+#define OBJECTTYPELAYOUT_H
+
+#include "libsamplemacros.h"
+#include "objecttype.h"
+
+#include <list>
+
+class ObjectType;
+
+class LIBSAMPLE_API ObjectTypeLayout : public ObjectType
+{
+public:
+ void addObject(ObjectType *obj);
+ std::list<ObjectType*> objects() const;
+
+ bool isLayoutType() override { return true; }
+ inline static ObjectTypeLayout *create() { return new ObjectTypeLayout(); }
+
+ ObjectType *takeChild(const Str &name) override { return ObjectType::takeChild(name); }
+
+private:
+ std::list<ObjectType*> m_objects;
+
+ void reparentChildren(ObjectType *parent);
+ friend LIBSAMPLE_API void ObjectType::setLayout(ObjectTypeLayout *l);
+};
+
+#endif // OBJECTTYPELAYOUT_H
diff --git a/sources/shiboken6/tests/libsample/objecttypeoperators.cpp b/sources/shiboken6/tests/libsample/objecttypeoperators.cpp
new file mode 100644
index 000000000..c78387a3e
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objecttypeoperators.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "objecttypeoperators.h"
+
+ObjectTypeOperators::ObjectTypeOperators(const std::string key) : m_key(key)
+{
+}
+
+bool ObjectTypeOperators::operator==(const ObjectTypeOperators &other) const
+{
+ return m_key == other.m_key;
+}
+
+const ObjectTypeOperators &ObjectTypeOperators::operator<(const ObjectTypeOperators &other) const
+{
+ return m_key < other.m_key ? *this : other;
+}
+
+bool operator==(const ObjectTypeOperators *obj, const std::string &str)
+{
+ return obj->key() == str;
+}
+
+bool operator==(const std::string &str, const ObjectTypeOperators *obj)
+{
+ return str == obj->key();
+}
+
+std::string operator+(const ObjectTypeOperators *obj, const std::string &str)
+{
+ return obj->key() + str;
+}
+
+std::string operator+(const std::string &str, const ObjectTypeOperators *obj)
+{
+ return str + obj->key();
+}
diff --git a/sources/shiboken6/tests/libsample/objecttypeoperators.h b/sources/shiboken6/tests/libsample/objecttypeoperators.h
new file mode 100644
index 000000000..6144952ca
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objecttypeoperators.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OBJECTTYPEOPERATORS_H
+#define OBJECTTYPEOPERATORS_H
+
+#include "libsamplemacros.h"
+
+#include <string>
+
+class LIBSAMPLE_API ObjectTypeOperators
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(ObjectTypeOperators)
+
+ explicit ObjectTypeOperators(const std::string key);
+ virtual ~ObjectTypeOperators() = default;
+
+ bool operator==(const ObjectTypeOperators &other) const;
+ const ObjectTypeOperators &operator<(const ObjectTypeOperators &other) const;
+
+ // chaos!
+ virtual void operator>(const ObjectTypeOperators &) { m_key.append("operator>"); }
+
+ std::string key() const { return m_key; }
+
+private:
+ std::string m_key;
+};
+
+LIBSAMPLE_API bool operator==(const ObjectTypeOperators *obj, const std::string &str);
+LIBSAMPLE_API bool operator==(const std::string &str, const ObjectTypeOperators *obj);
+LIBSAMPLE_API std::string operator+(const ObjectTypeOperators *obj, const std::string &str);
+LIBSAMPLE_API std::string operator+(const std::string &str, const ObjectTypeOperators *obj);
+
+#endif // OBJECTTYPEOPERATORS_H
diff --git a/sources/shiboken6/tests/libsample/objectview.cpp b/sources/shiboken6/tests/libsample/objectview.cpp
new file mode 100644
index 000000000..1b727f88c
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objectview.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "objectview.h"
+#include "objectmodel.h"
+#include "str.h"
+
+Str ObjectView::displayModelData()
+{
+ if (!m_model)
+ return {"(NULL)"};
+ return Str("Name: %VAR").arg(m_model->objectName());
+}
+
+void ObjectView::modifyModelData(Str &data)
+{
+ if (m_model)
+ m_model->setObjectName(data);
+}
+
+ObjectType *ObjectView::getRawModelData()
+{
+ return m_model->data();
+}
diff --git a/sources/shiboken6/tests/libsample/objectview.h b/sources/shiboken6/tests/libsample/objectview.h
new file mode 100644
index 000000000..2567deee5
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/objectview.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OBJECTVIEW_H
+#define OBJECTVIEW_H
+
+#include "objecttype.h"
+#include "libsamplemacros.h"
+
+class Str;
+class ObjectModel;
+
+class LIBSAMPLE_API ObjectView : public ObjectType
+{
+public:
+ explicit ObjectView(ObjectModel *model = nullptr, ObjectType *parent = nullptr)
+ : ObjectType(parent), m_model(model) {}
+
+ inline void setModel(ObjectModel *model) { m_model = model; }
+ inline ObjectModel *model() const { return m_model; }
+
+ Str displayModelData();
+ void modifyModelData(Str &data);
+
+ ObjectType *getRawModelData();
+
+private:
+ ObjectModel *m_model;
+};
+
+#endif // OBJECTVIEW_H
diff --git a/sources/shiboken6/tests/libsample/oddbool.cpp b/sources/shiboken6/tests/libsample/oddbool.cpp
new file mode 100644
index 000000000..bc1ee833f
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/oddbool.cpp
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "oddbool.h"
+
+ComparisonTester::ComparisonTester(int v) : m_value(v)
+{
+}
+
+ComparisonTester &ComparisonTester::operator=(int v)
+{
+ m_value = v;
+ return *this;
+}
+
+int ComparisonTester::compare(const ComparisonTester &rhs) const
+{
+ if (m_value < rhs.m_value)
+ return -1;
+ if (m_value > rhs.m_value)
+ return 1;
+ return 0;
+}
+
+SpaceshipComparisonTester::SpaceshipComparisonTester(int v) : m_value(v)
+{
+}
diff --git a/sources/shiboken6/tests/libsample/oddbool.h b/sources/shiboken6/tests/libsample/oddbool.h
new file mode 100644
index 000000000..dd2d32604
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/oddbool.h
@@ -0,0 +1,106 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ODDBOOL_H
+#define ODDBOOL_H
+
+#include "libsamplemacros.h"
+
+#include <type_traits>
+
+#if __cplusplus >= 202002 || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002)
+# include <compare>
+#endif
+
+class OddBool
+{
+
+public:
+ inline explicit OddBool(bool b) noexcept : m_value(b) {}
+ bool value() const { return m_value; }
+
+ inline OddBool operator!() const { return OddBool(!m_value); }
+
+private:
+ bool m_value;
+};
+
+inline bool operator==(OddBool b1, bool b2) { return (!b1).value() == !b2; }
+inline bool operator==(bool b1, OddBool b2) { return (!b1) == (!b2).value(); }
+inline bool operator==(OddBool b1, OddBool b2) { return (!b1).value() == (!b2).value(); }
+inline bool operator!=(OddBool b1, bool b2) { return (!b1).value() != !b2; }
+inline bool operator!=(bool b1, OddBool b2) { return (!b1) != (!b2).value(); }
+inline bool operator!=(OddBool b1, OddBool b2) { return (!b1).value() != (!b2).value(); }
+
+class OddBoolUser
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(OddBoolUser)
+
+ OddBoolUser() noexcept : m_oddbool(OddBool(false)) {}
+ OddBoolUser(const OddBool &oddBool) : m_oddbool(oddBool) {}
+ virtual ~OddBoolUser() = default;
+
+ inline OddBool oddBool() { return m_oddbool; }
+ inline void setOddBool(OddBool oddBool) { m_oddbool = oddBool; }
+
+ virtual OddBool invertedOddBool()
+ {
+ return !m_oddbool;
+ }
+
+ inline OddBool callInvertedOddBool()
+ {
+ return invertedOddBool();
+ }
+
+ static inline OddBool getOddBool(const OddBoolUser &oddBoolUser)
+ {
+ return oddBoolUser.m_oddbool;
+ }
+
+private:
+ OddBool m_oddbool;
+};
+
+class LIBSAMPLE_API ComparisonTester
+{
+public:
+ explicit ComparisonTester(int v);
+ ComparisonTester &operator=(int v);
+
+ int compare(const ComparisonTester &rhs) const;
+
+private:
+ int m_value;
+};
+
+// Hide the comparison operators from the clang parser (see typesystem_sample.xml:184,
+// oddbool_test.py)
+
+inline std::enable_if<std::is_assignable<ComparisonTester, int>::value, bool>::type
+ operator==(const ComparisonTester &c1, const ComparisonTester &c2)
+{ return c1.compare(c2) == 0; }
+
+inline std::enable_if<std::is_assignable<ComparisonTester, int>::value, bool>::type
+ operator!=(const ComparisonTester &c1, const ComparisonTester &c2)
+{ return c1.compare(c2) != 0; }
+
+class LIBSAMPLE_API SpaceshipComparisonTester
+{
+public:
+ explicit SpaceshipComparisonTester(int v);
+
+#if __cplusplus >= 202002 || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002)
+ auto operator<=>(const SpaceshipComparisonTester &rhs) const = default;
+
+ enum Enabled { HasSpaceshipOperator = 1 };
+#else
+ enum Enabled { HasSpaceshipOperator = 0 };
+#endif // C++ 20
+
+private:
+ int m_value;
+};
+
+#endif // ODDBOOL_H
diff --git a/sources/shiboken6/tests/libsample/onlycopy.cpp b/sources/shiboken6/tests/libsample/onlycopy.cpp
new file mode 100644
index 000000000..981ea88a4
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/onlycopy.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "onlycopy.h"
+
+class OnlyCopyPrivate
+{
+public:
+ explicit OnlyCopyPrivate(int v = 0) : value(v) {}
+
+ int value;
+};
+
+OnlyCopy::OnlyCopy(int value) : d(std::make_shared<OnlyCopyPrivate>(value))
+{
+}
+
+OnlyCopy::~OnlyCopy() = default;
+
+int OnlyCopy::value() const
+{
+ return d->value;
+}
+
+OnlyCopy FriendOfOnlyCopy::createOnlyCopy(int value)
+{
+ return OnlyCopy(value);
+}
+
+std::list<OnlyCopy> FriendOfOnlyCopy::createListOfOnlyCopy(int quantity)
+{
+ std::list<OnlyCopy> list;
+ for (int i = 0; i < quantity; ++i)
+ list.push_back(createOnlyCopy(i));
+ return list;
+}
diff --git a/sources/shiboken6/tests/libsample/onlycopy.h b/sources/shiboken6/tests/libsample/onlycopy.h
new file mode 100644
index 000000000..7dc3e0069
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/onlycopy.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ONLYCOPYCLASS_H
+#define ONLYCOPYCLASS_H
+
+#include "libsamplemacros.h"
+
+#include <list>
+#include <memory>
+
+// These classes simulate a situation found in QWebEngineHistoryItem.
+
+class OnlyCopyPrivate;
+
+class LIBSAMPLE_API OnlyCopy
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(OnlyCopy)
+
+ ~OnlyCopy();
+
+ int value() const;
+ static int getValue(OnlyCopy onlyCopy) { return onlyCopy.value(); }
+ static int getValueFromReference(const OnlyCopy &onlyCopy) { return onlyCopy.value(); }
+
+private:
+ friend class FriendOfOnlyCopy;
+
+ explicit OnlyCopy(int value);
+
+ std::shared_ptr<OnlyCopyPrivate> d;
+};
+
+class LIBSAMPLE_API FriendOfOnlyCopy
+{
+public:
+ static OnlyCopy createOnlyCopy(int value);
+ static std::list<OnlyCopy> createListOfOnlyCopy(int quantity);
+};
+
+#endif // ONLYCOPYCLASS_H
diff --git a/sources/shiboken6/tests/libsample/overload.cpp b/sources/shiboken6/tests/libsample/overload.cpp
new file mode 100644
index 000000000..34da28e03
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/overload.cpp
@@ -0,0 +1,203 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "overload.h"
+
+Overload::FunctionEnum Overload::overloaded()
+{
+ return Function0;
+}
+
+Overload::FunctionEnum Overload::overloaded(Size *)
+{
+ return Function1;
+}
+
+Overload::FunctionEnum Overload::overloaded(Point *, ParamEnum)
+{
+ return Function2;
+}
+
+Overload::FunctionEnum Overload::overloaded(const Point &)
+{
+ return Function3;
+}
+
+void Overload::differentReturnTypes(ParamEnum)
+{
+
+}
+
+int Overload::differentReturnTypes(ParamEnum, int val)
+{
+ return val;
+}
+
+int Overload::intOverloads(const Point &, double)
+{
+ return 1;
+}
+
+int Overload::intOverloads(int, int)
+{
+ return 2;
+}
+
+int Overload::intOverloads(int, int, double)
+{
+ return 3;
+}
+
+Overload::FunctionEnum Overload::intDoubleOverloads(double, double) const
+{
+ return Function1;
+}
+
+Overload::FunctionEnum Overload::intDoubleOverloads(int, int) const
+{
+ return Function0;
+}
+
+void Overload::singleOverload(Point *)
+{
+}
+
+Overload::FunctionEnum Overload::wrapperIntIntOverloads(const Polygon &, int, int)
+{
+ return Function1;
+}
+
+Overload::FunctionEnum Overload::wrapperIntIntOverloads(const Point &, int, int)
+{
+ return Function0;
+}
+
+Overload::FunctionEnum Overload::strBufferOverloads(const Str &, const char *, bool)
+{
+ return Function0;
+}
+
+Overload::FunctionEnum Overload::strBufferOverloads(unsigned char *, int)
+{
+ return Function1;
+}
+
+Overload::FunctionEnum Overload::drawText(const PointF &, const Str &)
+{
+ return Function1;
+}
+
+Overload::FunctionEnum Overload::drawText(const Point &, const Str &)
+{
+ return Function0;
+}
+
+Overload::FunctionEnum Overload::drawText(const RectF &, const Str &, const Echo &)
+{
+ return Function4;
+}
+
+Overload::FunctionEnum Overload::drawText(const RectF &, int, const Str &)
+{
+ return Function3;
+}
+
+Overload::FunctionEnum Overload::drawText(const Rect &, int, const Str &)
+{
+ return Function2;
+}
+
+Overload::FunctionEnum Overload::drawText(int, int, const Str &)
+{
+ return Function5;
+}
+
+Overload::FunctionEnum Overload::drawText(int, int, int, int, int, const Str &)
+{
+ return Function6;
+}
+
+Overload::FunctionEnum Overload::drawText2(const PointF &, const Str &)
+{
+ return Function1;
+}
+
+Overload::FunctionEnum Overload::drawText2(const Point &, const Str &)
+{
+ return Function0;
+}
+
+Overload::FunctionEnum Overload::drawText2(int, int, const Str &)
+{
+ return Function5;
+}
+
+Overload::FunctionEnum Overload::drawText2(const RectF &, const Str &, const Echo &)
+{
+ return Function4;
+}
+
+Overload::FunctionEnum Overload::drawText2(const RectF &, int, const Str &)
+{
+ return Function3;
+}
+
+Overload::FunctionEnum Overload::drawText2(const Rect &, int, const Str &)
+{
+ return Function2;
+}
+
+Overload::FunctionEnum Overload::drawText2(int, int, int, int, int, const Str &)
+{
+ return Function6;
+}
+
+Overload::FunctionEnum Overload::drawText3(const Str &, const Str &, const Str &)
+{
+ return Function0;
+}
+
+Overload::FunctionEnum Overload::drawText3(int, int, int, int, int)
+{
+ return Function1;
+}
+
+Overload::FunctionEnum Overload::drawText4(int, int, int)
+{
+ return Function0;
+}
+
+Overload::FunctionEnum Overload::drawText4(int, int, int, int, int)
+{
+ return Function1;
+}
+
+Overload::FunctionEnum Overload::acceptSequence()
+{
+ return Function0;
+}
+
+Overload::FunctionEnum Overload::acceptSequence(const Str &, ParamEnum)
+{
+ return Function2;
+}
+
+Overload::FunctionEnum Overload::acceptSequence(int, int)
+{
+ return Function1;
+}
+
+Overload::FunctionEnum Overload::acceptSequence(void *)
+{
+ return Function5;
+}
+
+Overload::FunctionEnum Overload::acceptSequence(const char *const[])
+{
+ return Function4;
+}
+
+Overload::FunctionEnum Overload::acceptSequence(const Size &)
+{
+ return Function3;
+}
diff --git a/sources/shiboken6/tests/libsample/overload.h b/sources/shiboken6/tests/libsample/overload.h
new file mode 100644
index 000000000..b640bf7c7
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/overload.h
@@ -0,0 +1,121 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OVERLOAD_H
+#define OVERLOAD_H
+
+#include "echo.h"
+#include "str.h"
+#include "size.h"
+#include "point.h"
+#include "pointf.h"
+#include "polygon.h"
+#include "rect.h"
+
+#include "libsamplemacros.h"
+
+class LIBSAMPLE_API Overload
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(Overload)
+
+ enum FunctionEnum {
+ Function0,
+ Function1,
+ Function2,
+ Function3,
+ Function4,
+ Function5,
+ Function6
+ };
+
+ enum ParamEnum {
+ Param0,
+ Param1
+ };
+
+ Overload() noexcept = default;
+ virtual ~Overload() = default;
+
+ FunctionEnum overloaded();
+ FunctionEnum overloaded(Size *size);
+ FunctionEnum overloaded(Point *point, ParamEnum param);
+ FunctionEnum overloaded(const Point &point);
+
+ void differentReturnTypes(ParamEnum param = Param0);
+ int differentReturnTypes(ParamEnum param, int val);
+
+ int intOverloads(const Point &p, double d);
+ int intOverloads(int i, int i2);
+ int intOverloads(int i, int removedArg, double d);
+
+ FunctionEnum intDoubleOverloads(int a0, int a1) const;
+ FunctionEnum intDoubleOverloads(double a0, double a1) const;
+
+ void singleOverload(Point *x);
+ Point *singleOverload() { return new Point(); }
+
+ // Similar to QImage::trueMatrix(QMatrix,int,int) and QImage::trueMatrix(QTransform,int,int)
+ FunctionEnum wrapperIntIntOverloads(const Point &arg0, int arg1, int arg2);
+ FunctionEnum wrapperIntIntOverloads(const Polygon &arg0, int arg1, int arg2);
+
+ // Similar to QImage constructor
+ FunctionEnum strBufferOverloads(const Str &arg0, const char *arg1 = nullptr,
+ bool arg2 = true);
+ FunctionEnum strBufferOverloads(unsigned char *arg0, int arg1);
+ FunctionEnum strBufferOverloads() { return Function2; }
+
+ // Similar to QPainter::drawText(...)
+ FunctionEnum drawText(const Point &a0, const Str &a1);
+ FunctionEnum drawText(const PointF &a0, const Str &a1);
+ FunctionEnum drawText(const Rect &a0, int a1, const Str &a2);
+ FunctionEnum drawText(const RectF &a0, int a1, const Str &a2);
+ FunctionEnum drawText(const RectF &a0, const Str &a1, const Echo &a2 = Echo());
+ FunctionEnum drawText(int a0, int a1, const Str &a2);
+ FunctionEnum drawText(int a0, int a1, int a2, int a3, int a4, const Str &a5);
+
+ // A variant of the one similar to QPainter::drawText(...)
+ FunctionEnum drawText2(const Point &a0, const Str &a1);
+ FunctionEnum drawText2(const PointF &a0, const Str &a1);
+ FunctionEnum drawText2(const Rect &a0, int a1, const Str &a2);
+ FunctionEnum drawText2(const RectF &a0, int a1, const Str &a2);
+ FunctionEnum drawText2(const RectF &a0, const Str &a1, const Echo &a2 = Echo());
+ FunctionEnum drawText2(int a0, int a1, const Str &a2);
+ FunctionEnum drawText2(int a0, int a1, int a2, int a3 = 0, int a4 = 0,
+ const Str &a5 = Str());
+
+ // A simpler variant of the one similar to QPainter::drawText(...)
+ FunctionEnum drawText3(const Str &a0, const Str &a1, const Str &a2);
+ FunctionEnum drawText3(int a0, int a1, int a2, int a3, int a4);
+
+ // Another simpler variant of the one similar to QPainter::drawText(...)
+ FunctionEnum drawText4(int a0, int a1, int a2);
+ FunctionEnum drawText4(int a0, int a1, int a2, int a3, int a4);
+
+ FunctionEnum acceptSequence();
+ FunctionEnum acceptSequence(int a0, int a1);
+ FunctionEnum acceptSequence(const Str &a0, ParamEnum a1 = Param0);
+ FunctionEnum acceptSequence(const Size &a0);
+ // The type must be changed to PySequence.
+ FunctionEnum acceptSequence(const char *const a0[]);
+ FunctionEnum acceptSequence(void *a0);
+};
+
+class LIBSAMPLE_API Overload2 : public Overload
+{
+public:
+ // test bug#616, public and private method differ only by const
+ void doNothingInPublic() const {}
+ void doNothingInPublic(int) {}
+ virtual void doNothingInPublic3() const {}
+ void doNothingInPublic3(int) const {}
+protected:
+ void doNothingInPublic2() const {}
+ void doNothingInPublic2(int) {}
+private:
+ void doNothingInPublic() {}
+ void doNothingInPublic2() {}
+ void doNothingInPublic3() {}
+};
+
+#endif // OVERLOAD_H
diff --git a/sources/shiboken6/tests/libsample/overloadsort.cpp b/sources/shiboken6/tests/libsample/overloadsort.cpp
new file mode 100644
index 000000000..a9b4b0972
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/overloadsort.cpp
@@ -0,0 +1,49 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "overloadsort.h"
+
+const char *SortedOverload::overload(int)
+{
+ return "int";
+}
+
+const char *SortedOverload::overload(double)
+{
+ return "double";
+}
+
+const char *SortedOverload::overload(ImplicitBase)
+{
+ return "ImplicitBase";
+}
+
+const char *SortedOverload::overload(ImplicitTarget)
+{
+ return "ImplicitTarget";
+}
+
+const char *SortedOverload::overload(const std::list<ImplicitBase> &)
+{
+ return "list(ImplicitBase)";
+}
+
+int SortedOverload::implicit_overload(const ImplicitBase &)
+{
+ return 1;
+}
+
+const char *SortedOverload::overloadDeep(int, ImplicitBase &)
+{
+ return "ImplicitBase";
+}
+
+int CustomOverloadSequence::overload(short v) const
+{
+ return v + int(sizeof(v));
+}
+
+int CustomOverloadSequence::overload(int v) const
+{
+ return v + 4;
+}
diff --git a/sources/shiboken6/tests/libsample/overloadsort.h b/sources/shiboken6/tests/libsample/overloadsort.h
new file mode 100644
index 000000000..ee269cc21
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/overloadsort.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OVERLOADSORT_H
+#define OVERLOADSORT_H
+
+#include "libsamplemacros.h"
+
+#include <list>
+
+class ImplicitTarget
+{
+public:
+ ImplicitTarget() = default;
+};
+
+class ImplicitBase
+{
+public:
+ ImplicitBase() = default;
+ ImplicitBase(const ImplicitTarget &b);
+};
+
+inline ImplicitBase::ImplicitBase(const ImplicitTarget &)
+{
+}
+
+class LIBSAMPLE_API SortedOverload
+{
+public:
+
+ const char *overload(int x);
+ const char *overload(double x);
+ const char *overload(ImplicitBase x);
+ const char *overload(ImplicitTarget x);
+ const char *overload(const std::list<ImplicitBase> &x);
+
+ int implicit_overload(const ImplicitBase &x);
+
+ const char *overloadDeep(int x, ImplicitBase &y);
+
+ inline const char *pyObjOverload(int, int) { return "int,int"; }
+ inline const char *pyObjOverload(unsigned char *, int)
+ { return "PyObject,int"; }
+};
+
+class LIBSAMPLE_API CustomOverloadSequence
+{
+public:
+ int overload(short v) const;
+ int overload(int v) const;
+};
+
+#endif // OVERLOADSORT_H
diff --git a/sources/shiboken6/tests/libsample/pairuser.cpp b/sources/shiboken6/tests/libsample/pairuser.cpp
new file mode 100644
index 000000000..5b7eb4d8c
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/pairuser.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "pairuser.h"
+
+std::pair<int, int> PairUser::callCreatePair()
+{
+ return createPair();
+}
+
+std::pair<int, int> PairUser::createPair()
+{
+ return {10, 20};
+}
+
+std::pair<Complex, Complex> PairUser::createComplexPair(Complex cpx0, Complex cpx1)
+{
+ return {cpx0, cpx1};
+}
+
+double PairUser::sumPair(std::pair<int, double> pair)
+{
+ return ((double) pair.first) + pair.second;
+}
diff --git a/sources/shiboken6/tests/libsample/pairuser.h b/sources/shiboken6/tests/libsample/pairuser.h
new file mode 100644
index 000000000..ee51d818e
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/pairuser.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PAIRUSER_H
+#define PAIRUSER_H
+
+#include "libsamplemacros.h"
+#include "complex.h"
+
+#include <utility>
+
+class LIBSAMPLE_API PairUser
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(PairUser)
+
+ PairUser() noexcept = default;
+ virtual ~PairUser() = default;
+
+ virtual std::pair<int, int> createPair();
+ std::pair<int, int> callCreatePair();
+ static std::pair<Complex, Complex> createComplexPair(Complex cpx0, Complex cpx1);
+ double sumPair(std::pair<int, double> pair);
+
+ inline void setPair(std::pair<int, int> pair) { m_pair = pair; }
+ inline std::pair<int, int> getPair() { return m_pair; }
+
+private:
+ std::pair<int, int> m_pair;
+};
+
+#endif // PAIRUSER_H
diff --git a/sources/shiboken6/tests/libsample/pen.cpp b/sources/shiboken6/tests/libsample/pen.cpp
new file mode 100644
index 000000000..76473a264
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/pen.cpp
@@ -0,0 +1,83 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "pen.h"
+
+Color::Color(SampleNamespace::InValue) : m_null(false)
+{
+}
+
+Color::Color(unsigned int) : m_null(false)
+{
+}
+
+bool Color::isNull() const
+{
+ return m_null;
+}
+
+Brush::Brush(const Color &c) : m_color(c)
+{
+}
+
+Brush::operator bool() const
+{
+ return !m_color.isNull();
+}
+
+Brush::Style Brush::style() const
+{
+ return m_style;
+}
+
+void Brush::setStyle(Style newStyle)
+{
+ m_style = newStyle;
+}
+
+const Color &Brush::color() const
+{
+ return m_color;
+}
+
+void Brush::setColor(const Color &newColor)
+{
+ m_color = newColor;
+}
+
+Pen::Pen() = default;
+
+Pen::Pen(SampleNamespace::Option) : m_ctor(EnumCtor)
+{
+}
+
+Pen::Pen(const Color &) : m_ctor(ColorCtor)
+{
+}
+
+Pen::Pen(const Pen &) : m_ctor(CopyCtor)
+{
+}
+
+Pen::Pen(Pen &&) noexcept = default;
+Pen &Pen::operator=(const Pen &pen) = default;
+Pen &Pen::operator=(Pen &&) noexcept = default;
+
+int Pen::ctorType()
+{
+ return m_ctor;
+}
+
+void Pen::drawLine(int, int, int, int, RenderHints)
+{
+}
+
+Pen::RenderHints Pen::getRenderHints() const
+{
+ return m_renderHints;
+}
+
+void Pen::setRenderHints(RenderHints h)
+{
+ m_renderHints = h;
+}
diff --git a/sources/shiboken6/tests/libsample/pen.h b/sources/shiboken6/tests/libsample/pen.h
new file mode 100644
index 000000000..6f528f0f9
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/pen.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PEN_H
+#define PEN_H
+
+#include "libsamplemacros.h"
+#include "samplenamespace.h"
+
+class LIBSAMPLE_API Color
+{
+public:
+ Color() = default;
+ Color(SampleNamespace::InValue arg);
+ Color(unsigned int arg);
+
+ bool isNull() const;
+
+private:
+ bool m_null = true;
+};
+
+class LIBSAMPLE_API Brush
+{
+public:
+ enum Style { Solid, Cross };
+
+ explicit Brush(const Color &c = {});
+
+ operator bool() const;
+
+ Style style() const;
+ void setStyle(Style newStyle);
+
+ const Color &color() const;
+ void setColor(const Color &newColor);
+
+private:
+ Style m_style = Solid;
+ Color m_color;
+};
+
+class LIBSAMPLE_API Pen
+{
+public:
+ enum { EmptyCtor, EnumCtor, ColorCtor, CopyCtor };
+
+ enum RenderHints { None = 0, Antialiasing = 0x1, TextAntialiasing = 0x2 };
+
+ Pen();
+ Pen(SampleNamespace::Option option);
+ Pen(const Color &color);
+ Pen(const Pen &pen);
+ Pen(Pen &&) noexcept;
+ Pen &operator=(const Pen &pen);
+ Pen &operator=(Pen &&) noexcept;
+ ~Pen() = default;
+
+ // PYSIDE-1325, default initializer
+ void drawLine(int x1, int y1, int x2, int y2, RenderHints renderHints = {});
+
+ int ctorType();
+
+ RenderHints getRenderHints() const;
+ void setRenderHints(RenderHints h);
+
+private:
+ int m_ctor = EmptyCtor;
+ RenderHints m_renderHints = None;
+};
+
+#endif
diff --git a/sources/shiboken6/tests/libsample/photon.cpp b/sources/shiboken6/tests/libsample/photon.cpp
new file mode 100644
index 000000000..2a7f20e33
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/photon.cpp
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "photon.h"
+
+namespace Photon
+{
+
+const ClassType Base::staticType;
+
+int callCalculateForValueDuplicatorPointer(ValueDuplicator *value)
+{
+ return value->calculate();
+}
+
+int callCalculateForValueDuplicatorReference(ValueDuplicator &value)
+{
+ return value.calculate();
+}
+
+int countValueIdentities(const std::list<ValueIdentity> &values)
+{
+ return values.size();
+}
+
+int countValueDuplicators(const std::list<TemplateBase<DuplicatorType> > &values)
+{
+ return values.size();
+}
+
+} // namespace Photon
diff --git a/sources/shiboken6/tests/libsample/photon.h b/sources/shiboken6/tests/libsample/photon.h
new file mode 100644
index 000000000..2debe47d1
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/photon.h
@@ -0,0 +1,110 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PHOTON_H
+#define PHOTON_H
+
+#include "libsamplemacros.h"
+
+#include <list>
+
+// This namespace and classes simulate
+// situations found in Qt's phonon module.
+
+namespace Photon
+{
+
+enum ClassType {
+ BaseType = 0,
+ IdentityType = 1,
+ DuplicatorType = 2
+};
+
+class LIBSAMPLE_API Base
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Base)
+
+ explicit Base(int value) noexcept : m_value(value) {}
+ virtual ~Base() = default;
+
+ inline void setValue(int value) { m_value = value; }
+ inline int value() const { return m_value; }
+
+ template <class T> bool isType() { return type() == T::staticType; }
+ bool isType(ClassType t) { return type() == t; }
+
+ virtual ClassType type() const { return BaseType; };
+ static const ClassType staticType = BaseType;
+
+protected:
+ int m_value;
+};
+
+template<ClassType CLASS_TYPE>
+class LIBSAMPLE_API TemplateBase : public Base
+{
+public:
+ explicit TemplateBase(int value) : Base(value) {}
+ inline int multiplicator() const { return int(CLASS_TYPE); }
+ inline int calculate() const { return m_value * (int(CLASS_TYPE)); }
+ static inline ClassType classType() { return CLASS_TYPE; }
+
+ inline int sumValueUsingPointer(TemplateBase<CLASS_TYPE> *other) const
+ { return m_value + other->m_value; }
+ inline int sumValueUsingReference(TemplateBase<CLASS_TYPE> &other) const
+ { return m_value + other.m_value; }
+
+ inline std::list<TemplateBase<CLASS_TYPE> > getListOfThisTemplateBase()
+ {
+ std::list<TemplateBase<CLASS_TYPE> > objs;
+ objs.push_back(*this);
+ objs.push_back(*this);
+ return objs;
+ }
+
+ static inline TemplateBase<CLASS_TYPE> *passPointerThrough(TemplateBase<CLASS_TYPE> *obj)
+ { return obj; }
+
+ ClassType type() const override { return CLASS_TYPE; }
+ static const ClassType staticType = CLASS_TYPE;
+};
+
+#if defined _WIN32 || defined __CYGWIN__
+template class LIBSAMPLE_API TemplateBase<IdentityType>;
+template class LIBSAMPLE_API TemplateBase<DuplicatorType>;
+#endif
+
+using ValueIdentity = TemplateBase<IdentityType>;
+using ValueDuplicator = TemplateBase<DuplicatorType>;
+
+LIBSAMPLE_API int callCalculateForValueDuplicatorPointer(ValueDuplicator *value);
+LIBSAMPLE_API int callCalculateForValueDuplicatorReference(ValueDuplicator &value);
+LIBSAMPLE_API int countValueIdentities(const std::list<ValueIdentity> &values);
+LIBSAMPLE_API int countValueDuplicators(const std::list<TemplateBase<DuplicatorType> > &values);
+
+class Pointer
+{
+public:
+ Pointer() noexcept = default;
+ explicit Pointer(int *p) : px(p) {}
+
+ void reset() noexcept { Pointer().swap(*this); }
+
+ int *get() const noexcept { return px; }
+ int &operator*() const { return *px; }
+
+ void swap(Pointer &rhs) noexcept
+ {
+ int *tmp = px;
+ px = rhs.px;
+ rhs.px = tmp;
+ }
+
+private:
+ int *px = nullptr;
+};
+
+} // namespace Photon
+
+#endif // PHOTON_H
diff --git a/sources/shiboken6/tests/libsample/point.cpp b/sources/shiboken6/tests/libsample/point.cpp
new file mode 100644
index 000000000..0a28e877f
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/point.cpp
@@ -0,0 +1,111 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "point.h"
+
+#include <iostream>
+
+Point::Point(int x, int y) noexcept : m_x(x), m_y(y)
+{
+}
+
+Point::Point(double x, double y) noexcept : m_x(x), m_y(y)
+{
+}
+
+void Point::midpoint(const Point &other, Point *midpoint) const
+{
+ if (!midpoint)
+ return;
+ midpoint->setX((m_x + other.m_x) / 2.0);
+ midpoint->setY((m_y + other.m_y) / 2.0);
+}
+
+Point *Point::copy() const
+{
+ Point *pt = new Point();
+ pt->m_x = m_x;
+ pt->m_y = m_y;
+ return pt;
+}
+
+void Point::show() const
+{
+ std::cout << "(x: " << m_x << ", y: " << m_y << ")";
+}
+
+bool Point::operator==(const Point &other) const
+{
+ return m_x == other.m_x && m_y == other.m_y;
+}
+
+Point Point::operator+(const Point &other)
+{
+ return {m_x + other.m_x, m_y + other.m_y};
+}
+
+Point Point::operator-(const Point &other)
+{
+ return {m_x - other.m_x, m_y - other.m_y};
+}
+
+Point &Point::operator+=(Point &other)
+{
+ m_x += other.m_x;
+ m_y += other.m_y;
+ return *this;
+}
+
+Point &Point::operator-=(Point &other)
+{
+ m_x -= other.m_x;
+ m_y -= other.m_y;
+ return *this;
+}
+
+Point operator*(const Point &pt, double mult)
+{
+ return Point(pt.m_x * mult, pt.m_y * mult);
+}
+
+Point operator*(const Point &pt, int mult)
+{
+ return {int(pt.m_x) * mult, int(pt.m_y) * mult};
+}
+
+Point operator*(double mult, const Point &pt)
+{
+ return {pt.m_x * mult, pt.m_y * mult};
+}
+
+Point operator*(int mult, const Point &pt)
+{
+ return {int(pt.m_x) * mult, int(pt.m_y) * mult};
+}
+
+Point operator-(const Point &pt)
+{
+ return {-pt.m_x, -pt.m_y};
+}
+
+bool operator!(const Point &pt)
+{
+ return pt.m_x == 0.0 && pt.m_y == 0.0;
+}
+
+Point Point::operator/(int operand)
+{
+ return {m_x/operand, m_y/operand};
+}
+
+Complex transmutePointIntoComplex(const Point &point)
+{
+ Complex cpx(point.x(), point.y());
+ return cpx;
+}
+
+Point transmuteComplexIntoPoint(const Complex &cpx)
+{
+ Point pt(cpx.real(), cpx.imag());
+ return pt;
+}
diff --git a/sources/shiboken6/tests/libsample/point.h b/sources/shiboken6/tests/libsample/point.h
new file mode 100644
index 000000000..7e5d128ab
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/point.h
@@ -0,0 +1,76 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef POINT_H
+#define POINT_H
+
+#include "libsamplemacros.h"
+#include "complex.h"
+
+#include <utility>
+
+class LIBSAMPLE_API Point
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Point)
+
+ Point(int x = 0, int y = 0) noexcept;
+ Point(double x, double y) noexcept;
+ ~Point() = default;
+
+ inline double x() const { return m_x; }
+ inline double y() const { return m_y; }
+
+ inline void setX(double x) { m_x = x; }
+ inline void setY(double y) { m_y = y; }
+ inline void setXAsUint(unsigned int x) { m_x = x; }
+ inline void setYAsUint(unsigned int y) { m_y = y; }
+
+ // This method could simply return the midpoint,
+ // but the interesting part of the test is to set the
+ // result in the pointer argument.
+ void midpoint(const Point &other, Point *midpoint) const;
+
+ Point *copy() const;
+
+ inline const Point &getConstReferenceToSelf() const { return *this; }
+ inline const Point *getSelf() const { return this; }
+
+ // 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) const;
+
+ Point operator+(const Point &other);
+ Point operator-(const Point &other);
+ Point operator/(int operand);
+
+ friend LIBSAMPLE_API Point operator*(const Point &pt, double mult);
+ friend LIBSAMPLE_API Point operator*(const Point &pt, int mult);
+ friend LIBSAMPLE_API Point operator*(double mult, const Point &pt);
+ friend LIBSAMPLE_API Point operator*(int mult, const Point &pt);
+ friend LIBSAMPLE_API Point operator-(const Point &pt);
+ friend LIBSAMPLE_API bool operator!(const Point &pt);
+
+ Point &operator+=(Point &other);
+ Point &operator-=(Point &other);
+
+ void show() const;
+
+private:
+ double m_x;
+ double m_y;
+};
+
+LIBSAMPLE_API Point operator*(const Point &pt, double mult);
+LIBSAMPLE_API Point operator*(const Point &pt, int mult);
+LIBSAMPLE_API Point operator*(double mult, const Point &pt);
+LIBSAMPLE_API Point operator*(int mult, const Point &pt);
+LIBSAMPLE_API Point operator-(const Point &pt);
+LIBSAMPLE_API bool operator!(const Point &pt);
+
+LIBSAMPLE_API Complex transmutePointIntoComplex(const Point &point);
+LIBSAMPLE_API Point transmuteComplexIntoPoint(const Complex &cpx);
+
+LIBSAMPLE_API Point operator*(const Point &pt, double multiplier);
+
+#endif // POINT_H
diff --git a/sources/shiboken6/tests/libsample/pointerholder.h b/sources/shiboken6/tests/libsample/pointerholder.h
new file mode 100644
index 000000000..26f1cf0a6
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/pointerholder.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef POINTERHOLDER_H
+#define POINTERHOLDER_H
+
+#include "libsamplemacros.h"
+
+class PointerHolder
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(PointerHolder)
+
+ explicit PointerHolder(void *ptr) : m_pointer(ptr) {}
+ ~PointerHolder() = default;
+
+ inline void *pointer() const { return m_pointer; }
+
+private:
+ void *m_pointer;
+};
+
+#endif // POINTERHOLDER_H
diff --git a/sources/shiboken6/tests/libsample/pointf.cpp b/sources/shiboken6/tests/libsample/pointf.cpp
new file mode 100644
index 000000000..736a5c6b5
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/pointf.cpp
@@ -0,0 +1,86 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "pointf.h"
+
+#include <iostream>
+
+PointF::PointF(const Point &point) noexcept : m_x(point.x()), m_y(point.y())
+{
+}
+
+PointF::PointF(double x, double y) noexcept : m_x(x), m_y(y)
+{
+}
+
+void PointF::midpoint(const PointF &other, PointF *midpoint) const
+{
+ if (!midpoint)
+ return;
+ midpoint->setX((m_x + other.m_x) / 2.0);
+ midpoint->setY((m_y + other.m_y) / 2.0);
+}
+
+void PointF::show() const
+{
+ std::cout << "(x: " << m_x << ", y: " << m_y << ")";
+}
+
+bool PointF::operator==(const PointF &other) const
+{
+ return m_x == other.m_x && m_y == other.m_y;
+}
+
+PointF PointF::operator+(const PointF &other)
+{
+ return {m_x + other.m_x, m_y + other.m_y};
+}
+
+PointF PointF::operator-(const PointF &other)
+{
+ return {m_x - other.m_x, m_y - other.m_y};
+}
+
+PointF &PointF::operator+=(PointF &other)
+{
+ m_x += other.m_x;
+ m_y += other.m_y;
+ return *this;
+}
+
+PointF &PointF::operator-=(PointF &other)
+{
+ m_x -= other.m_x;
+ m_y -= other.m_y;
+ return *this;
+}
+
+PointF operator*(const PointF &pt, double mult)
+{
+ return {pt.m_x * mult, pt.m_y * mult};
+}
+
+PointF operator*(const PointF &pt, int mult)
+{
+ return PointF(int(pt.m_x) * mult, int(pt.m_y) * mult);
+}
+
+PointF operator*(double mult, const PointF &pt)
+{
+ return {pt.m_x * mult, pt.m_y * mult};
+}
+
+PointF operator*(int mult, const PointF &pt)
+{
+ return PointF(int(pt.m_x) * mult, int(pt.m_y) * mult);
+}
+
+PointF operator-(const PointF &pt)
+{
+ return {-pt.m_x, -pt.m_y};
+}
+
+bool operator!(const PointF &pt)
+{
+ return pt.m_x == 0.0 && pt.m_y == 0.0;
+}
diff --git a/sources/shiboken6/tests/libsample/pointf.h b/sources/shiboken6/tests/libsample/pointf.h
new file mode 100644
index 000000000..49e009467
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/pointf.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef POINTF_H
+#define POINTF_H
+
+#include "libsamplemacros.h"
+#include "point.h"
+
+#include <utility>
+
+class LIBSAMPLE_API PointF
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(PointF)
+
+ PointF(const Point &point) noexcept;
+ PointF(double x = 0.0, double y = 0.0) noexcept;
+ ~PointF() noexcept = default;
+
+ inline double x() const { return m_x; }
+ inline double y() const { return m_y; }
+
+ inline void setX(double x) { m_x = x; }
+ inline void setY(double y) { m_y = y; }
+
+ // This method could simply return the midpoint,
+ // but the interesting part of the test is to set the
+ // result in the pointer argument.
+ void midpoint(const PointF &other, PointF *midpoint) const;
+
+ // 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) const;
+
+ PointF operator+(const PointF &other);
+ PointF operator-(const PointF &other);
+
+ friend LIBSAMPLE_API PointF operator*(const PointF &pt, double mult);
+ friend LIBSAMPLE_API PointF operator*(const PointF &pt, int mult);
+ friend LIBSAMPLE_API PointF operator*(double mult, const PointF &pt);
+ friend LIBSAMPLE_API PointF operator*(int mult, const PointF &pt);
+ friend LIBSAMPLE_API PointF operator-(const PointF &pt);
+ friend LIBSAMPLE_API bool operator!(const PointF &pt);
+
+ PointF &operator+=(PointF &other);
+ PointF &operator-=(PointF &other);
+
+ void show() const;
+
+private:
+ double m_x;
+ double m_y;
+};
+
+LIBSAMPLE_API PointF operator*(const PointF &pt, double mult);
+LIBSAMPLE_API PointF operator*(const PointF &pt, int mult);
+LIBSAMPLE_API PointF operator*(double mult, const PointF &pt);
+LIBSAMPLE_API PointF operator*(int mult, const PointF &pt);
+LIBSAMPLE_API PointF operator-(const PointF &pt);
+LIBSAMPLE_API bool operator!(const PointF &pt);
+
+LIBSAMPLE_API PointF operator*(const PointF &pt, double multiplier);
+
+#endif // POINTF_H
diff --git a/sources/shiboken6/tests/libsample/polygon.cpp b/sources/shiboken6/tests/libsample/polygon.cpp
new file mode 100644
index 000000000..6af597192
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/polygon.cpp
@@ -0,0 +1,39 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "polygon.h"
+
+Polygon::Polygon(double x, double y) : m_points({Point(x, y)})
+{
+}
+
+Polygon::Polygon(Point point) : m_points({point})
+{
+}
+
+Polygon::Polygon(PointList points) : m_points(points)
+{
+}
+
+void Polygon::addPoint(Point point)
+{
+ m_points.push_back(point);
+}
+
+Polygon Polygon::doublePolygonScale(Polygon polygon)
+{
+ Polygon result;
+ for (const auto &point : polygon.points())
+ result.addPoint(point * 2.0);
+ return result;
+}
+
+void Polygon::stealOwnershipFromPython(Point *point)
+{
+ delete point;
+}
+
+void Polygon::stealOwnershipFromPython(Polygon *polygon)
+{
+ delete polygon;
+}
diff --git a/sources/shiboken6/tests/libsample/polygon.h b/sources/shiboken6/tests/libsample/polygon.h
new file mode 100644
index 000000000..2424ddd51
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/polygon.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef POLYGON_H
+#define POLYGON_H
+
+#include "libsamplemacros.h"
+#include "point.h"
+
+#include <list>
+
+class LIBSAMPLE_API Polygon // should be moveable
+{
+public:
+ using PointList = std::list<Point>;
+
+ Polygon() noexcept = default;
+ Polygon(double x, double y);
+ Polygon(Point point);
+ Polygon(PointList points);
+
+ void addPoint(Point point);
+
+ inline const PointList &points() const { return m_points; }
+
+ // This method intentionally receives and returns copies of a Polygon object.
+ static Polygon doublePolygonScale(Polygon polygon);
+
+ // This method invalidates the argument to be used for Polygon(Point) implicit conversion.
+ static void stealOwnershipFromPython(Point *point);
+
+ // This method invalidates the argument to be used in a call to doublePolygonScale(Polygon).
+ static void stealOwnershipFromPython(Polygon *polygon);
+
+private:
+ PointList m_points;
+};
+
+#endif // POLYGON_H
diff --git a/sources/shiboken6/tests/libsample/privatector.h b/sources/shiboken6/tests/libsample/privatector.h
new file mode 100644
index 000000000..3b38414f8
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/privatector.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PRIVATECTOR_H
+#define PRIVATECTOR_H
+
+#include "libsamplemacros.h"
+
+class PrivateCtor
+{
+public:
+ inline static PrivateCtor *instance()
+ {
+ static PrivateCtor self;
+ self.m_instantiations++;
+ return &self;
+ }
+
+ inline int instanceCalls()
+ {
+ return m_instantiations;
+ }
+
+private:
+ int m_instantiations = 0;
+
+ PrivateCtor() = default;
+};
+
+class DeletedDefaultCtor
+{
+public:
+ DeletedDefaultCtor() = delete;
+
+ DeletedDefaultCtor(const DeletedDefaultCtor &) = default;
+ DeletedDefaultCtor(DeletedDefaultCtor &&) = default;
+ DeletedDefaultCtor &operator=(const DeletedDefaultCtor &) = default;
+ DeletedDefaultCtor &operator=(DeletedDefaultCtor &&) = default;
+ ~DeletedDefaultCtor() = default;
+};
+
+#endif // PRIVATECTOR_H
diff --git a/sources/shiboken6/tests/libsample/privatedtor.h b/sources/shiboken6/tests/libsample/privatedtor.h
new file mode 100644
index 000000000..05f18ea53
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/privatedtor.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PRIVATEDTOR_H
+#define PRIVATEDTOR_H
+
+#include "libsamplemacros.h"
+
+class PrivateDtor
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(PrivateDtor)
+
+ inline static PrivateDtor *instance()
+ {
+ static PrivateDtor self;
+ self.m_instantiations++;
+ return &self;
+ }
+
+ inline int instanceCalls()
+ {
+ return m_instantiations;
+ }
+
+protected:
+ inline int protectedInstanceCalls() { return m_instantiations; }
+
+private:
+ int m_instantiations = 0;
+
+ PrivateDtor() noexcept = default;
+ ~PrivateDtor() = default;
+};
+
+#endif // PRIVATEDTOR_H
diff --git a/sources/shiboken6/tests/libsample/protected.cpp b/sources/shiboken6/tests/libsample/protected.cpp
new file mode 100644
index 000000000..7ab52d22b
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/protected.cpp
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "protected.h"
+
+int ProtectedVirtualDestructor::dtor_called = 0;
+
+const char *ProtectedNonPolymorphic::dataTypeName(void *) const
+{
+ return "pointer";
+}
+
+const char *ProtectedNonPolymorphic::dataTypeName(int) const
+{
+ return "integer";
+}
diff --git a/sources/shiboken6/tests/libsample/protected.h b/sources/shiboken6/tests/libsample/protected.h
new file mode 100644
index 000000000..059cced5d
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/protected.h
@@ -0,0 +1,139 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef PROTECTED_H
+#define PROTECTED_H
+
+#include "libsamplemacros.h"
+#include "objecttype.h"
+#include "point.h"
+
+#include <string>
+#include <list>
+
+class LIBSAMPLE_API ProtectedNonPolymorphic
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(ProtectedNonPolymorphic)
+
+ explicit ProtectedNonPolymorphic(const char *name) : m_name(name) {}
+ ~ProtectedNonPolymorphic() = default;
+
+ inline const char *publicName() { return m_name.c_str(); }
+
+ inline static ProtectedNonPolymorphic *create()
+ { return new ProtectedNonPolymorphic("created"); }
+
+protected:
+ inline const char *protectedName() { return m_name.c_str(); }
+ inline int protectedSum(int a0, int a1) { return a0 + a1; }
+ inline int modifiedProtectedSum(int a0, int a1) { return a0 + a1; }
+ inline static const char *protectedStatic() { return "protectedStatic"; }
+ const char *dataTypeName(void *data = nullptr) const;
+ const char *dataTypeName(int data) const;
+
+private:
+ std::string m_name;
+};
+
+class LIBSAMPLE_API ProtectedPolymorphic
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(ProtectedPolymorphic)
+
+ explicit ProtectedPolymorphic(const char *name) : m_name(name) {}
+ virtual ~ProtectedPolymorphic() = default;
+
+ inline static ProtectedPolymorphic *create()
+ { return new ProtectedPolymorphic("created"); }
+ inline const char *publicName() { return m_name.c_str(); }
+ inline const char *callProtectedName() { return protectedName(); }
+
+protected:
+ virtual const char *protectedName() { return m_name.c_str(); }
+
+private:
+ std::string m_name;
+};
+
+class LIBSAMPLE_API ProtectedPolymorphicDaughter : public ProtectedPolymorphic
+{
+public:
+ explicit ProtectedPolymorphicDaughter(const char *name) :
+ ProtectedPolymorphic(name) {}
+ inline static ProtectedPolymorphicDaughter *create()
+ { return new ProtectedPolymorphicDaughter("created"); }
+};
+
+class LIBSAMPLE_API ProtectedPolymorphicGrandDaughter: public ProtectedPolymorphicDaughter
+{
+public:
+ explicit ProtectedPolymorphicGrandDaughter(const char *name) :
+ ProtectedPolymorphicDaughter(name) {}
+ inline static ProtectedPolymorphicGrandDaughter *create()
+ { return new ProtectedPolymorphicGrandDaughter("created"); }
+};
+
+class LIBSAMPLE_API ProtectedVirtualDestructor
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(ProtectedVirtualDestructor)
+
+ ProtectedVirtualDestructor() noexcept = default;
+ inline static ProtectedVirtualDestructor *create()
+ { return new ProtectedVirtualDestructor(); }
+ inline static int dtorCalled() { return dtor_called; }
+ inline static void resetDtorCounter() { dtor_called = 0; }
+protected:
+ virtual ~ProtectedVirtualDestructor() { dtor_called++; }
+private:
+ static int dtor_called;
+};
+
+class LIBSAMPLE_API ProtectedEnumClass
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(ProtectedEnumClass)
+
+ ProtectedEnumClass() noexcept = default;
+ virtual ~ProtectedEnumClass() = default;
+ enum PublicEnum {
+ PublicItem0,
+ PublicItem1
+ };
+protected:
+ enum ProtectedEnum {
+ ProtectedItem0,
+ ProtectedItem1
+ };
+ ProtectedEnum callProtectedEnumMethod(ProtectedEnum in)
+ { return protectedEnumMethod(in); }
+ inline PublicEnum callPublicEnumMethod(PublicEnum in)
+ { return publicEnumMethod(in); }
+
+ virtual ProtectedEnum protectedEnumMethod(ProtectedEnum in) { return in; }
+ virtual PublicEnum publicEnumMethod(PublicEnum in) { return in; }
+};
+
+class LIBSAMPLE_API ProtectedProperty
+{
+public:
+ ProtectedProperty() = default;
+
+protected:
+ // This is deliberately the first member to test wrapper registration
+ // for value type members sharing the same memory address.
+ Point protectedValueTypeProperty{0, 0};
+ int protectedProperty = 0;
+ std::list<int> protectedContainerProperty;
+ Event::EventType protectedEnumProperty = Event::NO_EVENT;
+ Point *protectedValueTypePointerProperty = nullptr;
+ ObjectType *protectedObjectTypeProperty = nullptr;
+};
+
+LIBSAMPLE_API inline ProtectedProperty *createProtectedProperty()
+{
+ return new ProtectedProperty;
+}
+
+#endif // PROTECTED_H
diff --git a/sources/shiboken6/tests/libsample/rect.h b/sources/shiboken6/tests/libsample/rect.h
new file mode 100644
index 000000000..53296d26c
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/rect.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef RECT_H
+#define RECT_H
+
+#include "libsamplemacros.h"
+
+class LIBSAMPLE_API Rect
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Rect)
+
+ Rect() noexcept = default;
+ explicit Rect(int left, int top, int right, int bottom) noexcept
+ : m_left(left), m_top(top), m_right(right), m_bottom(bottom) { }
+ ~Rect() = default;
+
+ inline int left() const { return m_left; }
+ inline int top() const { return m_top; }
+ inline int right() const { return m_right; }
+ inline int bottom() const { return m_bottom; }
+private:
+ int m_left = 0;
+ int m_top = 0;
+ int m_right = -1;
+ int m_bottom = -1;
+};
+
+class LIBSAMPLE_API RectF
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(RectF)
+
+ RectF() noexcept = default;
+ explicit RectF(int left, int top, int right, int bottom) noexcept
+ : m_left(left), m_top(top), m_right(right), m_bottom(bottom) { }
+ RectF(const Rect &other) noexcept :
+ m_left(other.left()), m_top(other.top()),
+ m_right(other.right()), m_bottom(other.bottom()) {}
+ ~RectF() = default;
+
+ inline double left() const { return m_left; }
+ inline double top() const { return m_top; }
+ inline double right() const { return m_right; }
+ inline double bottom() const { return m_bottom; }
+private:
+ double m_left = 0;
+ double m_top = 0;
+ double m_right = -1;
+ double m_bottom = -1;
+};
+
+#endif // RECT_H
diff --git a/sources/shiboken6/tests/libsample/reference.cpp b/sources/shiboken6/tests/libsample/reference.cpp
new file mode 100644
index 000000000..29dcfc054
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/reference.cpp
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "reference.h"
+
+#include <iostream>
+
+void Reference::show() const
+{
+ std::cout << "Reference.objId: " << m_objId << ", address: " << this;
+}
+
+Reference &Reference::returnMySecondArg(int, Reference &ref)
+{
+ return ref;
+}
+
+int Reference::usesReferenceVirtual(Reference &r, int inc)
+{
+ return r.m_objId + inc;
+}
+
+int Reference::usesConstReferenceVirtual(const Reference &r, int inc)
+{
+ return r.m_objId + inc;
+}
+
+int Reference::callUsesReferenceVirtual(Reference &r, int inc)
+{
+ return usesReferenceVirtual(r, inc);
+}
+
+int Reference::callUsesConstReferenceVirtual(const Reference &r, int inc)
+{
+ return usesConstReferenceVirtual(r, inc);
+}
+
+void Reference::alterReferenceIdVirtual(Reference &r)
+{
+ r.setObjId(r.objId() * Reference::multiplier());
+}
+
+void Reference::callAlterReferenceIdVirtual(Reference &r)
+{
+ alterReferenceIdVirtual(r);
+}
+
+ObjTypeReference::~ObjTypeReference() = default;
+
+ObjTypeReference &ObjTypeReference::returnMySecondArg(int, ObjTypeReference &ref)
+{
+ return ref;
+}
diff --git a/sources/shiboken6/tests/libsample/reference.h b/sources/shiboken6/tests/libsample/reference.h
new file mode 100644
index 000000000..52818d9ea
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/reference.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef REFERENCE_H
+#define REFERENCE_H
+
+#include "libsamplemacros.h"
+
+class LIBSAMPLE_API Reference
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Reference)
+
+ explicit Reference(int objId = -1) noexcept
+ : m_objId(objId) {}
+ virtual ~Reference() = default;
+
+ inline int objId() const { return m_objId; }
+ inline void setObjId(int objId) { m_objId = objId; }
+
+ inline static int usesReference(Reference &r) { return r.m_objId; }
+ inline static int usesConstReference(const Reference &r) { return r.m_objId; }
+
+ virtual int usesReferenceVirtual(Reference &r, int inc);
+ virtual int usesConstReferenceVirtual(const Reference &r, int inc);
+
+ int callUsesReferenceVirtual(Reference &r, int inc);
+ int callUsesConstReferenceVirtual(const Reference &r, int inc);
+
+ virtual void alterReferenceIdVirtual(Reference &r);
+ void callAlterReferenceIdVirtual(Reference &r);
+
+ void show() const;
+
+ inline static int multiplier() { return 10; }
+
+ virtual Reference &returnMyFirstArg(Reference &ref) { return ref; }
+ virtual Reference &returnMySecondArg(int a, Reference &ref);
+
+ // nonsense operator to test if Shiboken is ignoring dereference operators.
+ int operator*() { return m_objId; }
+
+private:
+ int m_objId;
+};
+
+class LIBSAMPLE_API ObjTypeReference
+{
+public:
+ LIBMINIMAL_DISABLE_MOVE(ObjTypeReference)
+
+ ObjTypeReference() noexcept = default;
+ ObjTypeReference(const ObjTypeReference &) noexcept = default;
+ ObjTypeReference &operator=(const ObjTypeReference &) = delete;
+ virtual ~ObjTypeReference();
+
+ virtual ObjTypeReference &returnMyFirstArg(ObjTypeReference &ref) { return ref; }
+ virtual ObjTypeReference &returnMySecondArg(int a, ObjTypeReference &ref);
+ virtual ObjTypeReference &justAPureVirtualFunc(ObjTypeReference &ref) = 0;
+};
+
+#endif // REFERENCE_H
diff --git a/sources/shiboken6/tests/libsample/removednamespaces.h b/sources/shiboken6/tests/libsample/removednamespaces.h
new file mode 100644
index 000000000..669f2ebf0
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/removednamespaces.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef REMOVEDNAMESPACE_H
+#define REMOVEDNAMESPACE_H
+
+#include "libsamplemacros.h"
+
+namespace RemovedNamespace1
+{
+
+enum RemovedNamespace1_Enum { RemovedNamespace1_Enum_Value0 = 0,
+ RemovedNamespace1_Enum_Value1 = 1 };
+
+enum { RemovedNamespace1_AnonymousEnum_Value0 };
+
+inline int mathSum(int x, int y) { return x + y; }
+
+struct ObjectOnInvisibleNamespace
+{
+ bool exists() const { return true; }
+ static int toInt(RemovedNamespace1_Enum e) { return static_cast<int>(e); }
+ static ObjectOnInvisibleNamespace consume(const ObjectOnInvisibleNamespace &other) { return other; }
+};
+
+namespace RemovedNamespace2
+{
+
+enum RemovedNamespace2_Enum { RemovedNamespace2_Enum_Value0 };
+
+} // namespace RemovedNamespace2
+} // namespace RemovedNamespace1
+
+namespace UnremovedNamespace
+{
+
+namespace RemovedNamespace3
+{
+ enum RemovedNamespace3_Enum { RemovedNamespace3_Enum_Value0 };
+
+ enum { RemovedNamespace3_AnonymousEnum_Value0 };
+
+ inline int nestedMathSum(int x, int y) { return x + y; }
+
+} // namespace RemovedNamespace3
+} // namespace UnremovedNamespace
+
+#endif // REMOVEDNAMESPACE_H
diff --git a/sources/shiboken6/tests/libsample/renaming.cpp b/sources/shiboken6/tests/libsample/renaming.cpp
new file mode 100644
index 000000000..d67b42a51
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/renaming.cpp
@@ -0,0 +1,21 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "renaming.h"
+
+#include <iostream>
+
+int ToBeRenamedValue::value() const
+{
+ return m_value;
+}
+
+void ToBeRenamedValue::setValue(int v)
+{
+ m_value = v;
+}
+
+void RenamedUser::useRenamedValue(const ToBeRenamedValue &v)
+{
+ std::cout << __FUNCTION__ << ' ' << v.value() << '\n';
+}
diff --git a/sources/shiboken6/tests/libsample/renaming.h b/sources/shiboken6/tests/libsample/renaming.h
new file mode 100644
index 000000000..787ccc2f7
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/renaming.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef RENAMING_H
+#define RENAMING_H
+
+#include "libsamplemacros.h"
+
+class LIBSAMPLE_API ToBeRenamedValue
+{
+public:
+ int value() const;
+ void setValue(int v);
+
+private:
+ int m_value = 42;
+};
+
+class LIBSAMPLE_API RenamedUser
+{
+public:
+ void useRenamedValue(const ToBeRenamedValue &v);
+};
+
+#endif // POINT_H
diff --git a/sources/shiboken6/tests/libsample/sample.cpp b/sources/shiboken6/tests/libsample/sample.cpp
new file mode 100644
index 000000000..5b5f8588b
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/sample.cpp
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "sample.h"
+
+namespace sample
+{
+
+sample::sample(int value) : m_value(value)
+{
+}
+
+int sample::value() const
+{
+ return m_value;
+}
+
+bool operator==(const sample &s1, const sample &s2)
+{
+ return s1.value() == s2.value();
+}
+} // namespace sample
diff --git a/sources/shiboken6/tests/libsample/sample.h b/sources/shiboken6/tests/libsample/sample.h
new file mode 100644
index 000000000..27909571a
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/sample.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SAMPLE_H
+#define SAMPLE_H
+
+#include "libsamplemacros.h"
+
+// namespace with the same name of the current package to try to mess up with the generator
+namespace sample
+{
+ // to increase the mess we add a class with the same name of the package/namespace
+ class LIBSAMPLE_API sample
+ {
+ public:
+ sample(int value = 0);
+ int value() const;
+ private:
+ int m_value;
+ };
+
+ // shiboken must not generate richcompare for namespace sample
+ LIBSAMPLE_API bool operator==(const sample &s1, const sample &s2);
+
+ const int INT_CONSTANT = 42;
+}
+
+#endif // SAMPLE_H
diff --git a/sources/shiboken6/tests/libsample/samplenamespace.cpp b/sources/shiboken6/tests/libsample/samplenamespace.cpp
new file mode 100644
index 000000000..eae5af2d2
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/samplenamespace.cpp
@@ -0,0 +1,101 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "samplenamespace.h"
+
+#include <iostream>
+#include <cstdlib>
+#include <ctime>
+
+namespace SampleNamespace
+{
+
+// PYSIDE-817, scoped enums must not be converted to int in the wrappers generated
+// for the protected hacks
+SomeClass::PublicScopedEnum SomeClass::protectedMethodReturningPublicScopedEnum() const
+{
+ return PublicScopedEnum::v1;
+}
+
+OutValue enumInEnumOut(InValue in)
+{
+ auto retval = OutValue(-1);
+ switch(in) {
+ case ZeroIn:
+ retval = ZeroOut;
+ break;
+ case OneIn:
+ retval = OneOut;
+ break;
+ case TwoIn:
+ retval = TwoOut;
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+Option enumArgumentWithDefaultValue(Option opt)
+{
+ return opt;
+}
+
+int getNumber(Option opt)
+{
+ int retval;
+ switch(opt) {
+ case RandomNumber:
+ retval = rand() % 100;
+ break;
+ case UnixTime:
+ retval = int(std::time(nullptr));
+ break;
+ default:
+ retval = 0;
+ break;
+ }
+ return retval;
+}
+
+void doSomethingWithArray(const unsigned char *, unsigned int, const char *)
+{
+ // This function does nothing in fact.
+ // It is here as a dummy copy of QPixmap.loadFromData method
+ // to check compilation issues, i.e. if it compiles, it's ok.
+}
+
+int enumItemAsDefaultValueToIntArgument(int value)
+{
+ return value;
+}
+
+void forceDecisorSideA(ObjectType *)
+{
+}
+
+void forceDecisorSideA(const Point &, const Str &, ObjectType *)
+{
+}
+
+void forceDecisorSideB(int, ObjectType *)
+{
+}
+
+void forceDecisorSideB(int, const Point &, const Str &, ObjectType *)
+{
+}
+
+double passReferenceToValueType(const Point &point, double multiplier)
+{
+ return (point.x() + point.y()) * multiplier;
+}
+
+int passReferenceToObjectType(const ObjectType &obj, int multiplier)
+{
+ return obj.objectName().size() * multiplier;
+}
+
+int variableInNamespace = 42;
+
+} // namespace SampleNamespace
diff --git a/sources/shiboken6/tests/libsample/samplenamespace.h b/sources/shiboken6/tests/libsample/samplenamespace.h
new file mode 100644
index 000000000..99a0787ee
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/samplenamespace.h
@@ -0,0 +1,164 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SAMPLENAMESPACE_H
+#define SAMPLENAMESPACE_H
+
+#include "libsamplemacros.h"
+#include "str.h"
+#include "point.h"
+#include "objecttype.h"
+
+#include <list>
+
+// Anonymous global enum
+enum {
+ AnonymousGlobalEnum_Value0,
+ AnonymousGlobalEnum_Value1
+};
+
+namespace SampleNamespace
+{
+
+inline namespace InlineNamespace
+{
+ enum EnumWithinInlineNamespace { EWIN_Value0, EWIN_Value1 };
+
+ class LIBSAMPLE_API ClassWithinInlineNamespace {
+ public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(ClassWithinInlineNamespace)
+
+ ClassWithinInlineNamespace() noexcept = default;
+ ~ClassWithinInlineNamespace() = default;
+
+ void setValue(EnumWithinInlineNamespace v) { m_value = v; }
+ EnumWithinInlineNamespace value() const { return m_value; }
+
+ private:
+ EnumWithinInlineNamespace m_value = EWIN_Value0;
+ };
+} // inline ns
+
+enum Option {
+ None_,
+ RandomNumber,
+ UnixTime
+};
+
+enum InValue {
+ ZeroIn,
+ OneIn,
+ TwoIn
+};
+
+enum OutValue {
+ ZeroOut,
+ OneOut,
+ TwoOut
+};
+
+// Anonymous non-global enum.
+// This counts as a class enum, since C++ namespaces
+// are represented as classes in Python.
+enum {
+ AnonymousClassEnum_Value0,
+ AnonymousClassEnum_Value1
+};
+
+LIBSAMPLE_API OutValue enumInEnumOut(InValue in);
+
+LIBSAMPLE_API Option enumArgumentWithDefaultValue(Option opt = UnixTime);
+
+LIBSAMPLE_API int getNumber(Option opt);
+
+inline double powerOfTwo(double num) {
+ return num * num;
+}
+
+LIBSAMPLE_API void doSomethingWithArray(const unsigned char *data, unsigned int size,
+ const char *format = nullptr);
+
+LIBSAMPLE_API int enumItemAsDefaultValueToIntArgument(int value = ZeroIn);
+
+class LIBSAMPLE_API SomeClass
+{
+public:
+ enum class PublicScopedEnum { v1, v2 };
+
+ class SomeInnerClass
+ {
+ public:
+ class OkThisIsRecursiveEnough
+ {
+ public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(OkThisIsRecursiveEnough)
+
+ OkThisIsRecursiveEnough() noexcept = default;
+ virtual ~OkThisIsRecursiveEnough() = default;
+ enum NiceEnum {
+ NiceValue1, NiceValue2
+ };
+
+ enum class NiceEnumClass {
+ NiceClassValue1, NiceClassValue2
+ };
+
+ inline int someMethod(SomeInnerClass *) { return 0; }
+ virtual OkThisIsRecursiveEnough *someVirtualMethod(OkThisIsRecursiveEnough *arg)
+ { return arg; }
+ };
+ protected:
+ enum ProtectedEnum {
+ ProtectedItem0,
+ ProtectedItem1
+ };
+ };
+ struct SomeOtherInnerClass {
+ std::list<SomeInnerClass> someInnerClasses;
+ };
+protected:
+ enum ProtectedEnum {
+ ProtectedItem0,
+ ProtectedItem1
+ };
+
+ PublicScopedEnum protectedMethodReturningPublicScopedEnum() const;
+};
+
+LIBSAMPLE_API inline int enumAsInt(SomeClass::PublicScopedEnum value)
+{ return static_cast<int>(value); }
+
+class DerivedFromNamespace : public SomeClass::SomeInnerClass::OkThisIsRecursiveEnough
+{
+public:
+ // FIXME Uncomment this when the fix for MSVC is available
+ // only to cause namespace confusion
+// enum SampleNamespace {
+// };
+ virtual OkThisIsRecursiveEnough *someVirtualMethod(OkThisIsRecursiveEnough *arg) { return arg; }
+ inline OkThisIsRecursiveEnough *methodReturningTypeFromParentScope() { return nullptr; }
+};
+
+// The combination of the following two overloaded methods could trigger a
+// problematic behaviour on the overload decisor, if it isn't working properly.
+LIBSAMPLE_API void forceDecisorSideA(ObjectType *object = nullptr);
+LIBSAMPLE_API void forceDecisorSideA(const Point &pt, const Str &text,
+ ObjectType *object = nullptr);
+
+// The combination of the following two overloaded methods could trigger a
+// problematic behaviour on the overload decisor, if it isn't working properly.
+// This is a variation of forceDecisorSideB.
+LIBSAMPLE_API void forceDecisorSideB(int a, ObjectType *object = nullptr);
+LIBSAMPLE_API void forceDecisorSideB(int a, const Point &pt, const Str &text,
+ ObjectType *object = nullptr);
+
+// Add a new signature on type system with only a Point value as parameter.
+LIBSAMPLE_API double passReferenceToValueType(const Point &point, double multiplier);
+// Add a new signature on type system with only a ObjectType pointer as parameter.
+LIBSAMPLE_API int passReferenceToObjectType(const ObjectType &obj, int multiplier);
+
+extern LIBSAMPLE_API int variableInNamespace;
+
+} // namespace SampleNamespace
+
+#endif // SAMPLENAMESPACE_H
diff --git a/sources/shiboken6/tests/libsample/sbkdate.cpp b/sources/shiboken6/tests/libsample/sbkdate.cpp
new file mode 100644
index 000000000..fd408f637
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/sbkdate.cpp
@@ -0,0 +1,23 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "sbkdate.h"
+
+SbkDate::SbkDate(int d, int m, int y) : m_d(d), m_m(m), m_y(y)
+{
+}
+
+int SbkDate::day() const
+{
+ return m_d;
+}
+
+int SbkDate::month() const
+{
+ return m_m;
+}
+
+int SbkDate::year() const
+{
+ return m_y;
+}
diff --git a/sources/shiboken6/tests/libsample/sbkdate.h b/sources/shiboken6/tests/libsample/sbkdate.h
new file mode 100644
index 000000000..5e1dd0b84
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/sbkdate.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SBKDATE_H
+#define SBKDATE_H
+
+#include "libsamplemacros.h"
+
+class LIBSAMPLE_API SbkDate
+{
+public:
+ explicit SbkDate(int d, int m, int y);
+
+ int day() const;
+ int month() const;
+ int year() const;
+
+private:
+ int m_d;
+ int m_m;
+ int m_y;
+};
+
+#endif // SBKDATE_H
diff --git a/sources/shiboken6/tests/libsample/simplefile.cpp b/sources/shiboken6/tests/libsample/simplefile.cpp
new file mode 100644
index 000000000..e51b14088
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/simplefile.cpp
@@ -0,0 +1,73 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "simplefile.h"
+
+#include <cstdlib>
+#include <cstdio>
+#include <string>
+#include <filesystem>
+
+class SimpleFilePrivate
+{
+public:
+ LIBMINIMAL_DISABLE_COPY_MOVE(SimpleFilePrivate)
+
+ SimpleFilePrivate(const char *filename) : m_filename(filename) {}
+ ~SimpleFilePrivate() = default;
+
+ std::string m_filename;
+ FILE *m_descriptor = nullptr;
+ long m_size = 0;
+};
+
+SimpleFile::SimpleFile(const char *filename) :
+ p(std::make_unique<SimpleFilePrivate>(filename))
+{
+}
+
+SimpleFile::~SimpleFile()
+{
+ close();
+}
+
+const char *SimpleFile::filename()
+{
+ return p->m_filename.c_str();
+}
+
+long SimpleFile::size() const
+{
+ return p->m_size;
+}
+
+bool SimpleFile::open()
+{
+ auto *descriptor = std::fopen(p->m_filename.c_str(), "rb");
+ if (descriptor == nullptr)
+ return false;
+
+ p->m_descriptor = descriptor;
+ const auto size = std::filesystem::file_size(std::filesystem::path(p->m_filename));
+ p->m_size = long(size);
+
+ return true;
+}
+
+void SimpleFile::close()
+{
+ if (p->m_descriptor != nullptr) {
+ std::fclose(p->m_descriptor);
+ p->m_descriptor = nullptr;
+ }
+}
+
+bool SimpleFile::exists() const
+{
+ return std::filesystem::exists(std::filesystem::path(p->m_filename));
+}
+
+bool SimpleFile::exists(const char *filename)
+{
+ return std::filesystem::exists(std::filesystem::path(filename));
+}
diff --git a/sources/shiboken6/tests/libsample/simplefile.h b/sources/shiboken6/tests/libsample/simplefile.h
new file mode 100644
index 000000000..e4612c944
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/simplefile.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SIMPLEFILE_H
+#define SIMPLEFILE_H
+
+#include "libsamplemacros.h"
+
+#include <memory>
+
+class SimpleFilePrivate;
+
+class LIBSAMPLE_API SimpleFile
+{
+public:
+ LIBMINIMAL_DISABLE_COPY(SimpleFile)
+ LIBMINIMAL_DEFAULT_MOVE(SimpleFile)
+
+ explicit SimpleFile(const char *filename);
+ ~SimpleFile();
+
+ const char *filename();
+ long size() const;
+ bool open();
+ void close();
+
+ bool exists() const;
+ static bool exists(const char *filename);
+
+private:
+ std::unique_ptr<SimpleFilePrivate> p;
+};
+
+#endif // SIMPLEFILE_H
diff --git a/sources/shiboken6/tests/libsample/size.cpp b/sources/shiboken6/tests/libsample/size.cpp
new file mode 100644
index 000000000..0291d6e86
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/size.cpp
@@ -0,0 +1,11 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "size.h"
+
+#include <iostream>
+
+void Size::show() const
+{
+ std::cout << "(width: " << m_width << ", height: " << m_height << ")";
+}
diff --git a/sources/shiboken6/tests/libsample/size.h b/sources/shiboken6/tests/libsample/size.h
new file mode 100644
index 000000000..2d194e96b
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/size.h
@@ -0,0 +1,185 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SIZE_H
+#define SIZE_H
+
+#include "libsamplemacros.h"
+
+class LIBSAMPLE_API Size
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Size)
+
+ explicit Size(double width = 0.0, double height = 0.0) noexcept :
+ m_width(width), m_height(height) {}
+ ~Size() = default;
+
+ inline double width() const { return m_width; }
+ inline void setWidth(double width) { m_width = width; }
+ inline double height() const { return m_height; }
+ inline void setHeight(double height) { m_height = height; }
+
+ inline double calculateArea() const { return m_width * m_height; }
+
+ // Comparison Operators
+ inline bool operator<(const Size &other)
+ {
+ return calculateArea() < other.calculateArea();
+ }
+
+ inline bool operator>(const Size &other)
+ {
+ // On some x86 hardware and compiler combinations, floating point
+ // comparisons may fail due to a hardware bug. One workaround is to
+ // simplify comparison expressions by putting partial results in
+ // variables. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323#c109
+ // for details.
+ double a = calculateArea();
+ double b = other.calculateArea();
+ return a > b;
+ }
+
+ inline bool operator<=(const Size &other)
+ {
+ // See comments for operator>()
+ double a = calculateArea();
+ double b = other.calculateArea();
+ return a <= b;
+ }
+
+ inline bool operator>=(const Size &other)
+ {
+ return calculateArea() >= other.calculateArea();
+ }
+
+ inline bool operator<(double area) { return calculateArea() < area; }
+ inline bool operator>(double area) { return calculateArea() > area; }
+ inline bool operator<=(double area) { return calculateArea() <= area; }
+ inline bool operator>=(double area) { return calculateArea() >= area; }
+
+ // Arithmetic Operators
+ inline Size &operator+=(const Size &s)
+ {
+ m_width += s.m_width;
+ m_height += s.m_height;
+ return *this;
+ }
+
+ inline Size &operator-=(const Size &s)
+ {
+ m_width -= s.m_width;
+ m_height -= s.m_height;
+ return *this;
+ }
+
+ inline Size &operator*=(double mult)
+ {
+ m_width *= mult;
+ m_height *= mult;
+ return *this;
+ }
+
+ inline Size &operator/=(double div)
+ {
+ m_width /= div;
+ m_height /= div;
+ return *this;
+ }
+
+ // TODO: add ++size, size++, --size, size--
+
+ // External operators
+ friend inline bool operator==(const Size&, const Size&);
+ friend inline bool operator!=(const Size&, const Size&);
+ friend inline Size operator+(const Size&, const Size&);
+ friend inline Size operator-(const Size&, const Size&);
+ friend inline Size operator*(const Size&, double);
+ friend inline Size operator*(double, const Size&);
+ friend inline Size operator/(const Size&, double);
+
+ friend inline bool operator<(double, const Size&);
+ friend inline bool operator>(double, const Size&);
+ friend inline bool operator<=(double, const Size&);
+ friend inline bool operator>=(double, const Size&);
+
+ void show() const;
+
+private:
+ double m_width;
+ double m_height;
+};
+
+// Comparison Operators
+inline bool operator!=(const Size &s1, const Size &s2)
+{
+ return s1.m_width != s2.m_width || s1.m_height != s2.m_height;
+}
+
+inline bool operator==(const Size &s1, const Size &s2)
+{
+ return s1.m_width == s2.m_width && s1.m_height == s2.m_height;
+}
+
+inline bool operator<(double area, const Size &s)
+{
+ return area < s.calculateArea();
+}
+
+inline bool operator>(double area, const Size &s)
+{
+ return area > s.calculateArea();
+}
+
+inline bool operator<=(double area, const Size &s)
+{
+ return area <= s.calculateArea();
+}
+
+inline bool operator>=(double area, const Size &s)
+{
+ return area >= s.calculateArea();
+}
+
+// Arithmetic Operators
+inline Size operator+(const Size &s1, const Size &s2)
+{
+ return Size(s1.m_width + s2.m_width, s1.m_height + s2.m_height);
+}
+
+inline Size operator-(const Size &s1, const Size &s2)
+{
+ return Size(s1.m_width - s2.m_width, s1.m_height - s2.m_height);
+}
+
+inline Size operator*(const Size &s, double mult)
+{
+ return Size(s.m_width * mult, s.m_height * mult);
+}
+
+inline Size operator*(double mult, const Size &s)
+{
+ return Size(s.m_width * mult, s.m_height * mult);
+}
+
+inline Size operator/(const Size &s, double div)
+{
+ return Size(s.m_width / div, s.m_height / div);
+}
+
+using real = double;
+using ushort = unsigned short;
+
+class LIBSAMPLE_API SizeF
+{
+public:
+ explicit SizeF(real width, real height) : m_width(width), m_height(height) {}
+ real width() const { return m_width; }
+ real height() const { return m_height; }
+ static inline ushort passTypedefOfUnsignedShort(ushort value) { return value; }
+private:
+ real m_width;
+ real m_height;
+};
+
+#endif // SIZE_H
diff --git a/sources/shiboken6/tests/libsample/snakecasetest.cpp b/sources/shiboken6/tests/libsample/snakecasetest.cpp
new file mode 100644
index 000000000..8240308b4
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/snakecasetest.cpp
@@ -0,0 +1,44 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "snakecasetest.h"
+
+int SnakeCaseGlobalFunction()
+{
+ return 42;
+}
+
+SnakeCaseTest::SnakeCaseTest() = default;
+SnakeCaseTest::~SnakeCaseTest() = default;
+
+int SnakeCaseTest::testFunction1() const
+{
+ return 42;
+}
+
+int SnakeCaseTest::testFunctionDisabled() const
+{
+ return 42;
+}
+
+int SnakeCaseTest::testFunctionBoth() const
+{
+ return 42;
+}
+
+int SnakeCaseTest::callVirtualFunc() const
+{
+ return virtualFunc();
+}
+
+int SnakeCaseTest::virtualFunc() const
+{
+ return 42;
+}
+
+SnakeCaseDerivedTest::SnakeCaseDerivedTest() = default;
+
+int SnakeCaseDerivedTest::virtualFunc() const
+{
+ return 43;
+}
diff --git a/sources/shiboken6/tests/libsample/snakecasetest.h b/sources/shiboken6/tests/libsample/snakecasetest.h
new file mode 100644
index 000000000..757dd23b2
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/snakecasetest.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SNAKECASETEST_H
+#define SNAKECASETEST_H
+
+#include "libsamplemacros.h"
+
+LIBSAMPLE_API int SnakeCaseGlobalFunction();
+
+class LIBSAMPLE_API SnakeCaseTest
+{
+public:
+ SnakeCaseTest();
+ virtual ~SnakeCaseTest();
+
+ int testFunction1() const;
+ int testFunctionDisabled() const;
+ int testFunctionBoth() const;
+
+ int callVirtualFunc() const;
+
+ int testField = 42;
+ int testFieldDisabled = 42;
+ int testFieldBoth = 42;
+
+protected:
+ virtual int virtualFunc() const;
+};
+
+class LIBSAMPLE_API SnakeCaseDerivedTest : public SnakeCaseTest
+{
+public:
+ SnakeCaseDerivedTest();
+
+protected:
+ int virtualFunc() const override;
+};
+
+#endif // SNAKECASETEST_H
diff --git a/sources/shiboken6/tests/libsample/sometime.cpp b/sources/shiboken6/tests/libsample/sometime.cpp
new file mode 100644
index 000000000..ad9a0d81c
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/sometime.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "sometime.h"
+
+#include <cstdio>
+
+void Time::setTime()
+{
+ m_hour = 0;
+ m_minute = 0;
+ m_second = 0;
+ m_msec = 0;
+ m_is_null = true;
+}
+
+void Time::setTime(int h, int m, int s, int ms)
+{
+ m_hour = h;
+ m_minute = m;
+ m_second = s;
+ m_msec = ms;
+ m_is_null = false;
+}
+
+Time::NumArgs Time::somethingCompletelyDifferent()
+{
+ return ZeroArgs;
+}
+
+Time::NumArgs Time::somethingCompletelyDifferent(int, int, ImplicitConv ic, ObjectType *type)
+{
+ if (type)
+ return FourArgs;
+ if (ic.ctorEnum() == ImplicitConv::CtorThree && ic.objId() == -1)
+ return TwoArgs;
+ return ThreeArgs;
+}
+
+Str Time::toString() const
+{
+ if (m_is_null)
+ return Str();
+ char buffer[13];
+ std::snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d.%03d",
+ m_hour, m_minute, m_second, m_msec);
+ return Str(buffer);
+}
+
+bool Time::operator==(const Time &other) const
+{
+ return m_hour == other.m_hour
+ && m_minute == other.m_minute
+ && m_second == other.m_second
+ && m_msec == other.m_msec
+ && m_is_null == other.m_is_null;
+}
+
+bool Time::operator!=(const Time &other) const
+{
+ return !operator==(other);
+}
+
+Time::operator Str() const
+{
+ return Time::toString();
+}
diff --git a/sources/shiboken6/tests/libsample/sometime.h b/sources/shiboken6/tests/libsample/sometime.h
new file mode 100644
index 000000000..575d4b136
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/sometime.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SOMETIME_H
+#define SOMETIME_H
+
+#include "libsamplemacros.h"
+#include "str.h"
+#include "implicitconv.h"
+#include "objecttype.h"
+
+class LIBSAMPLE_API Time
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(Time)
+
+ enum NumArgs {
+ ZeroArgs,
+ TwoArgs,
+ ThreeArgs,
+ FourArgs
+ };
+
+ Time() noexcept = default;
+ explicit Time(int h, int m, int s = 0, int ms = 0) noexcept:
+ m_hour(h), m_minute(m), m_second(s), m_msec(ms), m_is_null(false)
+ {}
+
+ ~Time() = default;
+
+ inline bool isNull() const { return m_is_null; }
+
+ inline int hour() const { return m_hour; }
+ inline int minute() const { return m_minute; }
+ inline int second() const { return m_second; }
+ inline int msec() const { return m_msec; }
+
+ void setTime();
+ void setTime(int h, int m, int s = 0, int ms = 0);
+
+ // This one is completely different from the other methods in this class,
+ // it was added to give the overload decisor a really hard time with
+ // an value-type with implicit conversion and a default argument, and also
+ // an object-type, just because I feel like it.
+ NumArgs somethingCompletelyDifferent();
+ NumArgs somethingCompletelyDifferent(int h, int m,
+ ImplicitConv ic = ImplicitConv::CtorThree,
+ ObjectType *type = nullptr);
+
+ Str toString() const;
+ bool operator==(const Time &other) const;
+ bool operator!=(const Time &other) const;
+
+ // This cast operator must become an implicit conversion of Str.
+ operator Str() const;
+
+private:
+ int m_hour = 0;
+ int m_minute = 0;
+ int m_second = 0;
+ int m_msec = 0;
+
+ bool m_is_null = true;
+};
+
+#endif // SOMETIME_H
diff --git a/sources/shiboken6/tests/libsample/stdcomplex.cpp b/sources/shiboken6/tests/libsample/stdcomplex.cpp
new file mode 100644
index 000000000..847174387
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/stdcomplex.cpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "stdcomplex.h"
+
+#include <iostream>
+
+StdComplex::StdComplex() noexcept = default;
+
+StdComplex::StdComplex(double re, double img) noexcept : m_impl(re, img)
+{
+}
+
+StdComplex::operator int() const
+{
+ return std::lround(abs_value());
+}
+
+StdComplex::StdComplex(const Impl &impl) noexcept : m_impl(impl)
+{
+}
+
+StdComplex StdComplex::pow(const StdComplex &exp) const
+{
+ return StdComplex(std::pow(m_impl, exp.m_impl));
+}
+
+std::ostream &operator<<(std::ostream &str, const StdComplex &c)
+{
+ str << "Complex(" << c.real() << ", " << c.imag() << ')';
+ return str;
+}
diff --git a/sources/shiboken6/tests/libsample/stdcomplex.h b/sources/shiboken6/tests/libsample/stdcomplex.h
new file mode 100644
index 000000000..b39b80612
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/stdcomplex.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef STDCOMPLEX_H
+#define STDCOMPLEX_H
+
+#include "libsamplemacros.h"
+
+#include <complex>
+#include <iosfwd>
+
+// A complex number based on std::complex for exercising esoteric number
+// protocols (Py_nb_). For standard number protocols, see Point.
+
+class LIBSAMPLE_API StdComplex
+{
+ using Impl = std::complex<double>;
+
+public:
+ StdComplex() noexcept;
+ explicit StdComplex(double re, double img) noexcept;
+
+ double real() const { return m_impl.real(); }
+ double imag() const { return m_impl.imag(); }
+
+ double abs_value() const { return std::abs(m_impl); } // abs() is reserved Python word
+
+ StdComplex pow(const StdComplex &exp) const;
+
+ operator double() const { return abs_value(); }
+ operator int() const;
+
+ friend inline bool operator==(const StdComplex &c1, const StdComplex &c2) noexcept
+ { return c1.m_impl == c2.m_impl; }
+ friend inline bool operator!=(const StdComplex &c1, const StdComplex &c2) noexcept
+ { return c1.m_impl != c2.m_impl; }
+
+ friend inline StdComplex operator+(const StdComplex &c1, const StdComplex &c2) noexcept
+ { return StdComplex(c1.m_impl + c2.m_impl); }
+ friend inline StdComplex operator-(const StdComplex &c1, const StdComplex &c2) noexcept
+ { return StdComplex(c1.m_impl - c2.m_impl); }
+ friend inline StdComplex operator*(const StdComplex &c1, const StdComplex &c2) noexcept
+ { return StdComplex(c1.m_impl * c2.m_impl); }
+ friend inline StdComplex operator/(const StdComplex &c1, const StdComplex &c2) noexcept
+ { return StdComplex(c1.m_impl / c2.m_impl); }
+
+private:
+ explicit StdComplex(const Impl &impl) noexcept;
+
+ Impl m_impl;
+};
+
+std::ostream &operator<<(std::ostream &str, const StdComplex &c);
+
+#endif // STDCOMPLEX_H
diff --git a/sources/shiboken6/tests/libsample/str.cpp b/sources/shiboken6/tests/libsample/str.cpp
new file mode 100644
index 000000000..742c0bb01
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/str.cpp
@@ -0,0 +1,137 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "str.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+
+Str::Str(char c)
+{
+ char str[2] = { c, 0 };
+ init(str);
+}
+
+Str::Str(const char *cstr)
+{
+ init(cstr);
+}
+
+void Str::init(const char *cstr)
+{
+ if (cstr)
+ m_str = cstr;
+}
+
+Str Str::arg(const Str &s) const
+{
+ size_t idx = m_str.find_first_of("%VAR");
+ if (idx == std::string::npos)
+ return *this;
+
+ std::string result = m_str;
+ result.replace(idx, 4, s.m_str);
+ return result.c_str();
+}
+
+Str &Str::append(const Str &s)
+{
+ m_str += s.m_str;
+ return *this;
+}
+
+Str &Str::prepend(const Str &s)
+{
+ m_str = s.m_str + m_str;
+ return *this;
+}
+
+const char *Str::cstring() const
+{
+ return m_str.c_str();
+}
+
+int Str::toInt(bool *ok, int base) const
+{
+ int result = 0;
+ std::istringstream conv(m_str);
+ switch (base) {
+ case 8:
+ conv >> std::oct >> result;
+ break;
+ case 10:
+ conv >> std::dec >> result;
+ break;
+ case 16:
+ conv >> std::hex >> result;
+ break;
+ }
+ const bool my_ok = std::istringstream::eofbit & conv.rdstate();
+ if (!my_ok)
+ result = 0;
+ if (ok)
+ *ok = my_ok;
+ return result;
+}
+
+void Str::show() const
+{
+ std::printf("%s", cstring());
+}
+
+char Str::get_char(int pos) const
+{
+ return m_str[pos];
+}
+
+bool Str::set_char(int pos, char ch)
+{
+ m_str[pos] = ch;
+ return true;
+}
+
+Str Str::operator+(int number) const
+{
+ std::ostringstream in;
+ in << m_str << number;
+ return in.str().c_str();
+}
+
+bool Str::operator==(const Str &other) const
+{
+ return m_str == other.m_str;
+}
+
+Str operator+(int number, const Str &str)
+{
+ std::ostringstream in;
+ in << number << str.m_str;
+ return in.str().c_str();
+}
+
+bool Str::operator<(const Str &other) const
+{
+ return m_str < other.m_str;
+}
+
+unsigned int strHash(const Str &str)
+{
+ unsigned int result = 0;
+ for (char c : str.m_str)
+ result = 5U * result + unsigned(c);
+ return result;
+}
+
+void changePStr(PStr *pstr, const char *suffix)
+{
+ pstr->append(suffix);
+}
+
+void duplicatePStr(PStr *pstr)
+{
+ if (!pstr)
+ return;
+ pstr->append(*pstr);
+}
diff --git a/sources/shiboken6/tests/libsample/str.h b/sources/shiboken6/tests/libsample/str.h
new file mode 100644
index 000000000..6b3386cef
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/str.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef STR_H
+#define STR_H
+
+#include "libsamplemacros.h"
+
+#include <string>
+
+class LIBSAMPLE_API Str
+{
+public:
+ Str(char c);
+ Str(const char *cstr = "");
+
+ Str arg(const Str &s) const;
+
+ Str &append(const Str &s);
+ Str &prepend(const Str &s);
+
+ const char *cstring() const;
+ char get_char(int pos) const;
+ bool set_char(int pos, char ch);
+
+ int toInt(bool *ok = nullptr, int base = 10) const;
+
+ void show() const;
+
+ inline int size() const { return int(m_str.size()); }
+
+ // nonsense operator just to test reverse operators
+ Str operator+(int number) const;
+ bool operator==(const Str &other) const;
+ bool operator<(const Str &other) const;
+
+private:
+ void init(const char *cstr);
+ std::string m_str;
+
+ friend LIBSAMPLE_API Str operator+(int number, const Str &str);
+ friend LIBSAMPLE_API unsigned int strHash(const Str &str);
+};
+
+LIBSAMPLE_API Str operator+(int number, const Str &str);
+LIBSAMPLE_API unsigned int strHash(const Str &str);
+
+using PStr = Str;
+LIBSAMPLE_API void changePStr(PStr *pstr, const char *suffix);
+LIBSAMPLE_API void duplicatePStr(PStr *pstr = nullptr);
+
+#endif // STR_H
diff --git a/sources/shiboken6/tests/libsample/strlist.cpp b/sources/shiboken6/tests/libsample/strlist.cpp
new file mode 100644
index 000000000..5840a0516
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/strlist.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "strlist.h"
+
+#include <algorithm>
+
+bool StrList::operator==(const std::list<Str> &other) const
+{
+ return size() == other.size()
+ && std::equal(begin(), end(), other.begin());
+}
+
+Str StrList::join(const Str &sep) const
+{
+ Str result;
+ const auto i1 = begin();
+ const auto i2 = end();
+ for (auto it = i1; i1 != i2; ++it) {
+ if (it != i1)
+ result.append(sep);
+ result.append(*it);
+ }
+ return result;
+}
diff --git a/sources/shiboken6/tests/libsample/strlist.h b/sources/shiboken6/tests/libsample/strlist.h
new file mode 100644
index 000000000..01865a5b4
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/strlist.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef STRLIST_H
+#define STRLIST_H
+
+#include "libsamplemacros.h"
+#include "str.h"
+
+#include <list>
+
+class LIBSAMPLE_API StrList : public std::list<Str>
+{
+public:
+ enum CtorEnum {
+ NoParamsCtor,
+ StrCtor,
+ CopyCtor,
+ ListOfStrCtor
+ };
+
+ inline StrList() = default;
+ inline StrList(const std::list<Str> &lst) :
+ std::list<Str>(lst), m_ctorUsed(ListOfStrCtor) {}
+ inline explicit StrList(const Str &str) :
+ m_ctorUsed(StrCtor) { push_back(str); }
+ inline StrList(const StrList &lst) :
+ std::list<Str>(lst), m_ctorUsed(CopyCtor) {}
+
+ StrList(StrList &&) = default;
+ StrList &operator=(const StrList &) = default;
+ StrList &operator=(StrList &&) = default;
+ ~StrList() = default;
+
+ inline void append(const Str &str) { push_back(str); }
+ Str join(const Str &sep) const;
+
+ bool operator==(const std::list<Str> &other) const;
+ inline bool operator!=(const std::list<Str> &other) const { return !(*this == other); }
+
+ CtorEnum constructorUsed() const { return m_ctorUsed; }
+
+private:
+ CtorEnum m_ctorUsed = NoParamsCtor;
+};
+
+using PStrList = StrList;
+
+#endif // STRLIST_H
diff --git a/sources/shiboken6/tests/libsample/templateptr.cpp b/sources/shiboken6/tests/libsample/templateptr.cpp
new file mode 100644
index 000000000..a73f78417
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/templateptr.cpp
@@ -0,0 +1,8 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "templateptr.h"
+
+void TemplatePtr::dummy(std::list<std::pair<BlackBox *, BlackBox *> > &)
+{
+}
diff --git a/sources/shiboken6/tests/libsample/templateptr.h b/sources/shiboken6/tests/libsample/templateptr.h
new file mode 100644
index 000000000..bf230c363
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/templateptr.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TEMPLATEPTR_H
+#define TEMPLATEPTR_H
+
+#include "libsamplemacros.h"
+#include "blackbox.h"
+
+#include <utility>
+#include <list>
+
+class LIBSAMPLE_API TemplatePtr
+{
+public:
+ void dummy(std::list<std::pair<BlackBox *, BlackBox *> > &items);
+};
+
+#endif // TEMPLATEPTR_H
diff --git a/sources/shiboken6/tests/libsample/transform.cpp b/sources/shiboken6/tests/libsample/transform.cpp
new file mode 100644
index 000000000..5ccf5d1ed
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/transform.cpp
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2013 Kitware, Inc.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "transform.h"
+
+#include <cmath>
+
+Point applyHomogeneousTransform(const Point &in,
+ double m11, double m12, double m13,
+ double m21, double m22, double m23,
+ double m31, double m32, double m33,
+ bool *okay)
+{
+ double x = m11 * in.x() + m12 * in.y() + m13;
+ double y = m21 * in.x() + m22 * in.y() + m23;
+ double w = m31 * in.x() + m32 * in.y() + m33;
+
+ if (std::isfinite(w) && fabs(w) > 1e-10) {
+ if (okay)
+ *okay = true;
+ return {x / w, y / w};
+ }
+
+ if (okay)
+ *okay = false;
+ return {};
+}
diff --git a/sources/shiboken6/tests/libsample/transform.h b/sources/shiboken6/tests/libsample/transform.h
new file mode 100644
index 000000000..34ebf40d3
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/transform.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2013 Kitware, Inc.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TRANSFORM_H
+#define TRANSFORM_H
+
+#include "point.h"
+
+#include "libsamplemacros.h"
+
+LIBSAMPLE_API Point applyHomogeneousTransform(const Point &in,
+ double m11, double m12, double m13,
+ double m21, double m22, double m23,
+ double m31, double m32, double m33,
+ bool *okay);
+
+#endif // TRANSFORM_H
diff --git a/sources/shiboken6/tests/libsample/typesystypedef.cpp b/sources/shiboken6/tests/libsample/typesystypedef.cpp
new file mode 100644
index 000000000..d9c9a92fc
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/typesystypedef.cpp
@@ -0,0 +1,12 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "typesystypedef.h"
+
+ValueWithUnitUser::ValueWithUnitUser() = default;
+
+ValueWithUnit<double, LengthUnit::Millimeter>
+ ValueWithUnitUser::doubleInchToMillimeter(ValueWithUnit<double, LengthUnit::Inch> v)
+{
+ return ValueWithUnit<double, LengthUnit::Millimeter>(v.value() * 254);
+}
diff --git a/sources/shiboken6/tests/libsample/typesystypedef.h b/sources/shiboken6/tests/libsample/typesystypedef.h
new file mode 100644
index 000000000..be42fbefe
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/typesystypedef.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TYPESYSTYPEDEF_H
+#define TYPESYSTYPEDEF_H
+
+#include "libsamplemacros.h"
+
+enum class LengthUnit { Millimeter, Inch };
+
+template <class T, LengthUnit Unit>
+class ValueWithUnit
+{
+ public:
+ explicit ValueWithUnit(T value = {}) : m_value(value) {}
+
+ T value() const { return m_value; }
+ void setValue(const T &value) { m_value = value; }
+
+private:
+ T m_value;
+};
+
+class LIBSAMPLE_API ValueWithUnitUser
+{
+public:
+ ValueWithUnitUser();
+
+ static ValueWithUnit<double, LengthUnit::Millimeter> doubleInchToMillimeter(ValueWithUnit<double, LengthUnit::Inch>);
+};
+
+#endif // TYPESYSTYPEDEF_H
diff --git a/sources/shiboken6/tests/libsample/valueandvirtual.h b/sources/shiboken6/tests/libsample/valueandvirtual.h
new file mode 100644
index 000000000..799e11e40
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/valueandvirtual.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef VALUEANDVIRTUAL_H
+#define VALUEANDVIRTUAL_H
+
+#include "libsamplemacros.h"
+
+class ValueAndVirtual
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(ValueAndVirtual)
+
+ explicit ValueAndVirtual(int id) noexcept : m_id(id) {}
+ virtual ~ValueAndVirtual() = default;
+
+ bool operator()(int id, int id2) { return id == id2; }
+
+ inline int id() const { return m_id; }
+
+private:
+ int m_id;
+};
+
+#endif // VALUEANDVIRTUAL_H
diff --git a/sources/shiboken6/tests/libsample/virtualmethods.cpp b/sources/shiboken6/tests/libsample/virtualmethods.cpp
new file mode 100644
index 000000000..515564664
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/virtualmethods.cpp
@@ -0,0 +1,66 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "virtualmethods.h"
+
+int VirtualDtor::dtor_called = 0;
+
+double VirtualMethods::virtualMethod0(Point pt, int val, Complex cpx, bool b)
+{
+ return (pt.x() * pt.y() * val) + cpx.imag() + ((int) b);
+}
+
+bool VirtualMethods::createStr(const char *text, Str *&ret)
+{
+ if (!text) {
+ ret = nullptr;
+ return false;
+ }
+
+ ret = new Str(text);
+ return true;
+}
+
+void VirtualMethods::getMargins(int *left, int *top, int *right, int *bottom) const
+{
+ *left = m_left;
+ *top = m_top;
+ *right = m_right;
+ *bottom = m_bottom;
+}
+
+int VirtualMethods::recursionOnModifiedVirtual(Str) const
+{
+ return 0;
+}
+
+const Str & VirtualMethods::returnConstRef() const
+{
+ static const Str result;
+ return result;
+}
+
+int VirtualMethods::stringViewLength(std::string_view in) const
+{
+ return int(in.size());
+}
+
+double VirtualDaughter2::virtualMethod0(Point pt, int val, Complex cpx, bool b)
+{
+ return 42 + VirtualMethods::virtualMethod0(pt, val, cpx, b);
+}
+
+int VirtualDaughter2::sum0(int a0, int a1, int a2)
+{
+ return 42 + VirtualMethods::sum0(a0, a1, a2);
+}
+
+double VirtualFinalDaughter::virtualMethod0(Point pt, int val, Complex cpx, bool b)
+{
+ return 42 + VirtualMethods::virtualMethod0(pt, val, cpx, b);
+}
+
+int VirtualFinalDaughter::sum0(int a0, int a1, int a2)
+{
+ return 42 + VirtualMethods::sum0(a0, a1, a2);
+}
diff --git a/sources/shiboken6/tests/libsample/virtualmethods.h b/sources/shiboken6/tests/libsample/virtualmethods.h
new file mode 100644
index 000000000..b7172ad0d
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/virtualmethods.h
@@ -0,0 +1,145 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef VIRTUALMETHODS_H
+#define VIRTUALMETHODS_H
+
+#include "point.h"
+#include "complex.h"
+#include "str.h"
+
+#include "libsamplemacros.h"
+#include "strlist.h"
+
+#include <string_view>
+#include <string>
+
+class LIBSAMPLE_API VirtualMethods
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(VirtualMethods)
+
+ explicit VirtualMethods(Str name = "VirtualMethods") : m_name(name) {}
+ virtual ~VirtualMethods() = default;
+
+ virtual double virtualMethod0(Point pt, int val, Complex cpx, bool b);
+ double callVirtualMethod0(Point pt, int val, Complex cpx, bool b)
+ {
+ return virtualMethod0(pt, val, cpx, b);
+ }
+
+ // Binding modification: rename.
+ virtual int sum0(int a0, int a1, int a2) { return a0 + a1 + a2; }
+ int callSum0(int a0, int a1, int a2) { return sum0(a0, a1, a2); }
+
+ // Binding modification: set default value for the last argument.
+ virtual int sum1(int a0, int a1, int a2) { return a0 + a1 + a2; }
+ int callSum1(int a0, int a1, int a2) { return sum1(a0, a1, a2); }
+
+ // Binding modification: remove the last argument and set a default value for it.
+ virtual int sum2(int a0, int a1, int a2) { return a0 + a1 + a2; }
+ int callSum2(int a0, int a1, int a2) { return sum2(a0, a1, a2); }
+
+ // Binding modification: remove the second argument.
+ virtual int sum3(int a0, int a1, int a2) { return a0 + a1 + a2; }
+ int callSum3(int a0, int a1, int a2) { return sum3(a0, a1, a2); }
+
+ // Binding modification: remove the second argument and set its default
+ // value, then inject code on the binding reimplementation of the virtual
+ // (with a native inject-code) to sum the value of the removed
+ // argument to the first argument before the method is called.
+ virtual int sum4(int a0, int a1, int a2) { return a0 + a1 + a2; }
+ int callSum4(int a0, int a1, int a2) { return sum4(a0, a1, a2); }
+
+ // Binding modification: prepend a string to the results of a Python override.
+ virtual Str name() { return m_name; }
+ Str callName() { return name(); }
+
+ // Binding modification: code injection that calls the Python override by itself.
+ virtual void callMe() {}
+ void callCallMe() { callMe(); }
+
+ // Passing reference to pointers.
+ virtual bool createStr(const char *text, Str *&ret);
+ bool callCreateStr(const char *text, Str *&ret) { return createStr(text, ret); }
+
+ // Return a non-binded method
+ std::list<Str> callStrListToStdList(const StrList &strList)
+ { return strListToStdList(strList); }
+ virtual std::list<Str> strListToStdList(const StrList &strList )
+ { return strList; }
+
+ void setMargins(int left, int top, int right, int bottom)
+ {
+ m_left = left;
+ m_top = top;
+ m_right = right;
+ m_bottom = bottom;
+ }
+ virtual void getMargins(int *left, int *top, int *right, int *bottom) const;
+ void callGetMargins(int *left, int *top, int *right, int *bottom) const
+ {
+ getMargins(left, top, right, bottom);
+ }
+
+ virtual int recursionOnModifiedVirtual(Str arg) const;
+ int callRecursionOnModifiedVirtual(Str arg) const { return recursionOnModifiedVirtual(arg); }
+
+ virtual const Str &returnConstRef() const;
+
+ virtual int stringViewLength(std::string_view in) const;
+
+protected:
+ // PYSIDE-1388: Protected hack with final classes (see VirtualFinalDaughter).
+ void protectedMethod() {}
+
+private:
+ Str m_name;
+ int m_left = 0;
+ int m_top = 0;
+ int m_right = 0;
+ int m_bottom = 0;
+};
+
+class LIBSAMPLE_API VirtualDaughter : public VirtualMethods
+{
+public:
+ VirtualDaughter() : VirtualMethods() {}
+ VirtualDaughter(Str name) : VirtualMethods(name) {}
+};
+
+class LIBSAMPLE_API VirtualDaughter2 : public VirtualMethods
+{
+public:
+ VirtualDaughter2() : VirtualMethods("VirtualDaughter2") {}
+
+ double virtualMethod0(Point pt, int val, Complex cpx, bool b) override;
+ int sum0(int a0, int a1, int a2) final;
+};
+
+class LIBSAMPLE_API VirtualFinalDaughter final : public VirtualMethods
+{
+public:
+ VirtualFinalDaughter() : VirtualMethods("VirtualFinalDaughter") {}
+
+ double virtualMethod0(Point pt, int val, Complex cpx, bool b) override;
+ int sum0(int a0, int a1, int a2) override;
+};
+
+class LIBSAMPLE_API VirtualDtor
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(VirtualDtor)
+
+ VirtualDtor() noexcept = default;
+ virtual ~VirtualDtor() { dtor_called++; }
+
+ static VirtualDtor *create() { return new VirtualDtor(); }
+ static int dtorCalled() { return dtor_called; }
+ static void resetDtorCounter() { dtor_called = 0; }
+
+private:
+ static int dtor_called;
+};
+
+#endif // VIRTUALMETHODS_H
diff --git a/sources/shiboken6/tests/libsample/voidholder.h b/sources/shiboken6/tests/libsample/voidholder.h
new file mode 100644
index 000000000..3f0f4d973
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/voidholder.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef VOIDHOLDER_H
+#define VOIDHOLDER_H
+
+#include "libsamplemacros.h"
+
+class VoidHolder
+{
+public:
+ LIBMINIMAL_DEFAULT_COPY_MOVE(VoidHolder)
+
+ explicit VoidHolder(void *ptr = nullptr) noexcept : m_ptr(ptr) {}
+ ~VoidHolder() = default;
+
+ inline void *voidPointer() { return m_ptr; }
+ inline static void *gimmeMeSomeVoidPointer()
+ {
+ static void *pointerToSomething = new VoidHolder();
+ return pointerToSomething;
+ }
+ void *takeVoidPointer(void *item)
+ {
+ return item;
+ }
+
+private:
+ void *m_ptr;
+};
+
+#endif // VOIDHOLDER_H
diff --git a/sources/shiboken6/tests/libsmart/CMakeLists.txt b/sources/shiboken6/tests/libsmart/CMakeLists.txt
new file mode 100644
index 000000000..95f0cffd6
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(libsmart)
+
+set(libsmart_SRC
+libsmartmacros.h
+smart.cpp smart.h
+smart_integer.h
+smart_obj.h
+smart_registry.h
+smart_sharedptr.h
+smart_test.h
+stdoptionaltestbench.cpp stdoptionaltestbench.h
+stdsharedptrtestbench.cpp stdsharedptrtestbench.h
+stduniqueptrtestbench.cpp stduniqueptrtestbench.h
+)
+
+add_library(libsmart SHARED ${libsmart_SRC})
+target_include_directories(libsmart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_compile_definitions(libsmart PRIVATE LIBSMART_BUILD)
+set_property(TARGET libsmart PROPERTY PREFIX "")
+
diff --git a/sources/shiboken6/tests/libsmart/libsmartmacros.h b/sources/shiboken6/tests/libsmart/libsmartmacros.h
new file mode 100644
index 000000000..c1f229b6c
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/libsmartmacros.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef LIB_SMART_MACROS_H
+#define LIB_SMART_MACROS_H
+
+#include "../libminimal/libminimalmacros.h"
+
+#define LIB_SMART_EXPORT LIBMINIMAL_EXPORT
+#define LIB_SMART_IMPORT LIBMINIMAL_IMPORT
+
+#ifdef LIBSMART_BUILD
+# define LIB_SMART_API LIB_SMART_EXPORT
+#else
+# define LIB_SMART_API LIB_SMART_IMPORT
+#endif
+
+#endif // LIB_SMART_MACROS_H
diff --git a/sources/shiboken6/tests/libsmart/smart.cpp b/sources/shiboken6/tests/libsmart/smart.cpp
new file mode 100644
index 000000000..2273040f9
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/smart.cpp
@@ -0,0 +1,272 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "smart.h"
+
+#include <algorithm>
+#include <iostream>
+
+static inline bool verbose()
+{
+ return Registry::getInstance()->verbose();
+}
+
+void SharedPtrBase::logDefaultConstructor(const char *instantiation, const void *t)
+{
+ if (verbose())
+ std::cout << "SharedPtr<" << instantiation << "> default constructor " << t << '\n';
+}
+
+void SharedPtrBase::logConstructor(const char *instantiation, const void *t,
+ const void *pointee)
+{
+ if (verbose()) {
+ std::cout << "SharedPtr<" << instantiation << "> constructor "
+ << t << " with pointer " << pointee << '\n';
+ }
+}
+
+void SharedPtrBase::logCopyConstructor(const char *instantiation, const void *t,
+ const void *refData)
+{
+ if (verbose()) {
+ std::cout << "SharedPtr<" << instantiation << ">) copy constructor "
+ << t << " with pointer " << refData << '\n';
+ }
+}
+
+void SharedPtrBase::logAssignment(const char *instantiation, const void *t, const void *refData)
+{
+ if (verbose()) {
+ std::cout << "SharedPtr<" << instantiation << ">::operator= " << t
+ << " with pointer " << refData << "\n";
+ }
+}
+
+void SharedPtrBase::logDestructor(const char *instantiation, const void *t,
+ int remainingRefCount)
+{
+ if (verbose()) {
+ std::cout << "~SharedPtr<" << instantiation << "> " << t << ", remaining refcount "
+ << remainingRefCount << '\n';
+ }
+}
+
+Obj::Obj() : m_integer(123), m_internalInteger(new Integer)
+{
+ Registry::getInstance()->add(this);
+ if (verbose())
+ std::cout << "Obj constructor " << this << '\n';
+}
+
+Obj::~Obj()
+{
+ Registry::getInstance()->remove(this);
+ delete m_internalInteger;
+ if (verbose())
+ std::cout << "~Obj " << this << '\n';
+}
+
+
+void Obj::printObj() {
+ if (verbose()) {
+ std::cout << "Obj::printObj(): integer value: " << m_integer
+ << " internal integer value: " << m_internalInteger->value() << '\n';
+ }
+}
+
+
+SharedPtr<Obj> Obj::createSharedPtrObj()
+{
+ SharedPtr<Obj> o(new Obj);
+ return o;
+}
+
+std::vector<SharedPtr<Obj> > Obj::createSharedPtrObjList(int size)
+{
+ std::vector<SharedPtr<Obj> > r;
+ for (int i=0; i < size; i++)
+ r.push_back(createSharedPtrObj());
+ return r;
+}
+
+
+SharedPtr<Integer> Obj::createSharedPtrInteger()
+{
+ SharedPtr<Integer> o(new Integer);
+ return o;
+}
+
+SharedPtr<Smart::Integer2> Obj::createSharedPtrInteger2()
+{
+ SharedPtr<Smart::Integer2> o(new Smart::Integer2);
+ return o;
+}
+
+int Obj::takeSharedPtrToObj(SharedPtr<Obj> pObj)
+{
+ pObj->printObj();
+ return pObj->m_integer;
+}
+
+int Obj::takeSharedPtrToInteger(SharedPtr<Integer> pInt)
+{
+ if (pInt.isNull()) {
+ std::cout << "SharedPtr<Integer>(nullptr) passed!\n";
+ return -1;
+ }
+ pInt->printInteger();
+ return pInt->value();
+}
+
+int Obj::takeSharedPtrToIntegerByConstRef(const SharedPtr<Integer> &pInt)
+{
+ if (pInt.isNull()) {
+ std::cout << "SharedPtr<Integer>(nullptr) passed!\n";
+ return -1;
+ }
+ pInt->printInteger();
+ return pInt->value();
+}
+
+SharedPtr<Integer> Obj::createSharedPtrInteger(int value)
+{
+ auto *i = new Integer;
+ i->setValue(value);
+ return SharedPtr<Integer>(i);
+}
+
+SharedPtr<Integer> Obj::createNullSharedPtrInteger()
+{
+ return {};
+}
+
+SharedPtr<const Integer> Obj::createSharedPtrConstInteger()
+{
+ SharedPtr<const Integer> co(new Integer);
+ return co;
+}
+
+int Obj::takeSharedPtrToConstInteger(SharedPtr<const Integer> pInt)
+{
+ return pInt->m_int;
+}
+
+Integer Obj::takeInteger(Integer val)
+{
+ return val;
+}
+
+Integer::Integer() : m_int(456)
+{
+ Registry::getInstance()->add(this);
+ if (verbose())
+ std::cout << "Integer constructor " << this << '\n';
+}
+
+Integer::Integer(const Integer &other)
+{
+ Registry::getInstance()->add(this);
+ if (verbose())
+ std::cout << "Integer copy constructor " << this << '\n';
+ m_int = other.m_int;
+}
+
+Integer &Integer::operator=(const Integer &other)
+{
+ Registry::getInstance()->add(this);
+ if (verbose())
+ std::cout << "Integer operator= " << this << '\n';
+ m_int = other.m_int;
+ return *this;
+}
+
+Integer::~Integer()
+{
+ Registry::getInstance()->remove(this);
+ if (verbose())
+ std::cout << "~Integer " << this << " (" << m_int << ")\n";
+}
+
+int Integer::value() const
+{
+ return m_int;
+}
+
+void Integer::setValue(int v)
+{
+ m_int = v;
+ if (verbose())
+ std::cout << "Integer::setValue(" << v << ") " << this << '\n';
+}
+
+int Integer::compare(const Integer &rhs) const
+{
+ if (m_int < rhs.m_int)
+ return -1;
+ return m_int > rhs.m_int ? 1 : 0;
+}
+
+void Integer::printInteger() const
+{
+ if (verbose())
+ std::cout << "Integer value for object " << this << " is " << m_int << '\n';
+}
+
+Registry *Registry::getInstance()
+{
+ static Registry registry;
+ return &registry;
+}
+
+Registry::Registry() = default;
+
+Registry::~Registry() = default;
+
+void Registry::add(Obj *p)
+{
+ m_objects.push_back(p);
+}
+
+void Registry::add(Integer *p)
+{
+ m_integers.push_back(p);
+}
+
+void Registry::remove(Obj *p)
+{
+ m_objects.erase(std::remove(m_objects.begin(), m_objects.end(), p), m_objects.end());
+}
+
+void Registry::remove(Integer *p)
+{
+ m_integers.erase(std::remove(m_integers.begin(), m_integers.end(), p), m_integers.end());
+}
+
+int Registry::countObjects() const
+{
+ return static_cast<int>(m_objects.size());
+}
+
+int Registry::countIntegers() const
+{
+ return static_cast<int>(m_integers.size());
+}
+
+bool Registry::verbose() const
+{
+ return m_verbose;
+}
+
+void Registry::setVerbose(bool flag)
+{
+ m_verbose = flag;
+}
+
+Smart::Integer2::Integer2()
+ : Integer ()
+{
+}
+
+Smart::Integer2::Integer2(const Smart::Integer2 &) = default;
+Smart::Integer2 &Smart::Integer2::operator=(const Integer2 &) = default;
diff --git a/sources/shiboken6/tests/libsmart/smart.h b/sources/shiboken6/tests/libsmart/smart.h
new file mode 100644
index 000000000..1f610b302
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/smart.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SMART_H
+#define SMART_H
+
+#include "smart_sharedptr.h"
+#include "smart_integer.h"
+#include "smart_obj.h"
+#include "smart_registry.h"
+#include "smart_test.h"
+#include "stdsharedptrtestbench.h"
+#include "stdoptionaltestbench.h"
+#include "stduniqueptrtestbench.h"
+
+#endif // SMART_H
diff --git a/sources/shiboken6/tests/libsmart/smart_integer.h b/sources/shiboken6/tests/libsmart/smart_integer.h
new file mode 100644
index 000000000..42a441a00
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/smart_integer.h
@@ -0,0 +1,69 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SMART_INTEGER_H
+#define SMART_INTEGER_H
+
+#include "libsmartmacros.h"
+
+class LIB_SMART_API Integer {
+public:
+ Integer();
+ Integer(const Integer &other);
+ Integer &operator=(const Integer &other);
+ Integer(Integer &&other) noexcept = default;
+ Integer &operator=(Integer &&other) noexcept = default;
+ ~Integer();
+ void printInteger() const;
+
+ int value() const;
+ void setValue(int v);
+
+ int compare(const Integer &rhs) const;
+
+ int m_int; // public for testing member field access.
+};
+
+inline bool operator==(const Integer &lhs, const Integer &rhs)
+{
+ return lhs.compare(rhs) == 0;
+}
+
+inline bool operator!=(const Integer &lhs, const Integer &rhs)
+{
+ return lhs.compare(rhs) != 0;
+}
+
+inline bool operator<(const Integer &lhs, const Integer &rhs)
+{
+ return lhs.compare(rhs) < 0;
+}
+
+inline bool operator<=(const Integer &lhs, const Integer &rhs)
+{
+ return lhs.compare(rhs) <= 0;
+}
+
+inline bool operator>(const Integer &lhs, const Integer &rhs)
+{
+ return lhs.compare(rhs) > 0;
+}
+
+inline bool operator>=(const Integer &lhs, const Integer &rhs)
+{
+ return lhs.compare(rhs) >= 0;
+}
+
+namespace Smart {
+class LIB_SMART_API Integer2 : public Integer {
+public:
+ Integer2();
+ Integer2(const Integer2 &);
+ Integer2 &operator=(const Integer2 &);
+ Integer2(Integer2 &&other) = delete;
+ Integer2 &operator=(Integer2 &&other) = delete;
+ ~Integer2() = default;
+};
+} // namespace Smart
+
+#endif // SMART_INTEGER_H
diff --git a/sources/shiboken6/tests/libsmart/smart_obj.h b/sources/shiboken6/tests/libsmart/smart_obj.h
new file mode 100644
index 000000000..9f4f8425d
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/smart_obj.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SMART_OBJ_H
+#define SMART_OBJ_H
+
+#include "libsmartmacros.h"
+#include "smart_sharedptr.h"
+
+#include <vector>
+
+class Integer;
+class Obj;
+namespace Smart { class Integer2; }
+
+// Couldn't name it Object because it caused some namespace clashes.
+class LIB_SMART_API Obj {
+public:
+ Obj();
+ Obj(const Obj &other) = delete;
+ Obj &operator=(const Obj &other) = delete;
+ Obj(Obj &&other) = delete;
+ Obj &operator=(Obj &&other) = delete;
+ virtual ~Obj();
+
+ void printObj();
+ Integer takeInteger(Integer val);
+ static SharedPtr<Obj> createSharedPtrObj();
+ std::vector<SharedPtr<Obj> > createSharedPtrObjList(int size);
+ virtual SharedPtr<Integer> createSharedPtrInteger(); // virtual for PYSIDE-1188
+ SharedPtr<const Integer> createSharedPtrConstInteger();
+ int takeSharedPtrToConstInteger(SharedPtr<const Integer> pInt);
+ SharedPtr<Smart::Integer2> createSharedPtrInteger2();
+ int takeSharedPtrToObj(SharedPtr<Obj> pObj);
+ int takeSharedPtrToInteger(SharedPtr<Integer> pInt);
+ int takeSharedPtrToIntegerByConstRef(const SharedPtr<Integer> &pInt);
+
+ static SharedPtr<Integer> createSharedPtrInteger(int value);
+ static SharedPtr<Integer> createNullSharedPtrInteger();
+
+ int m_integer; // public for testing member field access.
+ Integer *m_internalInteger;
+};
+
+#endif // SMART_OBJ_H
diff --git a/sources/shiboken6/tests/libsmart/smart_registry.h b/sources/shiboken6/tests/libsmart/smart_registry.h
new file mode 100644
index 000000000..abf7edc84
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/smart_registry.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SMART_REGISTRY_H
+#define SMART_REGISTRY_H
+
+#include <vector>
+
+#include "libsmartmacros.h"
+
+class Obj;
+class Integer;
+
+// Used to track which C++ objects are alive.
+class LIB_SMART_API Registry {
+public:
+ static Registry *getInstance();
+ ~Registry();
+
+ Registry(const Registry &) = delete;
+ Registry &operator=(const Registry &) = delete;
+ Registry(Registry &&) = delete;
+ Registry &operator=(Registry &&) = delete;
+
+ void add(Obj *p);
+ void add(Integer *p);
+ void remove(Obj *p);
+ void remove(Integer *p);
+ int countObjects() const;
+ int countIntegers() const;
+ bool verbose() const;
+ void setVerbose(bool flag);
+
+protected:
+ Registry();
+
+private:
+ std::vector<Obj *> m_objects;
+ std::vector<Integer *> m_integers;
+ bool m_verbose = false;
+};
+
+#endif // SMART_REGISTRY_H
diff --git a/sources/shiboken6/tests/libsmart/smart_sharedptr.h b/sources/shiboken6/tests/libsmart/smart_sharedptr.h
new file mode 100644
index 000000000..dc665810a
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/smart_sharedptr.h
@@ -0,0 +1,94 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SMART_SHARED_PTR_H
+#define SMART_SHARED_PTR_H
+
+#include <memory>
+
+#include "libsmartmacros.h"
+
+struct SharedPtrBase
+{
+ LIB_SMART_API static void logDefaultConstructor(const char *instantiation, const void *t);
+ LIB_SMART_API static void logConstructor(const char *instantiation, const void *t, const void *pointee);
+ LIB_SMART_API static void logCopyConstructor(const char *instantiation, const void *t, const void *refData);
+ LIB_SMART_API static void logAssignment(const char *instantiation, const void *t, const void *refData);
+ LIB_SMART_API static void logDestructor(const char *instantiation, const void *t, int remainingRefCount);
+};
+
+template <class T>
+class SharedPtr : public SharedPtrBase {
+public:
+ LIBMINIMAL_DEFAULT_MOVE(SharedPtr)
+
+ SharedPtr() { logDefaultConstructor(typeid(T).name(), this); }
+
+ SharedPtr(T *v) : mPtr(v)
+ {
+ logConstructor(typeid(T).name(), this, v);
+ }
+
+ SharedPtr(const SharedPtr<T> &other) : mPtr(other.mPtr)
+ {
+ logCopyConstructor(typeid(T).name(), this, data());
+ }
+
+ template<class X>
+ SharedPtr(const SharedPtr<X> &other) : mPtr(other.mPtr)
+ {
+ logCopyConstructor(typeid(T).name(), this, data());
+ }
+
+ SharedPtr &operator=(const SharedPtr &other)
+ {
+ if (this != &other)
+ mPtr = other.mPtr;
+ return *this;
+ }
+
+ T *data() const
+ {
+ return mPtr.get();
+ }
+
+ int useCount() const
+ {
+ return mPtr.use_count();
+ }
+
+ void dummyMethod1()
+ {
+ }
+
+ bool isNull() const
+ {
+ return mPtr.get() == nullptr;
+ }
+
+ T& operator*() const
+ {
+ // Crashes if smart pointer is empty (just like std::shared_ptr).
+ return *mPtr;
+ }
+
+ T *operator->() const
+ {
+ return mPtr.get();
+ }
+
+ bool operator!() const
+ {
+ return !mPtr;
+ }
+
+ ~SharedPtr()
+ {
+ if (mPtr.use_count() >= 1)
+ logDestructor(typeid(T).name(), this, mPtr.use_count() - 1);
+ }
+
+ std::shared_ptr<T> mPtr;
+};
+
+#endif // SMART_SHARED_PTR_H
diff --git a/sources/shiboken6/tests/libsmart/smart_test.h b/sources/shiboken6/tests/libsmart/smart_test.h
new file mode 100644
index 000000000..89d8cbc7c
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/smart_test.h
@@ -0,0 +1,13 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef SMART_TEST_H
+#define SMART_TEST_H
+
+namespace Test {
+
+enum DummyEnum { Dummy1, Dummy2 };
+
+}
+
+#endif // SMART_TEST_H
diff --git a/sources/shiboken6/tests/libsmart/stdoptionaltestbench.cpp b/sources/shiboken6/tests/libsmart/stdoptionaltestbench.cpp
new file mode 100644
index 000000000..69100720c
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/stdoptionaltestbench.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "stdoptionaltestbench.h"
+
+#include <iostream>
+
+std::ostream &operator<<(std::ostream &str, const Integer &i)
+{
+ str << i.value();
+ return str;
+}
+
+template <class T>
+std::ostream &operator<<(std::ostream &str, const std::optional<T> &o)
+{
+ if (o.has_value())
+ str << o.value();
+ else
+ str << "nullopt";
+ return str;
+}
+
+StdOptionalTestBench::StdOptionalTestBench() = default;
+
+std::optional<int> StdOptionalTestBench::optionalInt() const
+{
+ return m_optionalInt;
+}
+
+void StdOptionalTestBench::setOptionalInt(const std::optional<int> &i)
+{
+ std::cout << __FUNCTION__ << ' ' << i << '\n';
+ m_optionalInt = i;
+}
+
+void StdOptionalTestBench::setOptionalIntValue(int i)
+{
+ std::cout << __FUNCTION__ << ' ' << i << '\n';
+ m_optionalInt.emplace(i);
+}
+
+std::optional<Integer> StdOptionalTestBench::optionalInteger() const
+{
+ return m_optionalInteger;
+}
+
+void StdOptionalTestBench::setOptionalInteger(const std::optional<Integer> &s)
+{
+ std::cout << __FUNCTION__ << ' ' << s << '\n';
+ m_optionalInteger = s;
+}
+
+void StdOptionalTestBench::setOptionalIntegerValue(Integer &s)
+{
+ std::cout << __FUNCTION__ << ' ' << s << '\n';
+ m_optionalInteger.emplace(s);
+}
diff --git a/sources/shiboken6/tests/libsmart/stdoptionaltestbench.h b/sources/shiboken6/tests/libsmart/stdoptionaltestbench.h
new file mode 100644
index 000000000..baa709821
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/stdoptionaltestbench.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef OPTIONALTEST_H
+#define OPTIONALTEST_H
+
+#include "libsmartmacros.h"
+#include "smart_integer.h"
+
+#include <optional>
+
+class LIB_SMART_API StdOptionalTestBench
+{
+public:
+ StdOptionalTestBench();
+
+ std::optional<int> optionalInt() const;
+ void setOptionalInt(const std::optional<int> &i);
+ void setOptionalIntValue(int i);
+
+ std::optional<Integer> optionalInteger() const;
+ void setOptionalInteger(const std::optional<Integer> &s);
+ void setOptionalIntegerValue(Integer &s);
+
+private:
+ std::optional<int> m_optionalInt;
+ std::optional<Integer> m_optionalInteger;
+};
+
+#endif // OPTIONALTEST_H
diff --git a/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp
new file mode 100644
index 000000000..472f807f2
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp
@@ -0,0 +1,106 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "stdsharedptrtestbench.h"
+#include "smart_integer.h"
+
+#include <iostream>
+
+StdSharedPtrTestBench::StdSharedPtrTestBench() = default;
+StdSharedPtrTestBench::~StdSharedPtrTestBench() = default;
+
+std::shared_ptr<Integer> StdSharedPtrTestBench::createInteger(int v)
+{
+ auto result = std::make_shared<Integer>();
+ result->setValue(v);
+ return result;
+}
+
+std::shared_ptr<Integer> StdSharedPtrTestBench::createNullInteger()
+{
+ return {};
+}
+
+void StdSharedPtrTestBench::printInteger(const std::shared_ptr<Integer> &p)
+{
+ std::cerr << __FUNCTION__ << ' ';
+ if (p.get())
+ std::cerr << p->value();
+ else
+ std::cerr << "nullptr";
+ std::cerr << '\n';
+}
+
+std::shared_ptr<int> StdSharedPtrTestBench::createInt(int v)
+{
+ return std::make_shared<int>(v);
+}
+
+std::shared_ptr<int> StdSharedPtrTestBench::createNullInt()
+{
+ return {};
+}
+
+void StdSharedPtrTestBench::printInt(const std::shared_ptr<int> &p)
+{
+ std::cerr << __FUNCTION__ << ' ';
+ if (p.get())
+ std::cerr << *p;
+ else
+ std::cerr << "nullptr";
+ 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;
+
+std::shared_ptr<Integer> StdSharedPtrVirtualMethodTester::callModifyInteger(const std::shared_ptr<Integer> &p)
+{
+ return doModifyInteger(p);
+}
+
+std::shared_ptr<Integer> StdSharedPtrVirtualMethodTester::doModifyInteger(std::shared_ptr<Integer> p)
+{
+ p->setValue(p->value() + 1);
+ return p;
+}
diff --git a/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h
new file mode 100644
index 000000000..9d4c207b5
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef STDSHAREDPTRTESTBENCH_H
+#define STDSHAREDPTRTESTBENCH_H
+
+#include "libsmartmacros.h"
+
+#include <memory>
+#include <string>
+
+class Integer;
+
+class LIB_SMART_API StdSharedPtrTestBench
+{
+public:
+ StdSharedPtrTestBench();
+ ~StdSharedPtrTestBench();
+
+ static std::shared_ptr<Integer> createInteger(int v = 42);
+ static std::shared_ptr<Integer> createNullInteger();
+ static void printInteger(const std::shared_ptr<Integer> &);
+
+ 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
+{
+public:
+ StdSharedPtrVirtualMethodTester();
+ virtual ~StdSharedPtrVirtualMethodTester();
+
+ std::shared_ptr<Integer> callModifyInteger(const std::shared_ptr<Integer> &p);
+
+protected:
+ virtual std::shared_ptr<Integer> doModifyInteger(std::shared_ptr<Integer> p);
+};
+
+#endif // STDSHAREDPTRTESTBENCH_H
diff --git a/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.cpp b/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.cpp
new file mode 100644
index 000000000..df4b566fa
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.cpp
@@ -0,0 +1,133 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "stduniqueptrtestbench.h"
+#include "smart_integer.h"
+
+#include <iostream>
+
+std::ostream &operator<<(std::ostream &str, const std::unique_ptr<Integer> &p)
+{
+ str << "unique_ptr<Integer>(";
+ if (p.get())
+ str << p->value();
+ else
+ str << "nullptr";
+ str << ')';
+ return str;
+}
+
+std::ostream &operator<<(std::ostream &str, const std::unique_ptr<Smart::Integer2> &p)
+{
+ str << "unique_ptr<Integer>(";
+ if (p.get())
+ str << p->value();
+ else
+ str << "nullptr";
+ str << ')';
+ return str;
+}
+
+std::ostream &operator<<(std::ostream &str, const std::unique_ptr<int> &p)
+{
+ str << "unique_ptr<int>(";
+ if (p.get())
+ str << *p;
+ else
+ str << "nullptr";
+ str << ')';
+ return str;
+}
+
+StdUniquePtrTestBench::StdUniquePtrTestBench() = default;
+StdUniquePtrTestBench::~StdUniquePtrTestBench() = default;
+
+std::unique_ptr<Integer> StdUniquePtrTestBench::createInteger(int v)
+{
+ auto result = std::make_unique<Integer>();
+ result->setValue(v);
+ return result;
+}
+
+std::unique_ptr<Integer> StdUniquePtrTestBench::createNullInteger()
+{
+ return {};
+}
+
+void StdUniquePtrTestBench::printInteger(const std::unique_ptr<Integer> &p)
+{
+ std::cerr << __FUNCTION__ << ' ' << p << '\n';
+}
+
+void StdUniquePtrTestBench::takeInteger(std::unique_ptr<Integer> p)
+{
+ std::cerr << __FUNCTION__ << ' ' << p << '\n';
+}
+
+std::unique_ptr<int> StdUniquePtrTestBench::createInt(int v)
+{
+ return std::make_unique<int>(v);
+}
+
+std::unique_ptr<int> StdUniquePtrTestBench::createNullInt()
+{
+ return {};
+}
+
+void StdUniquePtrTestBench::printInt(const std::unique_ptr<int> &p)
+{
+ std::cerr << __FUNCTION__ << ' ' << p << '\n';
+}
+
+void StdUniquePtrTestBench::takeInt(std::unique_ptr<int> p)
+{
+ std::cerr << __FUNCTION__ << ' ' << p << '\n';
+}
+
+StdUniquePtrVirtualMethodTester::StdUniquePtrVirtualMethodTester() = default;
+
+StdUniquePtrVirtualMethodTester::~StdUniquePtrVirtualMethodTester() = default;
+
+bool StdUniquePtrVirtualMethodTester::testModifyIntegerByRef(int value, int expectedValue)
+{
+ auto p = std::make_unique<Integer>();
+ p->setValue(value);
+ const int actualValue = doModifyIntegerByRef(p);
+ return p.get() != nullptr && actualValue == expectedValue;
+}
+
+bool StdUniquePtrVirtualMethodTester::testModifyIntegerValue(int value, int expectedValue)
+{
+ auto p = std::make_unique<Integer>();
+ p->setValue(value);
+ const int actualValue = doModifyIntegerByValue(std::move(p));
+ return p.get() == nullptr && actualValue == expectedValue;
+}
+
+bool StdUniquePtrVirtualMethodTester::testCreateInteger(int value, int expectedValue)
+{
+ auto p = doCreateInteger(value);
+ return p.get() != nullptr && p->value() == expectedValue;
+}
+
+std::unique_ptr<Integer> StdUniquePtrVirtualMethodTester::doCreateInteger(int v)
+{
+ auto result = std::make_unique<Integer>();
+ result->setValue(v);
+ return result;
+}
+
+int StdUniquePtrVirtualMethodTester::doModifyIntegerByRef(const std::unique_ptr<Integer> &p)
+{
+ return p->value() + 1;
+}
+
+int StdUniquePtrVirtualMethodTester::doModifyIntegerByValue(std::unique_ptr<Integer> p)
+{
+ return p->value() + 1;
+}
+
+void StdUniquePtrTestBench::printInteger2(const std::unique_ptr<Smart::Integer2> &p)
+{
+ std::cerr << __FUNCTION__ << ' ' << p << '\n';
+}
diff --git a/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.h b/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.h
new file mode 100644
index 000000000..868c6d08c
--- /dev/null
+++ b/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef STDUNIQUEPTRTESTBENCH_H
+#define STDUNIQUEPTRTESTBENCH_H
+
+#include "libsmartmacros.h"
+
+#include <memory>
+
+class Integer;
+namespace Smart {
+class Integer2;
+}
+
+class LIB_SMART_API StdUniquePtrTestBench
+{
+public:
+ StdUniquePtrTestBench();
+ ~StdUniquePtrTestBench();
+
+ static std::unique_ptr<Integer> createInteger(int v = 42);
+ static std::unique_ptr<Integer> createNullInteger();
+ static void printInteger2(const std::unique_ptr<Smart::Integer2> &p);
+ static void printInteger(const std::unique_ptr<Integer> &p);
+ static void takeInteger(std::unique_ptr<Integer> p); // Call with std::move()
+
+ static std::unique_ptr<int> createInt(int v = 42);
+ static std::unique_ptr<int> createNullInt();
+ static void printInt(const std::unique_ptr<int> &p);
+ static void takeInt(std::unique_ptr<int> p); // Call with std::move()
+};
+
+class LIB_SMART_API StdUniquePtrVirtualMethodTester
+{
+public:
+ StdUniquePtrVirtualMethodTester();
+ virtual ~StdUniquePtrVirtualMethodTester();
+
+ bool testModifyIntegerByRef(int value, int expectedValue);
+ bool testModifyIntegerValue(int value, int expectedValue);
+ bool testCreateInteger(int value, int expectedValue);
+
+protected:
+ virtual std::unique_ptr<Integer> doCreateInteger(int v);
+ virtual int doModifyIntegerByRef(const std::unique_ptr<Integer> &p);
+ virtual int doModifyIntegerByValue(std::unique_ptr<Integer> p);
+};
+
+#endif // STDUNIQUEPTRTESTBENCH_H
diff --git a/sources/shiboken6/tests/minimalbinding/CMakeLists.txt b/sources/shiboken6/tests/minimalbinding/CMakeLists.txt
new file mode 100644
index 000000000..7f132bd34
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/CMakeLists.txt
@@ -0,0 +1,47 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(minimal)
+
+set(minimal_TYPESYSTEM
+${CMAKE_CURRENT_SOURCE_DIR}/typesystem_minimal.xml
+)
+
+set(minimal_SRC
+${CMAKE_CURRENT_BINARY_DIR}/minimal/minimal_module_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/minimal/containeruser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/minimal/obj_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/minimal/val_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/minimal/listuser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/minimal/spanuser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/minimal/minbooluser_wrapper.cpp
+)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/minimal-binding.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt" @ONLY)
+
+shiboken_get_tool_shell_wrapper(shiboken tool_wrapper)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+ BYPRODUCTS ${minimal_SRC}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Shiboken6::shiboken6>
+ --project-file=${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt
+ ${GENERATOR_EXTRA_FLAGS}
+ DEPENDS ${minimal_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h Shiboken6::shiboken6
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Running generator for 'minimal' test binding..."
+)
+
+add_library(minimal MODULE ${minimal_SRC})
+target_include_directories(minimal PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(minimal PUBLIC libminimal libshiboken)
+set_property(TARGET minimal PROPERTY PREFIX "")
+set_property(TARGET minimal PROPERTY OUTPUT_NAME "minimal${PYTHON_EXTENSION_SUFFIX}")
+if(WIN32)
+ set_property(TARGET minimal PROPERTY SUFFIX ".pyd")
+endif()
+
+create_generator_target(minimal)
diff --git a/sources/shiboken6/tests/minimalbinding/brace_pattern_test.py b/sources/shiboken6/tests/minimalbinding/brace_pattern_test.py
new file mode 100644
index 000000000..946a869db
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/brace_pattern_test.py
@@ -0,0 +1,87 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import os
+import re
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from shiboken6 import Shiboken # noqa: F401
+
+from shibokensupport.signature.lib.tool import build_brace_pattern
+
+"""
+This test tests the brace pattern from signature.lib.tool
+against a slower reference implementation.
+The pattern is crucial, because it is used heavily in signature.parser .
+"""
+
+
+def check(s):
+ """A slow reference parser for braces and strings"""
+ open, close = "[{(<", "]})>"
+ escape, quote = "\\", '"'
+ instring = blind = False
+ stack = []
+ for c in s:
+ if instring:
+ if blind:
+ blind = False
+ elif c == escape:
+ blind = True
+ elif c == quote:
+ instring = False
+ stack.pop()
+ continue
+ if c in open:
+ stack.append(c)
+ elif c in close:
+ pos = close.index(c)
+ if len(stack) > 0 and open[pos] == stack[len(stack) - 1]:
+ stack.pop()
+ else:
+ return False
+ elif c == escape:
+ return False
+ elif c == quote:
+ instring = True
+ stack.append(c)
+ return len(stack) == 0
+
+
+class TestBracePattern(unittest.TestCase):
+ tests = [
+ (r'{[]{()}}', True),
+ (r'[{}{})(]', False),
+ (r'[{}{} ")(" ]', True),
+ (r'[{}{} ")(\" ]', False),
+ (r'[{}{} ")(\" ]"]', True),
+ (r'a < b ( c [ d { "} \"\"}" } ] ) >', True),
+ (r'a < b ( c [ d { } ] ) >', True),
+ (r'a < b ( c [ d { "huh" } ] ) >', True),
+ (r'a < b ( c [ d { "huh\" \" \\\"" } ] ) >', True),
+ ]
+
+ def test_checkfunc(self):
+ for test, result in self.tests:
+ if result:
+ self.assertTrue(check(test))
+ else:
+ self.assertFalse(check(test))
+
+ def test_the_brace_pattern(self):
+ func = re.compile(build_brace_pattern(5, ",") + "$", re.VERBOSE).match
+ for test, result in self.tests:
+ if result:
+ self.assertTrue(func(test))
+ else:
+ self.assertFalse(func(test))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/minimalbinding/containeruser_test.py b/sources/shiboken6/tests/minimalbinding/containeruser_test.py
new file mode 100644
index 000000000..25d683957
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/containeruser_test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from minimal import ContainerUser
+
+
+class ContainerTest(unittest.TestCase):
+ """Simple test for converting std::vector and using an opaque container.
+ For advanced tests, see ListUser."""
+ def testVectorConversion(self):
+ v = ContainerUser.createIntVector(4)
+ self.assertEqual(ContainerUser.sumIntVector(v), 6)
+
+ def testVectorOpaqueContainer(self):
+ cu = ContainerUser()
+ oc = cu.intVector()
+ self.assertEqual(oc[0], 1)
+ oc[0] = 42
+ self.assertEqual(cu.intVector()[0], 42)
+
+ def testArrayConversion(self):
+ v = ContainerUser.createIntArray()
+ self.assertEqual(ContainerUser.sumIntArray(v), 6)
+
+ def testArrayOpaqueContainer(self):
+ cu = ContainerUser()
+ oc = cu.intArray()
+ self.assertEqual(oc[0], 1)
+ oc[0] = 42
+ self.assertEqual(cu.intArray()[0], 42)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/minimalbinding/global.h b/sources/shiboken6/tests/minimalbinding/global.h
new file mode 100644
index 000000000..fc5c59a26
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/global.h
@@ -0,0 +1,10 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "obj.h"
+#include "containeruser.h"
+#include "val.h"
+#include "minbool.h"
+#include "listuser.h"
+#include "spanuser.h"
+#include "typedef.h"
diff --git a/sources/shiboken6/tests/minimalbinding/listuser_test.py b/sources/shiboken6/tests/minimalbinding/listuser_test.py
new file mode 100644
index 000000000..b30bb653a
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/listuser_test.py
@@ -0,0 +1,376 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+from functools import reduce
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from minimal import ListUser, Val, Obj, StdIntList
+
+
+class ExtListUser(ListUser):
+ def __init__(self):
+ super().__init__()
+ self._stdIntList = StdIntList()
+ self._stdIntList.append(1)
+ self._stdIntList.append(2)
+
+ def createIntList(self, num):
+ return list(range(0, num * 2, 2))
+
+ def sumIntList(self, intList):
+ return sum(intList) * 2
+
+ def createMinBoolList(self, mb1, mb2):
+ return [not mb1, not mb2]
+
+ def oredMinBoolList(self, minBoolList):
+ return not reduce(lambda a, b: a | b, minBoolList)
+
+ def createValList(self, num):
+ return [Val(i) for i in range(0, num * 2, 2)]
+
+ def sumValList(self, valList):
+ return sum([val.valId() for val in valList]) * 2
+
+ def createObjList(self, o1, o2):
+ o1.setObjId(o1.objId() * 2)
+ o2.setObjId(o2.objId() * 2)
+ return [o1, o2]
+
+ def sumObjList(self, objList):
+ return sum([obj.objId() for obj in objList]) * 2
+
+ def createListOfIntLists(self, num):
+ return [self.createIntList(num)] * 4
+
+ def sumListOfIntLists(self, intListList):
+ return sum([sum(line) for line in intListList]) * 2
+
+ def returnIntListByPtr(self):
+ return self._stdIntList
+
+
+class IntListConversionTest(unittest.TestCase):
+
+ def testCreateIntList(self):
+ num = 4
+ lu = ListUser()
+ lst = lu.createIntList(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), int)
+ self.assertEqual(lst, list(range(num)))
+ lst = lu.callCreateIntList(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), int)
+ self.assertEqual(lst, list(range(num)))
+
+ def testCreateIntListFromExtendedClass(self):
+ lu = ExtListUser()
+ num = 4
+ lst = lu.createIntList(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), int)
+ self.assertEqual(lst, list(range(0, num * 2, 2)))
+ lst = lu.callCreateIntList(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), int)
+ self.assertEqual(lst, list(range(0, num * 2, 2)))
+
+ def testSumIntList(self):
+ lu = ListUser()
+ lst = range(4)
+ expected = sum(lst)
+ self.assertEqual(lu.sumIntList(lst), expected)
+ self.assertEqual(lu.callSumIntList(lst), expected)
+ self.assertEqual(lu.sumIntListDefaultParam(lst), expected)
+ self.assertEqual(lu.sumIntListDefaultParamConstRef(lst), expected)
+ # PYSIDE-2454: Check container default parameters (1,2,3)
+ self.assertEqual(lu.sumIntListDefaultParam(), 6)
+ self.assertEqual(lu.sumIntListDefaultParamConstRef(), 6)
+
+ def testSumIntListFromExtendedClass(self):
+ lu = ExtListUser()
+ lst = range(4)
+ self.assertEqual(lu.sumIntList(lst), sum(lst) * 2)
+ self.assertEqual(lu.callSumIntList(lst), sum(lst) * 2)
+
+
+class MinBoolListConversionTest(unittest.TestCase):
+
+ def testCreateMinBoolList(self):
+ lu = ListUser()
+ lst = lu.createMinBoolList(True, False)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), 2)
+ for i in lst:
+ self.assertEqual(type(i), bool)
+ self.assertEqual(lst, [True, False])
+
+ lst = lu.callCreateMinBoolList(False, True)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), 2)
+ for i in lst:
+ self.assertEqual(type(i), bool)
+ self.assertEqual(lst, [False, True])
+
+ def testCreateMinBoolListFromExtendedClass(self):
+ lu = ExtListUser()
+ lst = lu.createMinBoolList(True, False)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), 2)
+ for i in lst:
+ self.assertEqual(type(i), bool)
+ self.assertEqual(lst, [False, True])
+
+ lst = lu.callCreateMinBoolList(False, True)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), 2)
+ for i in lst:
+ self.assertEqual(type(i), bool)
+ self.assertEqual(lst, [True, False])
+
+ def testOredMinBoolList(self):
+ lu = ListUser()
+ lst = [False, False, True]
+ self.assertTrue(lu.oredMinBoolList(lst))
+ self.assertTrue(lu.callOredMinBoolList(lst))
+ lst = [False, False, False]
+ self.assertFalse(lu.oredMinBoolList(lst))
+ self.assertFalse(lu.callOredMinBoolList(lst))
+
+ def testOredMinBoolListFromExtendedClass(self):
+ lu = ExtListUser()
+ lst = [False, False, True]
+ self.assertFalse(lu.oredMinBoolList(lst))
+ self.assertFalse(lu.callOredMinBoolList(lst))
+ lst = [False, False, False]
+ self.assertTrue(lu.oredMinBoolList(lst))
+ self.assertTrue(lu.callOredMinBoolList(lst))
+
+
+class ValListConversionTest(unittest.TestCase):
+
+ def testCreateValList(self):
+ num = 4
+ lu = ListUser()
+ lst = lu.createValList(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), Val)
+ self.assertEqual([val.valId() for val in lst], list(range(num)))
+ lst = lu.callCreateValList(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), Val)
+ self.assertEqual([val.valId() for val in lst], list(range(num)))
+
+ def testCreateValListFromExtendedClass(self):
+ lu = ExtListUser()
+ num = 4
+ lst = lu.createValList(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), Val)
+ self.assertEqual([val.valId() for val in lst], list(range(0, num * 2, 2)))
+ lst = lu.callCreateValList(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), Val)
+ self.assertEqual([val.valId() for val in lst], list(range(0, num * 2, 2)))
+
+ def testSumValList(self):
+ lu = ListUser()
+ lst = [Val(i) for i in range(4)]
+ self.assertEqual(lu.sumValList(lst), sum([val.valId() for val in lst]))
+ self.assertEqual(lu.callSumValList(lst), sum([val.valId() for val in lst]))
+
+ def testSumValListFromExtendedClass(self):
+ lu = ExtListUser()
+ lst = [Val(i) for i in range(4)]
+ self.assertEqual(lu.sumValList(lst), sum([val.valId() for val in lst]) * 2)
+ self.assertEqual(lu.callSumValList(lst), sum([val.valId() for val in lst]) * 2)
+
+
+class ObjListConversionTest(unittest.TestCase):
+
+ def testCreateObjList(self):
+ o1 = Obj(1)
+ o2 = Obj(2)
+ lu = ListUser()
+ lst = lu.createObjList(o1, o2)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), 2)
+ for i in lst:
+ self.assertEqual(type(i), Obj)
+ self.assertEqual(lst, [o1, o2])
+ self.assertEqual([obj.objId() for obj in lst], [1, 2])
+
+ lst = lu.callCreateObjList(o1, o2)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), 2)
+ for i in lst:
+ self.assertEqual(type(i), Obj)
+ self.assertEqual(lst, [o1, o2])
+ self.assertEqual([obj.objId() for obj in lst], [1, 2])
+
+ def testCreateObjListFromExtendedClass(self):
+ o1 = Obj(1)
+ o2 = Obj(2)
+ lu = ExtListUser()
+ lst = lu.createObjList(o1, o2)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), 2)
+ for i in lst:
+ self.assertEqual(type(i), Obj)
+ self.assertEqual(lst, [o1, o2])
+ self.assertEqual([obj.objId() for obj in lst], [2, 4])
+
+ lst = lu.callCreateObjList(o1, o2)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), 2)
+ for i in lst:
+ self.assertEqual(type(i), Obj)
+ self.assertEqual(lst, [o1, o2])
+ self.assertEqual([obj.objId() for obj in lst], [4, 8])
+
+ def testSumObjList(self):
+ lu = ListUser()
+ lst = [Obj(i) for i in list(range(4))]
+ self.assertEqual(lu.sumObjList(lst), sum([obj.objId() for obj in lst]))
+ self.assertEqual(lu.callSumObjList(lst), sum([obj.objId() for obj in lst]))
+
+ def testSumObjListFromExtendedClass(self):
+ lu = ExtListUser()
+ lst = [Obj(i) for i in list(range(4))]
+ self.assertEqual(lu.sumObjList(lst), sum([obj.objId() for obj in lst]) * 2)
+ self.assertEqual(lu.callSumObjList(lst), sum([obj.objId() for obj in lst]) * 2)
+
+
+class ListOfIntListConversionTest(unittest.TestCase):
+
+ def testCreateListOfIntLists(self):
+ num = 4
+ lu = ListUser()
+ lst = lu.createListOfIntLists(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), list)
+ self.assertEqual(i, list(range(num)))
+ for j in i:
+ self.assertEqual(type(j), int)
+ self.assertEqual(lst, [list(range(num))] * 4)
+
+ def testCreateListOfIntListsFromExtendedClass(self):
+ num = 4
+ lu = ExtListUser()
+ lst = lu.createListOfIntLists(num)
+ self.assertEqual(type(lst), list)
+ self.assertEqual(len(lst), num)
+ for i in lst:
+ self.assertEqual(type(i), list)
+ self.assertEqual(i, list(range(0, num * 2, 2)))
+ for j in i:
+ self.assertEqual(type(j), int)
+ self.assertEqual(lst, [list(range(0, num * 2, 2))] * 4)
+
+ def testSumListIntLists(self):
+ lu = ListUser()
+ lst = [range(4)] * 4
+ self.assertEqual(lu.sumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4]))
+ self.assertEqual(lu.callSumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4]))
+
+ def testSumListOfIntListsFromExtendedClass(self):
+ lu = ExtListUser()
+ lst = [range(4)] * 4
+ self.assertEqual(lu.sumListOfIntLists(lst),
+ sum([sum(line) for line in [range(4)] * 4]) * 2)
+ self.assertEqual(lu.callSumListOfIntLists(lst),
+ sum([sum(line) for line in [range(4)] * 4]) * 2)
+
+ def testOpaqueContainer(self):
+ lu = ListUser()
+
+ # Set via Python
+ python_list = [1, 2]
+ lu.setStdIntList(python_list)
+ self.assertEqual(len(lu.m_stdIntList), 2)
+ self.assertEqual(lu.m_stdIntList[0], 1)
+ self.assertEqual(lu.m_stdIntList[1], 2)
+
+ # Set via C++
+ cpp_list = StdIntList()
+ cpp_list.append(3)
+ cpp_list.append(4)
+ lu.setStdIntList(cpp_list)
+ self.assertEqual(len(lu.m_stdIntList), 2)
+ self.assertEqual(lu.m_stdIntList[0], 3)
+ self.assertEqual(lu.m_stdIntList[1], 4)
+
+ # Access field directly via reference
+ lu.m_stdIntList.append(5)
+ self.assertEqual(len(lu.m_stdIntList), 3)
+ self.assertEqual(lu.m_stdIntList[2], 5)
+
+ # Access list via getter
+ il = lu.getIntList()
+ il.append(6)
+ self.assertEqual(len(lu.m_stdIntList), 4)
+ self.assertEqual(lu.m_stdIntList[3], 6)
+
+ # Access a const list via getter and verify that it cannot be modified
+ const_l = lu.getConstIntList()
+ self.assertEqual(len(const_l), 4)
+ self.assertRaises(TypeError, const_l.append, 6)
+
+ def testListByPtrOpaque(self):
+ """Test a function taking C++ list by pointer for which an opaque
+ container exists."""
+ lu = ListUser()
+ python_list = [1, 2]
+ self.assertEqual(lu.modifyIntListPtr(python_list), 2)
+
+ # Pass an opaque container and verify whether it is modified by C++
+ cpp_list = StdIntList()
+ cpp_list.append(1)
+ cpp_list.append(2)
+ self.assertEqual(lu.modifyIntListPtr(cpp_list), 2)
+ self.assertEqual(len(cpp_list), 3)
+
+ def testListByPtr(self):
+ """Test a function taking C++ list by pointer for which no opaque
+ container exists."""
+ lu = ListUser()
+ python_list = [1.1, 22.2]
+ self.assertEqual(lu.modifyDoubleListPtr(python_list), 2)
+
+ def testReturnListByPtr(self):
+ """Test that a virtual function returning a list by pointer can be
+ reimplemented by a Python function returning an opaque container."""
+ lu = ExtListUser()
+ size = lu.callReturnIntListByPtr() # Call virtual from C++
+ self.assertEqual(size, 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/minimalbinding/minbool_test.py b/sources/shiboken6/tests/minimalbinding/minbool_test.py
new file mode 100644
index 000000000..d9ce0eac0
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/minbool_test.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from minimal import MinBoolUser
+
+
+class DerivedMinBoolUser (MinBoolUser):
+ def returnMyselfVirtual(self):
+ return MinBoolUser()
+
+
+class MinBoolTest(unittest.TestCase):
+
+ def testMinBoolUser(self):
+ mbuTrue = MinBoolUser()
+ mbuFalse = MinBoolUser()
+ mbuTrue.setMinBool(True)
+ self.assertFalse(mbuFalse.minBool())
+ self.assertTrue(mbuTrue.minBool())
+ self.assertFalse(mbuTrue.callInvertedMinBool())
+
+ self.assertTrue(mbuTrue.minBool())
+ self.assertFalse(mbuFalse.minBool())
+ self.assertTrue(mbuTrue.minBool() != mbuFalse.minBool())
+
+ self.assertFalse(mbuFalse.minBool())
+ self.assertFalse(mbuFalse.minBool())
+ self.assertTrue(mbuTrue.minBool() != mbuFalse.minBool())
+
+ def testVirtuals(self):
+ dmbu = DerivedMinBoolUser()
+ self.assertEqual(dmbu.invertedMinBool(), True)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/minimalbinding/minimal-binding.txt.in b/sources/shiboken6/tests/minimalbinding/minimal-binding.txt.in
new file mode 100644
index 000000000..101567070
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/minimal-binding.txt.in
@@ -0,0 +1,16 @@
+[generator-project]
+
+generator-set = shiboken
+
+header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h
+typesystem-file = @minimal_TYPESYSTEM@
+
+output-directory = @CMAKE_CURRENT_BINARY_DIR@
+
+include-path = @libminimal_SOURCE_DIR@
+
+typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@
+
+enable-parent-ctor-heuristic
+use-isnull-as-nb_nonzero
+lean-headers
diff --git a/sources/shiboken6/tests/minimalbinding/minimalbinding.pyproject b/sources/shiboken6/tests/minimalbinding/minimalbinding.pyproject
new file mode 100644
index 000000000..ab19dc443
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/minimalbinding.pyproject
@@ -0,0 +1,10 @@
+{
+ "files": ["brace_pattern_test.py",
+ "containeruser_test.py",
+ "listuser_test.py",
+ "minbool_test.py",
+ "obj_test.py",
+ "typedef_test.py",
+ "val_test.py",
+ "typesystem_minimal.xml"]
+}
diff --git a/sources/shiboken6/tests/minimalbinding/obj_test.py b/sources/shiboken6/tests/minimalbinding/obj_test.py
new file mode 100644
index 000000000..e873845de
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/obj_test.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from minimal import Obj
+
+
+class ExtObj(Obj):
+ def __init__(self, objId):
+ Obj.__init__(self, objId)
+ self.virtual_method_called = False
+
+ def virtualMethod(self, val):
+ self.virtual_method_called = True
+ return not Obj.virtualMethod(self, val)
+
+ def passObjectType(self, obj):
+ obj.setObjId(obj.objId() + 1)
+ return obj
+
+ def passObjectTypeReference(self, obj):
+ obj.setObjId(obj.objId() + 1)
+ return obj
+
+
+class ObjTest(unittest.TestCase):
+
+ def testNormalMethod(self):
+ objId = 123
+ obj = Obj(objId)
+ self.assertEqual(obj.objId(), objId)
+
+ def testNormalMethodFromExtendedClass(self):
+ objId = 123
+ obj = ExtObj(objId)
+ self.assertEqual(obj.objId(), objId)
+
+ def testVirtualMethod(self):
+ obj = Obj(0)
+ even_number = 8
+ self.assertEqual(obj.virtualMethod(even_number), obj.callVirtualMethod(even_number))
+
+ def testVirtualMethodFromExtendedClass(self):
+ obj = ExtObj(0)
+ even_number = 8
+ self.assertEqual(obj.virtualMethod(even_number), obj.callVirtualMethod(even_number))
+ self.assertTrue(obj.virtual_method_called)
+
+ def testPassObjectType(self):
+ obj = Obj(0)
+ self.assertEqual(obj, obj.passObjectType(obj))
+ self.assertEqual(obj, obj.callPassObjectType(obj))
+
+ def testPassObjectTypeNone(self):
+ obj = Obj(0)
+ self.assertEqual(None, obj.passObjectType(None))
+ self.assertEqual(None, obj.callPassObjectType(None))
+
+ def testPassObjectTypeReference(self):
+ obj = Obj(0)
+ self.assertEqual(obj, obj.passObjectTypeReference(obj))
+ self.assertEqual(obj, obj.callPassObjectTypeReference(obj))
+
+ def testPassObjectTypeFromExtendedClass(self):
+ obj = ExtObj(0)
+ self.assertEqual(obj.objId(), 0)
+ sameObj = obj.passObjectType(obj)
+ self.assertEqual(obj, sameObj)
+ self.assertEqual(sameObj.objId(), 1)
+ sameObj = obj.callPassObjectType(obj)
+ self.assertEqual(obj, sameObj)
+ self.assertEqual(sameObj.objId(), 2)
+
+ def testPassObjectTypeReferenceFromExtendedClass(self):
+ obj = ExtObj(0)
+ self.assertEqual(obj.objId(), 0)
+ sameObj = obj.passObjectTypeReference(obj)
+ self.assertEqual(obj, sameObj)
+ self.assertEqual(sameObj.objId(), 1)
+ sameObj = obj.callPassObjectTypeReference(obj)
+ self.assertEqual(obj, sameObj)
+ self.assertEqual(sameObj.objId(), 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/minimalbinding/spanuser_test.py b/sources/shiboken6/tests/minimalbinding/spanuser_test.py
new file mode 100644
index 000000000..6db6aa616
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/spanuser_test.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from minimal import SpanUser
+
+
+class IntSpanTest(unittest.TestCase):
+
+ def testCreateIntSpan(self):
+ if not SpanUser.enabled():
+ return
+ expected = [1, 2, 3]
+ self.assertEqual(SpanUser.getIntSpan3(), expected)
+ self.assertEqual(SpanUser.getIntSpan(), expected)
+ self.assertEqual(SpanUser.getConstIntSpan3(), expected)
+
+ self.assertEqual(SpanUser.sumIntSpan3(expected), 6)
+ self.assertEqual(SpanUser.sumIntSpan(expected), 6)
+ self.assertEqual(SpanUser.sumConstIntSpan3(expected), 6)
+
+ def testSpanOpaqueContainer(self):
+ if not SpanUser.enabled():
+ return
+ oc = SpanUser.getIntSpan3_OpaqueContainer() # 1,2,3
+ oc[1] = 10
+ oc = SpanUser.getIntSpan3_OpaqueContainer()
+ # note: This converts to std::vector
+ self.assertEqual(SpanUser.sumIntSpan3(oc), 14)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/minimalbinding/typedef_test.py b/sources/shiboken6/tests/minimalbinding/typedef_test.py
new file mode 100644
index 000000000..c2fc8fc12
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/typedef_test.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from minimal import (arrayFunc, arrayFuncInt, arrayFuncIntReturn,
+ arrayFuncIntReturnTypedef, arrayFuncIntTypedef,
+ arrayFuncReturn, arrayFuncReturnTypedef, arrayFuncTypedef)
+
+try:
+ import numpy as np
+except ImportError as e:
+ print(e)
+ np = None
+
+
+class TypedefTest(unittest.TestCase):
+
+ def setUp(self):
+ self.the_size = 8
+
+ def test_arrayFuncInt(self):
+ none = ()
+ full = range(self.the_size)
+ self.assertTrue(arrayFuncInt(none), "None is empty, arrayFuncInt should return true")
+ self.assertFalse(arrayFuncInt(full), "Full is NOT empty, arrayFuncInt should return false")
+
+ self.assertTrue(arrayFuncInt(np.array(none)),
+ "None is empty, arrayFuncInt should return true")
+ self.assertFalse(arrayFuncInt(np.array(full)),
+ "Full is NOT empty, arrayFuncInt should return false")
+
+ def test_arrayFuncIntTypedef(self):
+ none = ()
+ full = (1, 2, 3)
+ self.assertTrue(arrayFuncIntTypedef(none),
+ "None is empty, arrayFuncIntTypedef should return true")
+ self.assertFalse(arrayFuncIntTypedef(full),
+ "Full is NOT empty, arrayFuncIntTypedef should return false")
+
+ self.assertTrue(arrayFuncIntTypedef(np.array(none)),
+ "None is empty, arrayFuncIntTypedef should return true")
+ self.assertFalse(arrayFuncIntTypedef(np.array(full)),
+ "Full is NOT empty, arrayFuncIntTypedef should return false")
+
+ def test_arrayFuncIntReturn(self):
+ none = arrayFuncIntReturn(0)
+ full = arrayFuncIntReturn(self.the_size)
+ self.assertTrue((len(none) == 0), "none should be empty")
+ self.assertTrue((len(full) == self.the_size),
+ f"full should have {self.the_size} elements")
+
+ def test_arrayFuncIntReturnTypedef(self):
+ none = arrayFuncIntReturnTypedef(0)
+ full = arrayFuncIntReturnTypedef(self.the_size)
+ self.assertTrue((len(none) == 0), "none should be empty")
+ self.assertTrue((len(full) == self.the_size),
+ f"full should have {self.the_size} elements")
+
+ def test_arrayFunc(self):
+ none = ()
+ full = range(self.the_size)
+ self.assertTrue(arrayFunc(none), "None is empty, arrayFunc should return true")
+ self.assertFalse(arrayFunc(full), "Full is NOT empty, arrayFunc should return false")
+
+ self.assertTrue(arrayFunc(np.array(none)), "None is empty, arrayFunc should return true")
+ self.assertFalse(arrayFunc(np.array(full)),
+ "Full is NOT empty, arrayFunc should return false")
+
+ def test_arrayFuncTypedef(self):
+ none = ()
+ full = (1, 2, 3)
+ self.assertTrue(arrayFuncTypedef(none),
+ "None is empty, arrayFuncTypedef should return true")
+ self.assertFalse(arrayFuncTypedef(full),
+ "Full is NOT empty, arrayFuncTypedef should return false")
+
+ self.assertTrue(arrayFuncTypedef(np.array(none)),
+ "None is empty, arrayFuncTypedef should return true")
+ self.assertFalse(arrayFuncTypedef(np.array(full)),
+ "Full is NOT empty, arrayFuncTypedef should return false")
+
+ def test_arrayFuncReturn(self):
+ none = arrayFuncReturn(0)
+ full = arrayFuncReturn(self.the_size)
+ self.assertTrue((len(none) == 0), "none should be empty")
+ self.assertTrue((len(full) == self.the_size),
+ f"full should have {self.the_size} elements")
+
+ def test_arrayFuncReturnTypedef(self):
+ none = arrayFuncReturnTypedef(0)
+ full = arrayFuncReturnTypedef(self.the_size)
+ self.assertTrue((len(none) == 0), "none should be empty")
+ self.assertTrue((len(full) == self.the_size),
+ f"full should have {self.the_size} elements")
+
+
+if __name__ == '__main__':
+ if np is not None:
+ unittest.main()
diff --git a/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml
new file mode 100644
index 000000000..e18bf8686
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<typesystem package="minimal">
+
+ <primitive-type name="MinBool" target-lang-api-name="PyBool" default-constructor="MinBool(false)">
+ <include file-name="minbool.h" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ return PyBool_FromLong(%in.value());
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyBool" check="PyBool_Check(%in)">
+ %out = %OUTTYPE(%in == Py_True);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
+ <opaque-container name="std::list" opaque-containers="int:StdIntList"/>
+
+ <opaque-container name="std::vector" opaque-containers="int:StdIntVector"/>
+
+ <opaque-container name="std::array" opaque-containers="int,3:StdIntArray"/>
+
+ <?if c++20?> <!-- FIXME PYSIDE 7: Remove "if" -->
+ <opaque-container name="std::span" opaque-containers="int,3:StdIntSpan3"/>
+ <?endif?>
+
+ <object-type name="Obj"/>
+ <value-type name="Val">
+ <enum-type name="ValEnum"/>
+ </value-type>
+ <value-type name="ListUser">
+ <modify-field name="m_stdIntList" opaque-container="yes"/>
+ <modify-function signature="getIntList()">
+ <modify-argument index="return">
+ <replace-type modified-type="StdIntList"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="getConstIntList()const">
+ <modify-argument index="return">
+ <replace-type modified-type="StdIntList"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+ <value-type name="SpanUser">
+ <?if c++20?> <!-- FIXME PYSIDE 7: Remove "if" -->
+ <modify-function signature="getIntSpan3_OpaqueContainer()">
+ <modify-argument index="return">
+ <replace-type modified-type="StdIntSpan3"/>
+ </modify-argument>
+ </modify-function>
+ <?endif?>
+ </value-type>
+
+ <value-type name="MinBoolUser"/>
+
+ <value-type name="ContainerUser">
+ <modify-function signature="intVector()">
+ <modify-argument index="return">
+ <replace-type modified-type="StdIntVector"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="intArray()">
+ <modify-argument index="return">
+ <replace-type modified-type="StdIntArray"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+ <!-- Test wrapping of a typedef -->
+ <function signature="arrayFuncInt(std::vector&lt;int&gt;)" />
+ <!-- Note manual expansion of the typedef -->
+ <function signature="arrayFuncIntTypedef(std::vector&lt;int&gt;)" />
+
+ <function signature="arrayFuncIntReturn(int)" />
+ <function signature="arrayFuncIntReturnTypedef(int)" />
+
+ <!-- Test wrapping of a typedef of a typedef -->
+ <function signature="arrayFunc(std::vector&lt;int&gt;)" />
+ <!-- Note manual expansion of the typedef -->
+ <function signature="arrayFuncTypedef(std::vector&lt;int&gt;)" />
+
+ <function signature="arrayFuncReturn(int)" />
+ <function signature="arrayFuncReturnTypedef(int)" />
+</typesystem>
diff --git a/sources/shiboken6/tests/minimalbinding/val_test.py b/sources/shiboken6/tests/minimalbinding/val_test.py
new file mode 100644
index 000000000..b8225a247
--- /dev/null
+++ b/sources/shiboken6/tests/minimalbinding/val_test.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from minimal import Val
+
+
+class ExtVal(Val):
+ def __init__(self, valId):
+ Val.__init__(self, valId)
+
+ def passValueType(self, val):
+ return ExtVal(val.valId() + 1)
+
+ def passValueTypePointer(self, val):
+ val.setValId(val.valId() + 1)
+ return val
+
+ def passValueTypeReference(self, val):
+ val.setValId(val.valId() + 1)
+ return val
+
+
+class ValTest(unittest.TestCase):
+
+ def testNormalMethod(self):
+ valId = 123
+ val = Val(valId)
+ self.assertEqual(val.valId(), valId)
+
+ def testPassValueType(self):
+ val = Val(123)
+ val1 = val.passValueType(val)
+ self.assertNotEqual(val, val1)
+ self.assertEqual(val1.valId(), 123)
+ val2 = val.callPassValueType(val)
+ self.assertNotEqual(val, val2)
+ self.assertEqual(val2.valId(), 123)
+
+ def testPassValueTypePointer(self):
+ val = Val(0)
+ self.assertEqual(val, val.passValueTypePointer(val))
+ self.assertEqual(val, val.callPassValueTypePointer(val))
+
+ def testPassValueTypeReference(self):
+ val = Val(0)
+ self.assertEqual(val, val.passValueTypeReference(val))
+ self.assertEqual(val, val.callPassValueTypeReference(val))
+
+ def testPassAndReceiveEnumValue(self):
+ val = Val(0)
+ self.assertEqual(val.oneOrTheOtherEnumValue(Val.One), Val.Other)
+ self.assertEqual(val.oneOrTheOtherEnumValue(Val.Other), Val.One)
+
+ def testPassValueTypeFromExtendedClass(self):
+ val = ExtVal(0)
+ val1 = val.passValueType(val)
+ self.assertNotEqual(val, val1)
+ self.assertEqual(val1.valId(), val.valId() + 1)
+ val2 = val.callPassValueType(val)
+ self.assertNotEqual(val, val2)
+ self.assertEqual(val2.valId(), val.valId() + 1)
+
+ def testPassValueTypePointerFromExtendedClass(self):
+ val = ExtVal(0)
+ self.assertEqual(val.valId(), 0)
+ sameVal = val.passValueTypePointer(val)
+ self.assertEqual(val, sameVal)
+ self.assertEqual(sameVal.valId(), 1)
+ sameVal = val.callPassValueTypePointer(val)
+ self.assertEqual(val, sameVal)
+ self.assertEqual(sameVal.valId(), 2)
+
+ def testPassValueTypeReferenceFromExtendedClass(self):
+ val = ExtVal(0)
+ self.assertEqual(val.valId(), 0)
+ sameVal = val.passValueTypeReference(val)
+ self.assertEqual(val, sameVal)
+ self.assertEqual(sameVal.valId(), 1)
+ sameVal = val.callPassValueTypeReference(val)
+ self.assertEqual(val, sameVal)
+ self.assertEqual(sameVal.valId(), 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/CMakeLists.txt b/sources/shiboken6/tests/otherbinding/CMakeLists.txt
new file mode 100644
index 000000000..2172593d3
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/CMakeLists.txt
@@ -0,0 +1,58 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(other)
+
+set(other_TYPESYSTEM
+${CMAKE_CURRENT_SOURCE_DIR}/typesystem_other.xml
+)
+
+set(other_SRC
+${CMAKE_CURRENT_BINARY_DIR}/other/extendsnoimplicitconversion_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/number_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/otherderived_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/othermultiplederived_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/otherobjecttype_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/othervaluewithunituser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/sharedptr_str_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/smartptrtester_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/other_module_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/valuewithunitintinch_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/other/valuewithunitintmillimeter_wrapper.cpp
+)
+
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/other-binding.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt" @ONLY)
+
+shiboken_get_tool_shell_wrapper(shiboken tool_wrapper)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+ BYPRODUCTS ${other_SRC}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Shiboken6::shiboken6>
+ --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt
+ ${GENERATOR_EXTRA_FLAGS}
+ DEPENDS ${other_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h Shiboken6::shiboken6
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Running generator for 'other' test binding..."
+)
+
+add_library(other MODULE ${other_SRC})
+target_include_directories(other PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${sample_BINARY_DIR}/sample
+ ${smart_BINARY_DIR}/smart)
+target_link_libraries(other PUBLIC libother libsample libsmart libshiboken)
+set_property(TARGET other PROPERTY PREFIX "")
+set_property(TARGET other PROPERTY OUTPUT_NAME "other${PYTHON_EXTENSION_SUFFIX}")
+
+if(WIN32)
+ set_property(TARGET other PROPERTY SUFFIX ".pyd")
+endif()
+
+
+add_dependencies(other sample smart)
+create_generator_target(other)
+
diff --git a/sources/shiboken6/tests/otherbinding/collector_external_operator_test.py b/sources/shiboken6/tests/otherbinding/collector_external_operator_test.py
new file mode 100644
index 000000000..2ba21653d
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/collector_external_operator_test.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for Collector shift operators defined in other modules.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Collector, ObjectType
+from other import OtherObjectType
+
+
+class CollectorOtherObjectType(unittest.TestCase):
+ '''Test cases for Collector << OtherObjectType'''
+
+ def testLShiftWithExpectedType(self):
+ '''Collector << ObjectType # libsample << operator'''
+ collector = Collector()
+ obj = ObjectType()
+ collector << obj
+ self.assertEqual(collector.items()[0], obj.identifier())
+
+ def testOtherReversal(self):
+ '''Collector << OtherObjectType # libother << operator'''
+ collector = Collector()
+ obj = OtherObjectType()
+ collector << obj
+ self.assertEqual(collector.items()[0], obj.identifier() * 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py b/sources/shiboken6/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py
new file mode 100644
index 000000000..bd00b5892
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests calling NoImplicitConversion using a ExtendsNoImplicitConversion parameter,
+ being that the latter defines a new conversion operator for the former, and this one
+ has no implicit conversions.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import NoImplicitConversion
+from other import ExtendsNoImplicitConversion
+
+
+class ConversionOperatorForClassWithoutImplicitConversionsTest(unittest.TestCase):
+ '''Tests calling NoImplicitConversion constructor using a
+ ExtendsNoImplicitConversion parameter.'''
+
+ def testNoImplicitConversion(self):
+ '''Basic test to see if the NoImplicitConversion is Ok.'''
+ obj = NoImplicitConversion(123)
+ # NoImplicitConversion.receivesNoImplicitConversionByValue(NoImplicitConversion)
+ self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByValue(obj))
+ # NoImplicitConversion.receivesNoImplicitConversionByPointer(NoImplicitConversion*)
+ self.assertEqual(obj.objId(),
+ NoImplicitConversion.receivesNoImplicitConversionByPointer(obj))
+ # NoImplicitConversion.receivesNoImplicitConversionByReference(NoImplicitConversion&)
+ self.assertEqual(obj.objId(),
+ NoImplicitConversion.receivesNoImplicitConversionByReference(obj))
+
+ def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByValue(self):
+ '''Gives an ExtendsNoImplicitConversion object to a function expecting a
+ NoImplicitConversion, passing by value.'''
+ obj = ExtendsNoImplicitConversion(123)
+ self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByValue(obj))
+
+ def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByReference(self):
+ '''Gives an ExtendsNoImplicitConversion object to a function expecting a
+ NoImplicitConversion, passing by reference.'''
+ obj = ExtendsNoImplicitConversion(123)
+ self.assertEqual(obj.objId(),
+ NoImplicitConversion.receivesNoImplicitConversionByReference(obj))
+
+ def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByPointer(self):
+ '''Gives an ExtendsNoImplicitConversion object to a function expecting
+ a NoImplicitConversion, passing by pointer. This should not be
+ accepted, since pointers should not be converted.'''
+ obj = ExtendsNoImplicitConversion(123)
+ self.assertRaises(TypeError,
+ NoImplicitConversion.receivesNoImplicitConversionByPointer, obj)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/extended_multiply_operator_test.py b/sources/shiboken6/tests/otherbinding/extended_multiply_operator_test.py
new file mode 100644
index 000000000..abbef6231
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/extended_multiply_operator_test.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for libsample's Point multiply operator defined in libother module.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point
+from other import Number
+
+
+class PointOperationsWithNumber(unittest.TestCase):
+ '''Test cases for libsample's Point multiply operator defined in libother module.'''
+
+ def testPointTimesInt(self):
+ '''sample.Point * int'''
+ pt1 = Point(2, 7)
+ num = 3
+ pt2 = Point(pt1.x() * num, pt1.y() * num)
+ self.assertEqual(pt1 * num, pt2)
+
+ def testIntTimesPoint(self):
+ '''int * sample.Point'''
+ pt1 = Point(2, 7)
+ num = 3
+ pt2 = Point(pt1.x() * num, pt1.y() * num)
+ self.assertEqual(num * pt1, pt2)
+
+ def testPointTimesNumber(self):
+ '''sample.Point * other.Number'''
+ pt = Point(2, 7)
+ num = Number(11)
+ self.assertEqual(pt * num.value(), pt * 11)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/global.h b/sources/shiboken6/tests/otherbinding/global.h
new file mode 100644
index 000000000..af796734a
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/global.h
@@ -0,0 +1,11 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "../samplebinding/global.h"
+#include "extendsnoimplicitconversion.h"
+#include "number.h"
+#include "otherderived.h"
+#include "otherobjecttype.h"
+#include "othermultiplederived.h"
+#include "othertypesystypedef.h"
+#include "smartptrtester.h"
diff --git a/sources/shiboken6/tests/otherbinding/module_reload_test.py b/sources/shiboken6/tests/otherbinding/module_reload_test.py
new file mode 100644
index 000000000..bde2f5236
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/module_reload_test.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+from importlib import reload
+import os
+import shutil
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+
+orig_path = Path(__file__).parent
+workdir = Path.cwd()
+src = orig_path / 'test_module_template.py'
+dst = workdir / 'test_module.py'
+shutil.copyfile(src, dst)
+sys.path.append(os.fspath(workdir))
+
+
+class TestModuleReloading(unittest.TestCase):
+
+ def testModuleReloading(self):
+ '''Test module reloading with on-the-fly modifications.'''
+ import test_module
+ for i in range(3):
+ oldObject = test_module.obj
+ self.assertTrue(oldObject is test_module.obj)
+ reload(test_module)
+ self.assertFalse(oldObject is test_module.obj)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/new_ctor_operator_test.py b/sources/shiboken6/tests/otherbinding/new_ctor_operator_test.py
new file mode 100644
index 000000000..d6c356436
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/new_ctor_operator_test.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests calling Str constructor using a Number parameter, being that number defines
+ a cast operator to Str.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Str
+from other import Number
+
+
+class NewCtorOperatorTest(unittest.TestCase):
+ '''Tests calling Str constructor using a Number parameter, being that number
+ defines a cast operator to Str.'''
+
+ def testNumber(self):
+ '''Basic test to see if the Number class is Ok.'''
+ value = 123
+ num = Number(value)
+ self.assertEqual(num.value(), value)
+
+ def testStrCtorWithNumberArgument(self):
+ '''Try to build a Str from 'sample' module with a Number argument from 'other' module.'''
+ value = 123
+ num = Number(value)
+ string = Str(num) # noqa: F841
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/objtypehashes_test.py b/sources/shiboken6/tests/otherbinding/objtypehashes_test.py
new file mode 100644
index 000000000..d2cd7de5b
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/objtypehashes_test.py
@@ -0,0 +1,34 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import HandleHolder
+from shiboken6 import Shiboken
+
+
+class TestHashFuncs (unittest.TestCase):
+
+ def testIt(self):
+ obj1 = HandleHolder()
+ obj2 = HandleHolder()
+
+ hash1 = hash(obj1)
+ hash2 = hash(obj2)
+ self.assertNotEqual(hash1, hash2)
+
+ # Now invalidate the object and test its hash. It shouldn't segfault.
+ Shiboken.invalidate(obj1)
+
+ hash1_2 = hash(obj1)
+ self.assertEqual(hash1_2, hash1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/other-binding.txt.in b/sources/shiboken6/tests/otherbinding/other-binding.txt.in
new file mode 100644
index 000000000..d85f6030a
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/other-binding.txt.in
@@ -0,0 +1,20 @@
+[generator-project]
+
+generator-set = shiboken
+
+header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h
+typesystem-file = @other_TYPESYSTEM@
+
+output-directory = @CMAKE_CURRENT_BINARY_DIR@
+
+include-path = @libother_SOURCE_DIR@
+include-path = @libsmart_SOURCE_DIR@
+include-path = @libsample_SOURCE_DIR@
+include-path = @libsample_SOURCE_DIR@/..
+
+typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@
+typesystem-path = @sample_SOURCE_DIR@
+typesystem-path = @smart_SOURCE_DIR@
+
+enable-parent-ctor-heuristic
+lean-headers
diff --git a/sources/shiboken6/tests/otherbinding/otherbinding.pyproject b/sources/shiboken6/tests/otherbinding/otherbinding.pyproject
new file mode 100644
index 000000000..d1bbee11e
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/otherbinding.pyproject
@@ -0,0 +1,17 @@
+{
+ "files": ["collector_external_operator_test.py",
+ "conversion_operator_for_class_without_implicit_conversions_test.py",
+ "extended_multiply_operator_test.py",
+ "module_reload_test.py",
+ "new_ctor_operator_test.py",
+ "objtypehashes_test.py",
+ "otherderived_test.py",
+ "othertypesystypedef_test.py",
+ "signature_test.py",
+ "smartptr_test.py",
+ "test_module_template.py",
+ "typediscovery_test.py",
+ "usersprimitivefromothermodule_test.py",
+ "wrongctor_test.py",
+ "typesystem_other.xml"]
+}
diff --git a/sources/shiboken6/tests/otherbinding/otherderived_test.py b/sources/shiboken6/tests/otherbinding/otherderived_test.py
new file mode 100644
index 000000000..459f474f1
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/otherderived_test.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for OtherDerived class'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Abstract, Derived
+from other import OtherDerived, Number
+
+
+class Multiple(Derived, Number):
+ def __init__(self):
+ Derived.__init__(self, 42)
+ Number.__init__(self, 42)
+
+ def testCall(self):
+ return True
+
+
+class OtherDeviant(OtherDerived):
+ def __init__(self):
+ OtherDerived.__init__(self)
+ self.pure_virtual_called = False
+ self.unpure_virtual_called = False
+
+ def pureVirtual(self):
+ self.pure_virtual_called = True
+
+ def unpureVirtual(self):
+ self.unpure_virtual_called = True
+
+ def className(self):
+ return 'OtherDeviant'
+
+
+class MultipleTest(unittest.TestCase):
+ '''Test case for Multiple derived class'''
+
+ def testConstructor(self):
+ o = Multiple()
+ self.assertTrue(isinstance(o, Multiple))
+ self.assertTrue(isinstance(o, Number))
+ self.assertTrue(isinstance(o, Derived))
+ del o
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ def testMethodCall(self):
+ o = Multiple()
+ self.assertTrue(o.id_(), 42)
+ self.assertTrue(o.value(), 42)
+ self.assertTrue(o.testCall())
+
+
+class OtherDerivedTest(unittest.TestCase):
+ '''Test case for OtherDerived class'''
+
+ def testParentClassMethodsAvailability(self):
+ '''Test if OtherDerived class really inherits its methods from parent.'''
+ inherited_methods = set(['callPureVirtual', 'callUnpureVirtual',
+ 'id_', 'pureVirtual', 'unpureVirtual'])
+ self.assertTrue(inherited_methods.issubset(dir(OtherDerived)))
+
+ def testReimplementedPureVirtualMethodCall(self):
+ '''Test if a Python override of a implemented pure virtual method is
+ correctly called from C++.'''
+ d = OtherDeviant()
+ d.callPureVirtual()
+ self.assertTrue(d.pure_virtual_called)
+
+ def testReimplementedVirtualMethodCall(self):
+ '''Test if a Python override of a reimplemented virtual method is
+ correctly called from C++.'''
+ d = OtherDeviant()
+ d.callUnpureVirtual()
+ self.assertTrue(d.unpure_virtual_called)
+
+ def testVirtualMethodCallString(self):
+ '''Test virtual method call returning string.'''
+ d = OtherDerived()
+ self.assertEqual(d.className(), 'OtherDerived')
+ self.assertEqual(d.getClassName(), 'OtherDerived')
+
+ def testReimplementedVirtualMethodCallReturningString(self):
+ '''Test if a Python override of a reimplemented virtual method is
+ correctly called from C++.'''
+ d = OtherDeviant()
+ self.assertEqual(d.className(), 'OtherDeviant')
+ self.assertEqual(d.getClassName(), 'OtherDeviant')
+
+ def testCallToMethodWithAbstractArgument(self):
+ '''Call to method that expects an Abstract argument.'''
+ objId = 123
+ d = OtherDerived(objId)
+ self.assertEqual(Abstract.getObjectId(d), objId)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/othertypesystypedef_test.py b/sources/shiboken6/tests/otherbinding/othertypesystypedef_test.py
new file mode 100644
index 000000000..198c71693
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/othertypesystypedef_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for a class that holds a void pointer.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from other import (OtherValueWithUnitUser, ValueWithUnitIntMillimeter)
+from sample import (ValueWithUnitDoubleMillimeter)
+
+
+class OtherTypeSysTypeDefTest(unittest.TestCase):
+ '''Test case type system typedefs across modules.'''
+
+ def test(self):
+ # Exercise existing typedefs from "sample"
+ mm_value = ValueWithUnitDoubleMillimeter(2540)
+ inch_value = OtherValueWithUnitUser.doubleMillimeterToInch(mm_value)
+ self.assertEqual(int(inch_value.value()), 10)
+ # Exercise typedefs in "other"
+ mm_value = ValueWithUnitIntMillimeter(2540)
+ inch_value = OtherValueWithUnitUser.intMillimeterToInch(mm_value)
+ self.assertEqual(inch_value.value(), 10)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/signature_test.py b/sources/shiboken6/tests/otherbinding/signature_test.py
new file mode 100644
index 000000000..8db3e566b
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/signature_test.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for functions signature'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from other import OtherObjectType
+from shiboken_test_helper import objectFullname
+
+from shibokensupport.signature import get_signature
+
+
+class SignatureTest(unittest.TestCase):
+
+ # Check if the argument of
+ # 'OtherObjectType::enumAsInt(SampleNamespace::SomeClass::PublicScopedEnum value)'
+ # has the correct representation
+ def testNamespaceFromOtherModule(self):
+ argType = get_signature(OtherObjectType.enumAsInt).parameters["value"].annotation
+ self.assertEqual(objectFullname(argType),
+ "sample.SampleNamespace.SomeClass.PublicScopedEnum")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/smartptr_test.py b/sources/shiboken6/tests/otherbinding/smartptr_test.py
new file mode 100644
index 000000000..fd5c7fa09
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/smartptr_test.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for the SmartPtrTester class'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from other import SmartPtrTester
+
+
+class SmartPtrTest(unittest.TestCase):
+ '''Test case for the SmartPtrTester class'''
+
+ def test(self):
+ tester = SmartPtrTester()
+
+ integerPtr = tester.createSharedPtrInteger(42)
+ self.assertEqual(tester.valueOfSharedPtrInteger(integerPtr), 42)
+
+ strPtr = tester.createSharedPtrStr('hello')
+ self.assertEqual(tester.valueOfSharedPtrStr(strPtr), 'hello')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/star_import_test.py b/sources/shiboken6/tests/otherbinding/star_import_test.py
new file mode 100644
index 000000000..4b5f1d270
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/star_import_test.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+"""PYSIDE-2404: Test whether star imports work as they require special handling
+ by the lazy initialization."""
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+SHIBOKEN_NAME = "shiboken6.Shiboken"
+MINIMAL_NAME = "minimal"
+OTHER_NAME = "other"
+
+shiboken_loaded = 1 if sys.modules.get(SHIBOKEN_NAME) else 0
+minimal_loaded = 1 if sys.modules.get(MINIMAL_NAME) else 0
+other_loaded = 1 if sys.modules.get(OTHER_NAME) else 0
+
+from minimal import * # noqa: F403
+
+shiboken_loaded += 2 if sys.modules.get(SHIBOKEN_NAME) else 0
+minimal_loaded += 2 if sys.modules.get(MINIMAL_NAME) else 0
+other_loaded += 2 if sys.modules.get(OTHER_NAME) else 0
+
+from other import Number # noqa: F403
+from other import * # noqa: F403
+
+shiboken_loaded += 4 if sys.modules.get(SHIBOKEN_NAME) else 0
+minimal_loaded += 4 if sys.modules.get(MINIMAL_NAME) else 0
+other_loaded = +4 if sys.modules.get(OTHER_NAME) else 0
+
+import shiboken6.Shiboken # noqa: F401 F403
+
+shiboken_loaded += 8 if sys.modules.get(SHIBOKEN_NAME) else 0
+
+
+class ValTest(unittest.TestCase):
+
+ def test(self):
+ val_id = 123
+ val = Val(val_id) # noqa: F405
+ self.assertEqual(val.valId(), val_id)
+
+
+class Simple(Number):
+
+ def __init__(self):
+ Number.__init__(self, 42)
+
+
+class OtherTest(unittest.TestCase):
+
+ def testConstructor(self):
+ o = Simple()
+ self.assertTrue(isinstance(o, Number))
+
+
+class StarImportTest(unittest.TestCase):
+ """
+ This test is meant for Lazy Init.
+ We explicitly choose modules which are able to lazy load.
+
+ The ValTest:
+ ------------
+ We load something with `import *`.
+ There is no module from our known ones imported.
+ This means we need stack introspection to find out that this was
+ a star import and we must disable lazyness.
+
+ The OtherTest:
+ --------------
+ We load something normally that should be lazy.
+ After that, we follow with a star import.
+ Now the stack introspection does not work, because the loading is
+ cached. The first import did a lazy load. The following star import
+ needs to undo the lazyness. But now we have a redirected import.
+
+ All tests simply check if the objects are real and not just names.
+ The <module>_loaded tests prevend upcoming internal dependencies.
+
+ To make sure that Shiboken is really not involved, it is checked
+ and really imported afterwards (ensuring nothing is misspelled).
+ """
+
+ def testStar(self):
+ self.assertEqual(other_loaded, 4)
+ self.assertEqual(minimal_loaded, 6)
+ self.assertEqual(shiboken_loaded, 14)
+ # Interesting effect: Did not expect that shiboken is loaded at all.
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/test_module_template.py b/sources/shiboken6/tests/otherbinding/test_module_template.py
new file mode 100644
index 000000000..36ab43ae3
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/test_module_template.py
@@ -0,0 +1,24 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from other import OtherObjectType
+from sample import ObjectType
+
+
+class MyObjectType(ObjectType):
+ pass
+
+
+class MyOtherObjectType(OtherObjectType):
+ value = 10
+
+
+obj = MyObjectType()
diff --git a/sources/shiboken6/tests/otherbinding/typediscovery_test.py b/sources/shiboken6/tests/otherbinding/typediscovery_test.py
new file mode 100644
index 000000000..39dc5cf0f
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/typediscovery_test.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for type discovery'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import (Abstract, Base1, Derived,
+ MDerived1, SonOfMDerived1, MDerived3)
+from other import OtherMultipleDerived
+
+
+class TypeDiscoveryTest(unittest.TestCase):
+
+ def testPureVirtualsOfImpossibleTypeDiscovery(self):
+ a = Derived.triggerImpossibleTypeDiscovery()
+ self.assertEqual(type(a), Abstract)
+ # call some pure virtual method
+ a.pureVirtual()
+
+ def testAnotherImpossibleTypeDiscovery(self):
+ a = Derived.triggerAnotherImpossibleTypeDiscovery()
+ self.assertEqual(type(a), Derived)
+
+ def testMultipleInheritance(self):
+ obj = OtherMultipleDerived.createObject("Base1")
+ self.assertEqual(type(obj), Base1)
+ # 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), MDerived1)
+ obj = OtherMultipleDerived.createObject("SonOfMDerived1")
+ self.assertEqual(type(obj), SonOfMDerived1)
+ obj = OtherMultipleDerived.createObject("MDerived3")
+ 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)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/typesystem_other.xml b/sources/shiboken6/tests/otherbinding/typesystem_other.xml
new file mode 100644
index 000000000..ade1c8bad
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/typesystem_other.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<typesystem package="other">
+ <load-typesystem name="typesystem_sample.xml" generate="no" />
+ <load-typesystem name="typesystem_smart.xml" generate="no" />
+
+ <object-type name="OtherObjectType" />
+ <object-type name="OtherDerived" />
+ <object-type name="OtherMultipleDerived" />
+
+ <value-type name="ExtendsNoImplicitConversion" />
+ <value-type name="Number" />
+
+ <smart-pointer-type name="SharedPtr" type="shared" getter="data" ref-count-method="useCount"
+ instantiations="Str"/>
+ <value-type name="SmartPtrTester"/>
+
+ <typedef-type name="ValueWithUnitIntInch" source="ValueWithUnit&lt;int,LengthUnit::Inch&gt;"/>
+ <typedef-type name="ValueWithUnitIntMillimeter" source="ValueWithUnit&lt;int,LengthUnit::Millimeter&gt;"/>
+ <value-type name="OtherValueWithUnitUser"/>
+</typesystem>
diff --git a/sources/shiboken6/tests/otherbinding/usersprimitivefromothermodule_test.py b/sources/shiboken6/tests/otherbinding/usersprimitivefromothermodule_test.py
new file mode 100644
index 000000000..15a988326
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/usersprimitivefromothermodule_test.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests user defined primitive type from a required module.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from other import Number
+
+
+class UserDefinedPrimitiveTypeFromRequiredModuleTest(unittest.TestCase):
+
+ def testUsersPrimitiveFromRequiredModuleAsArgument(self):
+ '''static Number Number::fromComplex(Complex)'''
+ cpx = complex(3.0, 1.2)
+ number = Number.fromComplex(cpx)
+ self.assertEqual(number.value(), int(cpx.real))
+
+ def testUsersPrimitiveFromRequiredModuleAsReturnValue(self):
+ '''Complex Number::toComplex()'''
+ number = Number(12)
+ cpx = number.toComplex()
+ self.assertEqual(number.value(), int(cpx.real))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/otherbinding/wrongctor_test.py b/sources/shiboken6/tests/otherbinding/wrongctor_test.py
new file mode 100644
index 000000000..b9251b428
--- /dev/null
+++ b/sources/shiboken6/tests/otherbinding/wrongctor_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import Abstract, ObjectType
+from other import OtherDerived
+
+
+class Foo(OtherDerived):
+ def __init__(self):
+ Abstract.__init__(self, 2) # this should raise an exception
+
+
+class Foo2(ObjectType, OtherDerived):
+ def __init__(self):
+ ObjectType.__init__(self)
+ Abstract.__init__(self, 2) # this should raise an exception
+
+
+class WrongCtorTest(unittest.TestCase):
+ def testIt(self):
+ self.assertRaises(TypeError, Foo)
+ self.assertRaises(TypeError, Foo2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/qtxmltosphinx/CMakeLists.txt b/sources/shiboken6/tests/qtxmltosphinx/CMakeLists.txt
new file mode 100644
index 000000000..11b22f038
--- /dev/null
+++ b/sources/shiboken6/tests/qtxmltosphinx/CMakeLists.txt
@@ -0,0 +1,32 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.18)
+
+# Standalone-buildable
+
+project(qtxmltosphinx)
+
+set(CMAKE_AUTOMOC ON)
+
+find_package(Qt6 COMPONENTS Core)
+
+set(generator_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../generator)
+set(api_extractor_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../ApiExtractor)
+
+set(qtxmltosphinx_SRC
+ ${generator_src_dir}/qtdoc/qtxmltosphinx.cpp
+ ${api_extractor_src_dir}/codesniphelpers.cpp
+ ${api_extractor_src_dir}/textstream.cpp
+ main.cpp)
+
+add_executable(qtxmltosphinx ${qtxmltosphinx_SRC})
+
+target_include_directories(qtxmltosphinx PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${api_extractor_src_dir}
+ ${generator_src_dir}
+ ${generator_src_dir}/shiboken
+ ${generator_src_dir}/qtdoc)
+
+target_link_libraries(qtxmltosphinx PRIVATE Qt::Core)
diff --git a/sources/shiboken6/tests/qtxmltosphinx/main.cpp b/sources/shiboken6/tests/qtxmltosphinx/main.cpp
new file mode 100644
index 000000000..5b0624376
--- /dev/null
+++ b/sources/shiboken6/tests/qtxmltosphinx/main.cpp
@@ -0,0 +1,115 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qtxmltosphinxinterface.h"
+#include "qtxmltosphinx.h"
+
+#include <QtCore/QCommandLineParser>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QFile>
+#include <QtCore/QLoggingCategory>
+
+#include <exception>
+#include <iostream>
+
+using namespace Qt::StringLiterals;
+
+static const char help[] = R"(QtXmlToSphinx WebXML to rst converter
+
+A manual test for converting WebXML files to rst files for checking
+formatting.
+)";
+
+Q_LOGGING_CATEGORY(lcQtXmlToSphinx, "qt.xmltosphinx");
+
+static std::ostream &operator<<(std::ostream &str, const QString &s)
+{
+ str << s.toUtf8().constData();
+ return str;
+}
+
+class QtXmlToSphinxDocGenerator : public QtXmlToSphinxDocGeneratorInterface
+{
+public:
+ QtXmlToSphinxDocGenerator() = default;
+
+ QString expandFunction(const QString &) const override;
+ QString expandClass(const QString &, const QString &) const override;
+ QString resolveContextForMethod(const QString &,
+ 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
+QString QtXmlToSphinxDocGenerator::expandFunction(const QString &) const
+{
+ return {};
+}
+
+QString QtXmlToSphinxDocGenerator::expandClass(const QString &, const QString &) const
+{
+ return {};
+}
+
+QString QtXmlToSphinxDocGenerator::resolveContextForMethod(const QString &, const QString &) const
+{
+ return {};
+}
+
+const QLoggingCategory &QtXmlToSphinxDocGenerator::loggingCategory() const
+{
+ return lcQtXmlToSphinx();
+}
+
+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;
+ QtXmlToSphinxParameters parameters;
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ std::cerr << "Cannot open " << fileName << ": " << file.errorString() << '\n';
+ return false;
+ }
+ const QString xml = QString::fromUtf8(file.readAll());
+ file.close();
+ std::cout << QtXmlToSphinx(&generator, parameters, xml).result();
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ QCommandLineParser commandLineParser;
+ commandLineParser.setApplicationDescription(QString::fromLatin1(help));
+ commandLineParser.addHelpOption();
+ commandLineParser.addPositionalArgument(u"[file]"_s, u"WebXML file to process."_s);
+ commandLineParser.process(QCoreApplication::arguments());
+ if (commandLineParser.positionalArguments().isEmpty())
+ commandLineParser.showHelp(0); // quits
+
+ int exitCode = 1;
+ try {
+ if (run(commandLineParser.positionalArguments().constFirst()))
+ exitCode = 0;
+ } catch (const std::exception &e) {
+ std::cerr << "An exception occurred: " << e.what() << '\n';
+ }
+ return exitCode;
+}
diff --git a/sources/shiboken6/tests/qtxmltosphinxtest/CMakeLists.txt b/sources/shiboken6/tests/qtxmltosphinxtest/CMakeLists.txt
new file mode 100644
index 000000000..25074e716
--- /dev/null
+++ b/sources/shiboken6/tests/qtxmltosphinxtest/CMakeLists.txt
@@ -0,0 +1,38 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.18)
+
+project(qtxmltosphinxtest)
+
+set(CMAKE_AUTOMOC ON)
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Test)
+
+set(generator_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../generator)
+set(api_extractor_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../ApiExtractor)
+
+set(qtxmltosphinxtest_SRC
+ ${generator_src_dir}/qtdoc/qtxmltosphinx.cpp
+ ${api_extractor_src_dir}/codesniphelpers.cpp
+ ${api_extractor_src_dir}/textstream.cpp
+ qtxmltosphinxtest.cpp
+ qtxmltosphinxtest.h)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR}
+ ${api_extractor_src_dir}
+ ${generator_src_dir}
+ ${generator_src_dir}/shiboken
+ ${generator_src_dir}/qtdoc)
+
+add_executable(qtxmltosphinxtest ${qtxmltosphinxtest_SRC})
+
+target_link_libraries(qtxmltosphinxtest PRIVATE
+ Qt::Core
+ Qt::Test)
+
+add_test("qtxmltosphinx" qtxmltosphinxtest)
+if (INSTALL_TESTS)
+ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/qtxmltosphinxtest DESTINATION ${TEST_INSTALL_DIR})
+endif()
diff --git a/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp
new file mode 100644
index 000000000..3ba77196f
--- /dev/null
+++ b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp
@@ -0,0 +1,517 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qtxmltosphinxtest.h"
+#include "qtxmltosphinx.h"
+#include <QtTest/QTest>
+
+#include <QtCore/QBuffer>
+#include <QtCore/QDebug>
+#include <QtCore/QLoggingCategory>
+
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcQtXmlToSphinxTest, "qt.sphinxtabletest");
+
+// QtXmlToSphinxDocGeneratorInterface
+QString QtXmlToSphinxTest::expandFunction(const QString &) const
+{
+ return {};
+}
+
+QString QtXmlToSphinxTest::expandClass(const QString &, const QString &) const
+{
+ return {};
+}
+
+QString QtXmlToSphinxTest::resolveContextForMethod(const QString &, const QString &) const
+{
+ return {};
+}
+
+const QLoggingCategory &QtXmlToSphinxTest::loggingCategory() const
+{
+ return lcQtXmlToSphinxTest();
+}
+
+QtXmlToSphinxLink QtXmlToSphinxTest::resolveLink(const QtXmlToSphinxLink &link) const
+{
+ 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();
+}
+
+void QtXmlToSphinxTest::testTable_data()
+{
+ QTest::addColumn<QString>("xml");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("emptyString") << QString() << QString();
+
+ // testSimpleTable
+ const char *xml = R"(<table>
+ <header>
+ <item>
+ <para>Header 1</para>
+ </item>
+ <item>
+ <para>Header 2</para>
+ </item>
+ </header>
+ <row>
+ <item>
+ <para>1 1</para>
+ </item>
+ <item>
+ <para>1 2</para>
+ </item>
+ </row>
+ <row>
+ <item>
+ <para>2 1</para>
+ </item>
+ <item>
+ <para>2 2</para>
+ </item>
+ </row>
+</table>)";
+
+ const char *expected = R"(
+ +--------+--------+
+ |Header 1|Header 2|
+ +========+========+
+ |1 1 |1 2 |
+ +--------+--------+
+ |2 1 |2 2 |
+ +--------+--------+
+
+)";
+
+ QTest::newRow("testSimpleTable")
+ << QString::fromLatin1(xml) << QString::fromLatin1(expected);
+
+ // testRowSpan
+ xml = R"(<table>
+ <header>
+ <item>
+ <para>Header 1</para>
+ </item>
+ <item>
+ <para>Header 2</para>
+ </item>
+ </header>
+ <row>
+ <item colspan="2">
+ <para>I'm a big text!</para>
+ </item>
+ </row>
+ <row>
+ <item>
+ <para>2 1</para>
+ </item>
+ <item>
+ <para>2 2</para>
+ </item>
+ </row>
+</table>)";
+
+ expected = R"(
+ +---------------+--------+
+ |Header 1 |Header 2|
+ +===============+========+
+ |I'm a big text! |
+ +---------------+--------+
+ |2 1 |2 2 |
+ +---------------+--------+
+
+)";
+
+ QTest::newRow("testColSpan")
+ << QString::fromLatin1(xml) << QString::fromLatin1(expected);
+
+ // testRowSpan
+ xml = R"(<table>
+ <header>
+ <item>
+ <para>Header 1</para>
+ </item>
+ <item>
+ <para>Header 2</para>
+ </item>
+ </header>
+ <row>
+ <item rowspan="2">
+ <para>1.1</para>
+ </item>
+ <item>
+ <para>1.2</para>
+ </item>
+ </row>
+ <row>
+ <item>
+ <para>2 2</para>
+ </item>
+ </row>
+</table>)";
+
+ expected = R"(
+ +--------+--------+
+ |Header 1|Header 2|
+ +========+========+
+ |1.1 |1.2 |
+ + +--------+
+ | |2 2 |
+ +--------+--------+
+
+)";
+
+ QTest::newRow("testRowSpan")
+ << QString::fromLatin1(xml) << QString::fromLatin1(expected);
+
+ // testComplexTable
+ xml = R"(<table>
+ <header>
+ <item>
+ <para>Header 1</para>
+ </item>
+ <item>
+ <para>Header 2</para>
+ </item>
+ <item>
+ <para>Header 3</para>
+ </item>
+ </header>
+ <row>
+ <item rowspan="2">
+ <para>1.1</para>
+ </item>
+ <item colspan="2">
+ <para>1.2</para>
+ </item>
+ </row>
+ <row>
+ <item>
+ <para>2 2</para>
+ </item>
+ <item>
+ <para>2 3</para>
+ </item>
+ </row>
+</table>)";
+
+ expected = R"(
+ +--------+--------+--------+
+ |Header 1|Header 2|Header 3|
+ +========+========+========+
+ |1.1 |1.2 |
+ + +--------+--------+
+ | |2 2 |2 3 |
+ +--------+--------+--------+
+
+)";
+
+ QTest::newRow("testComplexTable")
+ << QString::fromLatin1(xml) << QString::fromLatin1(expected);
+
+ // testRowSpan2
+ xml = R"(<table>
+ <header>
+ <item><para>h1</para></item>
+ <item><para>h2</para></item>
+ <item><para>h3</para></item>
+ <item><para>h4</para></item>
+ </header>
+ <row>
+ <item rowspan="6"><para>A</para></item>
+ <item rowspan="6"><para>B</para></item>
+ <item><para>C</para></item>
+ <item><para>D</para></item>
+ </row>
+ <row>
+ <item><para>E</para></item>
+ <item><para>F</para></item>
+ </row>
+ <row>
+ <item><para>E</para></item>
+ <item><para>F</para></item>
+ </row>
+ <row>
+ <item><para>E</para></item>
+ <item><para>F</para></item>
+ </row>
+ <row>
+ <item><para>E</para></item>
+ <item><para>F</para></item>
+ </row>
+ <row>
+ <item><para>E</para></item>
+ <item><para>F</para></item>
+ </row>
+</table>)";
+
+ expected = R"(
+ +--+--+--+--+
+ |h1|h2|h3|h4|
+ +==+==+==+==+
+ |A |B |C |D |
+ + + +--+--+
+ | | |E |F |
+ + + +--+--+
+ | | |E |F |
+ + + +--+--+
+ | | |E |F |
+ + + +--+--+
+ | | |E |F |
+ + + +--+--+
+ | | |E |F |
+ +--+--+--+--+
+
+)";
+
+ QTest::newRow("testRowSpan2")
+ << QString::fromLatin1(xml) << QString::fromLatin1(expected);
+
+ // testNestedList
+ xml = R"(<table>
+ <row>
+ <item>
+ <list type="bullet">
+ <item>
+ <para>I11</para>
+ </item>
+ <item>
+ <para>I21</para>
+ </item>
+ </list>
+ </item>
+ <item>
+ <list type="bullet">
+ <item>
+ <para>I12</para>
+ </item>
+ <item>
+ <para>I22</para>
+ </item>
+ </list>
+ </item>
+ </row>
+</table>)";
+
+ expected = R"(
+ +---------+---------+
+ | * I11| * I12|
+ | * I21| * I22|
+ +---------+---------+
+
+)";
+
+ QTest::newRow("testNestedList")
+ << QString::fromLatin1(xml) << QString::fromLatin1(expected);
+
+ // testBrokenTable
+ xml = R"(<table>
+ <header>
+ <item>
+ <para>Header 1</para>
+ </item>
+ <item>
+ <para>Header 2</para>
+ </item>
+ </header>
+ <row>
+ <item>
+ <para>1.1</para>
+ </item>
+ <item>
+ <para>1.2</para>
+ </item>
+ </row>
+ <row>
+ <item colspan="2">
+ <para>2 2</para>
+ </item>
+ <item>
+ <para>2 3</para>
+ </item>
+ <item>
+ <para>2 4</para>
+ </item>
+ <item>
+ <para>2 5</para>
+ </item>
+ </row>
+ <row>
+ <item>
+ <para>3 1</para>
+ </item>
+ <item>
+ <para>3 2</para>
+ </item>
+ <item>
+ <para>3 3</para>
+ </item>
+ </row>
+</table>)";
+
+ expected = R"(
+ +--------+------------+
+ |Header 1|Header 2 |
+ +========+============+
+ |1.1 |1.2 |
+ +--------+------------+
+ |2 2 2 3 2 4 2 5|
+ +--------+------------+
+ |3 1 |3 2 3 3 |
+ +--------+------------+
+
+)";
+
+ QTest::newRow("testBrokenTable")
+ << QString::fromLatin1(xml) << QString::fromLatin1(expected);
+}
+
+void QtXmlToSphinxTest::testTable()
+{
+ QFETCH(QString, xml);
+ QFETCH(QString, expected);
+
+ const QString actual = transformXml(xml);
+
+ QEXPECT_FAIL("testBrokenTable", "testBrokenTable fails", Continue);
+ QCOMPARE(actual, expected);
+}
+
+using TablePtr = std::shared_ptr<QtXmlToSphinx::Table>;
+
+Q_DECLARE_METATYPE(TablePtr);
+
+void QtXmlToSphinxTest::testTableFormatting_data()
+{
+ using TableCell = QtXmlToSphinx::TableCell;
+
+ QTest::addColumn<TablePtr>("table");
+ QTest::addColumn<QString>("expected");
+
+ TablePtr table(new QtXmlToSphinx::Table);
+ table->appendRow({TableCell("item11"), TableCell("item12")});
+ table->appendRow({TableCell(""), TableCell("item22")});
+ table->normalize();
+
+ const char *expected = R"(+------+------+
+|item11|item12|
++------+------+
+| |item22|
++------+------+
+
+)";
+
+ QTest::newRow("normal") << table << QString::fromLatin1(expected);
+
+ table.reset(new QtXmlToSphinx::Table);
+ table->appendRow({TableCell("item11"), TableCell("item12\nline2")});
+ table->appendRow({TableCell(""), TableCell("item22\nline2\nline3")});
+ table->normalize();
+
+ expected = R"(+------+------+
+|item11|item12|
+| |line2 |
++------+------+
+| |item22|
+| |line2 |
+| |line3 |
++------+------+
+
+)";
+
+ QTest::newRow("multi-line") << table << QString::fromLatin1(expected);
+}
+
+void QtXmlToSphinxTest::testTableFormatting()
+{
+ QFETCH(TablePtr, table);
+ QFETCH(QString, expected);
+
+ StringStream str;
+ table->format(str);
+ const QString actual = str.toString();
+
+ QCOMPARE(actual, expected);
+}
+
+void QtXmlToSphinxTest::testTableFormattingIoDevice_data()
+{
+ testTableFormatting_data();
+}
+
+void QtXmlToSphinxTest::testTableFormattingIoDevice()
+{
+ QFETCH(TablePtr, table);
+ QFETCH(QString, expected);
+
+ QByteArray byteArray;
+ {
+ TextStream str(&byteArray);
+ table->format(str);
+ }
+ const QString actual = QString::fromUtf8(byteArray);
+
+ QCOMPARE(actual, expected);
+}
+
+void QtXmlToSphinxTest::testSnippetExtraction_data()
+{
+ QTest::addColumn<QByteArray>("file");
+ QTest::addColumn<QLatin1StringView>("id");
+ QTest::addColumn<QString>("expected");
+
+ const char *fileCpp = R"(bla
+// ![snip1]
+snip1_line1
+// ![snip1] // ![snip2]
+snip2_line1
+snip2_line2
+// ![snip2] // ![snip3]
+)";
+
+ constexpr auto id = "snip2"_L1;
+ const QString expected = uR"(snip2_line1
+snip2_line2
+)"_s;
+
+ const char *filePython = R"(bla
+# ![snip1]
+snip1_line1
+# ![snip1] # ![snip2]
+snip2_line1
+snip2_line2
+# ![snip2] # ![snip3]
+)";
+
+ QTest::newRow("c++") << QByteArray(fileCpp) << id << expected;
+ QTest::newRow("Python") << QByteArray(filePython) << id << expected;
+}
+
+void QtXmlToSphinxTest::testSnippetExtraction()
+{
+ QFETCH(QByteArray, file);
+ QFETCH(QLatin1StringView, id);
+ QFETCH(QString, expected);
+
+ QBuffer buffer(&file);
+ QVERIFY(buffer.open(QIODevice::ReadOnly));
+ QString errorMessage;
+ QString actual = QtXmlToSphinx::readSnippet(buffer, id, &errorMessage);
+ QVERIFY2(errorMessage.isEmpty(), qPrintable(errorMessage));
+ QCOMPARE(actual, expected);
+}
+
+QTEST_APPLESS_MAIN( QtXmlToSphinxTest)
diff --git a/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h
new file mode 100644
index 000000000..5108ef452
--- /dev/null
+++ b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QTXMLTOSPHINXTEST_H
+#define QTXMLTOSPHINXTEST_H
+
+#include "qtxmltosphinxinterface.h"
+
+#include <QtCore/QObject>
+
+class QtXmlToSphinxTest : public QObject, public QtXmlToSphinxDocGeneratorInterface
+{
+ Q_OBJECT
+public:
+ // QtXmlToSphinxDocGeneratorInterface
+ QString expandFunction(const QString &) const override;
+ QString expandClass(const QString &, const QString &) const override;
+ QString resolveContextForMethod(const QString &,
+ 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();
+ void testTable();
+ void testTableFormatting_data();
+ void testTableFormatting();
+ void testTableFormattingIoDevice_data();
+ void testTableFormattingIoDevice();
+ void testSnippetExtraction_data();
+ void testSnippetExtraction();
+
+private:
+ QString transformXml(const QString &xml) const;
+
+ QtXmlToSphinxParameters m_parameters;
+};
+
+#endif // QTXMLTOSPHINXTEST_H
diff --git a/sources/shiboken6/tests/samplebinding/CMakeLists.txt b/sources/shiboken6/tests/samplebinding/CMakeLists.txt
new file mode 100644
index 000000000..fc812feb8
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/CMakeLists.txt
@@ -0,0 +1,176 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(sample)
+
+set(sample_TYPESYSTEM
+${CMAKE_CURRENT_SOURCE_DIR}/typesystem_sample.xml
+)
+
+set(sample_SRC
+${CMAKE_CURRENT_BINARY_DIR}/sample/abstractmodifications_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/abstract_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/arraymodifytest_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/base1_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/base2_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/base3_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/base4_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/base5_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/base6_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/blackbox_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/brush_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/bytearray_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/bucket_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/classwithfunctionpointer_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/collector_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/comparisontester_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/color_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/ctorconvrule_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/customoverloadsequence_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/cvlistuser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/cvvaluetype_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/sbkdate_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/deleteddefaultctor_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/derived_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/derivedusingct_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/derived_someinnerclass_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/echo_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/event_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/expression_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/exceptiontest_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/friendofonlycopy_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/handleholder_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/implicitconv_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/implicitbase_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/implicittarget_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/intarray2_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/intarray3_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/intlist_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/sortedoverload_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/intwrapper_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/injectcode_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/listuser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/mapuser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/mderived1_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/mderived2_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/mderived3_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/mderived4_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/mderived5_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/modelindex_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/modifications_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/modifiedconstructor_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/noimplicitconversion_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/nondefaultctor_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objectmodel_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objecttype_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypebyvalue_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypeholder_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypederived_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypelayout_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypeptrlist_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypeoperators_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objectview_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/objtypereference_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/oddbooluser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/onlycopy_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/otherbase_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/overload_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/overload2_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/pairuser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/pen_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/persistentmodelindex_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/photon_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/photon_base_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueidentity_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueduplicator_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/point_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/pointerholder_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/pointf_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/pointvaluelist_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/polygon_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/primitivestructpointerholder_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/privatector_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/privatedtor_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/protectedenumclass_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/protectednonpolymorphic_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/protectedpolymorphic_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/protectedpolymorphicdaughter_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/protectedpolymorphicgranddaughter_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/protectedproperty_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/protectedvirtualdestructor_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/rect_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/rectf_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/reference_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/referentmodelindex_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/toberenamedvalue_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/removednamespace1_objectoninvisiblenamespace_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/renameduser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/sample_module_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/sample_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/sample_sample_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_ctparam_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_inlinenamespace_classwithininlinenamespace_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_okthisisrecursiveenough_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someotherinnerclass_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_derivedfromnamespace_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/stdcomplex_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/simplefile_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/size_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/sizef_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/snakecasetest_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/snakecasederivedtest_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/sonofmderived1_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/spaceshipcomparisontester_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/str_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/strlist_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/time_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/templateptr_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/unremovednamespace_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/valuewithunitdoubleinch_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/valuewithunitdoublemillimeter_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/valuewithunituser_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/virtualdaughter_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/virtualdaughter2_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/virtualfinaldaughter_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/virtualdtor_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/virtualmethods_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/voidholder_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/valueandvirtual_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/filter_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/data_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/intersection_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/union_wrapper.cpp
+)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sample-binding.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt" @ONLY)
+
+shiboken_get_tool_shell_wrapper(shiboken tool_wrapper)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+ BYPRODUCTS ${sample_SRC}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Shiboken6::shiboken6>
+ --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt
+ ${GENERATOR_EXTRA_FLAGS}
+ DEPENDS ${sample_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h Shiboken6::shiboken6
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Running generator for 'sample' test binding..."
+)
+
+add_library(sample MODULE ${sample_SRC})
+target_include_directories(sample PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(sample PUBLIC libsample libshiboken)
+set_property(TARGET sample PROPERTY PREFIX "")
+set_property(TARGET sample PROPERTY OUTPUT_NAME "sample${PYTHON_EXTENSION_SUFFIX}")
+
+if(WIN32)
+ set_property(TARGET sample PROPERTY SUFFIX ".pyd")
+endif()
+
+create_generator_target(sample)
diff --git a/sources/shiboken6/tests/samplebinding/__del___test.py b/sources/shiboken6/tests/samplebinding/__del___test.py
new file mode 100644
index 000000000..456886614
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/__del___test.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+import sample
+
+delCalled = False
+
+
+class MyObject(sample.ObjectType):
+ def __del__(self):
+ global delCalled
+ delCalled = True
+
+
+class TestDel(unittest.TestCase):
+ def testIt(self):
+ a = MyObject()
+ del a
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertTrue(delCalled)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/abstract_test.py b/sources/shiboken6/tests/samplebinding/abstract_test.py
new file mode 100644
index 000000000..89e87be1d
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/abstract_test.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for Abstract class'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Abstract
+
+
+class Incomplete(Abstract):
+ def __init__(self):
+ Abstract.__init__(self)
+
+
+class Concrete(Abstract):
+ def __init__(self):
+ Abstract.__init__(self)
+ self.pure_virtual_called = False
+ self.unpure_virtual_called = False
+
+ def pureVirtual(self):
+ self.pure_virtual_called = True
+
+ def pureVirtualReturningVoidPtr(self):
+ return 42
+
+ def unpureVirtual(self):
+ self.unpure_virtual_called = True
+
+ def virtualGettingAEnum(self, enum):
+ self.virtual_getting_enum = True
+
+
+class AbstractTest(unittest.TestCase):
+ '''Test case for Abstract class'''
+
+ def testAbstractPureVirtualMethodAvailability(self):
+ '''Test if Abstract class pure virtual method was properly wrapped.'''
+ self.assertTrue('pureVirtual' in dir(Abstract))
+
+ def testAbstractInstanciation(self):
+ '''Test if instanciation of an abstract class raises the correct exception.'''
+ self.assertRaises(NotImplementedError, Abstract)
+
+ def testUnimplementedPureVirtualMethodCall(self):
+ '''Test if calling a pure virtual method raises the correct exception.'''
+ i = Incomplete()
+ self.assertRaises(NotImplementedError, i.pureVirtual)
+
+ def testPureVirtualReturningVoidPtrReturnValue(self):
+ '''Test if a pure virtual method returning void ptr can be properly reimplemented'''
+ # Note that the semantics of reimplementing the pure virtual method in
+ # Python and calling it from C++ is undefined until it's decided how to
+ # cast the Python data types to void pointers
+ c = Concrete()
+ self.assertEqual(c.pureVirtualReturningVoidPtr(), 42)
+
+ def testReimplementedVirtualMethodCall(self):
+ '''Test if a Python override of a virtual method is correctly called from C++.'''
+ c = Concrete()
+ c.callUnpureVirtual()
+ self.assertTrue(c.unpure_virtual_called)
+
+ def testImplementedPureVirtualMethodCall(self):
+ '''Test if a Python override of a pure virtual method is correctly called from C++.'''
+ c = Concrete()
+ c.callPureVirtual()
+ self.assertTrue(c.pure_virtual_called)
+
+ def testEnumParameterOnVirtualMethodCall(self):
+ '''testEnumParameterOnVirtualMethodCall'''
+ c = Concrete()
+ c.callVirtualGettingEnum(Abstract.Short)
+ self.assertTrue(c.virtual_getting_enum)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/addedfunction_test.py b/sources/shiboken6/tests/samplebinding/addedfunction_test.py
new file mode 100644
index 000000000..0b5680143
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/addedfunction_test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for added functions.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import SampleNamespace, ObjectType, Point
+
+
+class TestAddedFunctionsWithSimilarTypes(unittest.TestCase):
+ '''Adds new signatures very similar to already existing ones.'''
+
+ def testValueTypeReferenceAndValue(self):
+ '''In C++ we have "function(const ValueType&, double)",
+ in Python we add "function(ValueType)".'''
+ point = Point(10, 20)
+ multiplier = 4.0
+ control = (point.x() + point.y()) * multiplier
+ self.assertEqual(SampleNamespace.passReferenceToValueType(point, multiplier), control)
+ control = point.x() + point.y()
+ self.assertEqual(SampleNamespace.passReferenceToValueType(point), control)
+
+ def testObjectTypeReferenceAndPointer(self):
+ '''In C++ we have "function(const ObjectType&, int)",
+ in Python we add "function(ValueType)".'''
+ obj = ObjectType()
+ obj.setObjectName('sbrubbles')
+ multiplier = 3.0
+ control = len(obj.objectName()) * multiplier
+ self.assertEqual(SampleNamespace.passReferenceToObjectType(obj, multiplier), control)
+ control = len(obj.objectName())
+ self.assertEqual(SampleNamespace.passReferenceToObjectType(obj), control)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/addedfunction_with_container_args_test.py b/sources/shiboken6/tests/samplebinding/addedfunction_with_container_args_test.py
new file mode 100644
index 000000000..2a739033b
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/addedfunction_with_container_args_test.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for added functions with nested and multi-argument container types.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import sum2d, sumproduct
+
+
+class TestAddedFunctionsWithContainerArgs(unittest.TestCase):
+ '''Tests added functions with nested and multi-argument container types.'''
+
+ def testNestedContainerType(self):
+ '''Test added function with single-argument containers.'''
+ values = [[1, 2], [3, 4, 5], [6]]
+ self.assertEqual(sum2d(values), 21)
+
+ def testMultiArgContainerType(self):
+ '''Test added function with a two-argument container.'''
+ values = [(1, 2), (3, 4), (5, 6)]
+ self.assertEqual(sumproduct(values), 44)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/argumentmodifications_test.py b/sources/shiboken6/tests/samplebinding/argumentmodifications_test.py
new file mode 100644
index 000000000..b0ca56a6d
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/argumentmodifications_test.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for method arguments modifications performed as described on typesystem.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Modifications, Point
+
+
+class ArgumentModificationsTest(unittest.TestCase):
+ '''Test cases for method arguments modifications performed as described on typesystem.'''
+
+ def setUp(self):
+ self.mods = Modifications()
+
+ def tearDown(self):
+ del self.mods
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ def testArgRemoval0(self):
+ '''Tests argument removal modifications on Modifications.argRemoval0.'''
+ # void [-> PyObject*] argRemoval0(int, bool, int = 123 [removed, new val = 321], int = 456)
+ # code-injection: returns tuple with received parameters plus removed ones
+ a0, a1, a2 = 1, True, 2
+ self.assertEqual(self.mods.argRemoval0(a0, a1), (a0, a1, 321, 456))
+ self.assertEqual(self.mods.argRemoval0(a0, a1, a2), (a0, a1, 321, a2))
+ # the other wasn't modified
+ # void argRemoval0(int, bool, int, bool)
+ self.assertEqual(self.mods.argRemoval0(0, False, 0, False), None)
+
+ def testArgRemoval1(self):
+ '''Tests argument removal modifications on Modifications.argRemoval1.'''
+ # void [-> PyObject*] argRemoval1(int, bool, Point = Point(1, 2) [removed],
+ # Point = Point(3, 4) [removed], int = 333)
+ # code-injection: returns tuple with received parameters plus removed ones
+ a0, a1, a2 = 1, True, 2
+ self.assertEqual(self.mods.argRemoval1(a0, a1), (a0, a1, Point(1, 2), Point(3, 4), 333))
+ self.assertEqual(self.mods.argRemoval1(a0, a1, a2), (a0, a1, Point(1, 2), Point(3, 4), a2))
+ # the other wasn't modified
+ # void argRemoval1(int, bool, int, bool)
+ self.assertEqual(self.mods.argRemoval1(0, False, 0, False), None)
+
+ def testArgRemoval2(self):
+ '''Tests argument removal modifications on Modifications.argRemoval2.'''
+ # void [-> PyObject*] argRemoval2(int, bool, Point = Point(1, 2)
+ # [removed], Point = Point(3, 4) [removed], int = 333)
+ # code-injection: returns tuple with received parameters plus removed ones
+ a0, a1, a2 = 1, True, 2
+ self.assertEqual(self.mods.argRemoval2(a0, a1), (a0, a1, Point(1, 2), Point(3, 4), 333))
+ self.assertEqual(self.mods.argRemoval2(a0, a1, a2), (a0, a1, Point(1, 2), Point(3, 4), a2))
+
+ def testArgRemoval3(self):
+ '''Tests argument removal modifications on Modifications.argRemoval3.'''
+ # void [-> PyObject*] argRemoval3(int, Point = Point(1, 2) [removed],
+ # bool = true, Point = Point(3, 4) [removed], int = 333)
+ # code-injection: returns tuple with received parameters plus removed ones
+ a0, a1, a2 = 1, True, 2
+ self.assertEqual(self.mods.argRemoval3(a0), (a0, Point(1, 2), True, Point(3, 4), 333))
+ self.assertEqual(self.mods.argRemoval3(a0, a1), (a0, Point(1, 2), a1, Point(3, 4), 333))
+ self.assertEqual(self.mods.argRemoval3(a0, a1, a2), (a0, Point(1, 2), a1, Point(3, 4), a2))
+
+ def testArgRemoval4(self):
+ '''Tests argument removal modifications on Modifications.argRemoval4.'''
+ # void [-> PyObject*] argRemoval4(int, Point [removed, new val = Point(6, 9)], bool,
+ # Point = Point(3, 4) [removed], int = 333)
+ # code-injection: returns tuple with received parameters plus removed ones
+ a0, a1, a2 = 1, True, 2
+ self.assertRaises(TypeError, self.mods.argRemoval4, a0)
+ self.assertEqual(self.mods.argRemoval4(a0, a1), (a0, Point(6, 9), a1, Point(3, 4), 333))
+ self.assertEqual(self.mods.argRemoval4(a0, a1, a2), (a0, Point(6, 9), a1, Point(3, 4), a2))
+
+ def testArgRemoval5(self):
+ '''Tests argument removal modifications on Modifications.argRemoval5.'''
+ # void [-> PyObject*] argRemoval5(int [removed, new val = 100], bool,
+ # Point = Point(1, 2) [removed],
+ # Point = Point(3, 4) [removed], int = 333)
+ # code-injection: returns tuple with received parameters plus removed ones
+ a0, a1, a2 = True, 2, True
+ self.assertEqual(self.mods.argRemoval5(a0), (100, a0, Point(1, 2), Point(3, 4), 333))
+ self.assertEqual(self.mods.argRemoval5(a0, a1), (100, a0, Point(1, 2), Point(3, 4), a1))
+ # void [-> PyObject*] argRemoval5(int [removed, new val = 200], bool, int, bool)
+ # code-injection: returns tuple with received parameters plus removed ones
+ self.assertEqual(self.mods.argRemoval5(a0, a1, a2), (200, a0, a1, a2))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/array_numpy_test.py b/sources/shiboken6/tests/samplebinding/array_numpy_test.py
new file mode 100644
index 000000000..0d73bca1c
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/array_numpy_test.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for NumPy Array types.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+import sample
+
+hasNumPy = False
+
+try:
+ import numpy
+ hasNumPy = True
+except ImportError:
+ pass
+
+
+class ArrayTester(unittest.TestCase):
+ '''Test case for NumPy arrays.'''
+
+ def testIntArray(self):
+ intList = numpy.array([1, 2, 3, 4], dtype='int32')
+ self.assertEqual(sample.sumIntArray(intList), 10)
+
+ def testDoubleArray(self):
+ doubleList = numpy.array([1, 2, 3, 4], dtype='double')
+ self.assertEqual(sample.sumDoubleArray(doubleList), 10)
+
+ def testIntMatrix(self):
+ intMatrix = numpy.array([[1, 2, 3], [4, 5, 6]], dtype='int32')
+ self.assertEqual(sample.sumIntMatrix(intMatrix), 21)
+
+ def testDoubleMatrix(self):
+ doubleMatrix = numpy.array([[1, 2, 3], [4, 5, 6]], dtype='double')
+ self.assertEqual(sample.sumDoubleMatrix(doubleMatrix), 21)
+
+
+if __name__ == '__main__' and hasNumPy:
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/array_sequence_test.py b/sources/shiboken6/tests/samplebinding/array_sequence_test.py
new file mode 100644
index 000000000..ad65d58db
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/array_sequence_test.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for Array types (PySequence).'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+import sample
+
+
+class ArrayTester(unittest.TestCase):
+ '''Test case for arrays.'''
+
+ def testIntArray(self):
+ intList = [1, 2, 3, 4]
+ self.assertEqual(sample.sumIntArray(intList), 10)
+
+ def testIntArrayModified(self):
+ intList = [1, 2, 3, 4]
+ tester = sample.ArrayModifyTest()
+ self.assertEqual(tester.sumIntArray(4, intList), 10)
+
+ def testDoubleArray(self):
+ doubleList = [1.2, 2.3, 3.4, 4.5]
+ self.assertEqual(sample.sumDoubleArray(doubleList), 11.4)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/bug_554_test.py b/sources/shiboken6/tests/samplebinding/bug_554_test.py
new file mode 100644
index 000000000..a7e7a7210
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/bug_554_test.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Unit test for bug#554'''
+
+import os
+import sys
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class Bug554:
+ def crash(self):
+ class Crasher(ObjectType):
+ pass
+
+
+if __name__ == '__main__':
+ bug = Bug554()
+ bug.crash()
diff --git a/sources/shiboken6/tests/samplebinding/bug_704_test.py b/sources/shiboken6/tests/samplebinding/bug_704_test.py
new file mode 100644
index 000000000..c470fe723
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/bug_704_test.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class NewStyle(object):
+ def name(self):
+ return "NewStyle"
+
+
+def defineNewStyle():
+ class MyObjectNew(ObjectType, NewStyle):
+ pass
+
+
+class ObjectTypeTest(unittest.TestCase):
+ '''Test cases to avoid declaring Shiboken classes with multiple inheritance
+ from old style classes.'''
+
+ def testObjectTypeNewStype(self):
+ defineNewStyle()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/bytearray_test.py b/sources/shiboken6/tests/samplebinding/bytearray_test.py
new file mode 100644
index 000000000..e51a899fa
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/bytearray_test.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import ByteArray
+
+
+class ByteArrayBufferProtocolTest(unittest.TestCase):
+ '''Tests ByteArray implementation of Python buffer protocol.'''
+
+ def testByteArrayBufferProtocol(self):
+ # Tests ByteArray implementation of Python buffer protocol using the Path().is_dir
+ # function with a unicode object or other object implementing the Python buffer protocol.
+ Path(str(ByteArray('/tmp'))).is_dir()
+
+
+class ByteArrayConcatenationOperatorTest(unittest.TestCase):
+ '''Test cases for ByteArray concatenation with '+' operator.'''
+
+ def testConcatByteArrayAndPythonString(self):
+ # Test concatenation of a ByteArray with a Python string, in this order.
+ ba = ByteArray('foo')
+ result = ba + '\x00bar'
+ self.assertEqual(type(result), ByteArray)
+ self.assertEqual(result, 'foo\x00bar')
+
+ def testConcatPythonStringAndByteArray(self):
+ # Test concatenation of a Python string with a ByteArray, in this order.
+ concat_python_string_add_qbytearray_worked = True # noqa: F841
+ ba = ByteArray('foo')
+ result = 'bar\x00' + ba
+ self.assertEqual(type(result), ByteArray)
+ self.assertEqual(result, 'bar\x00foo')
+
+
+class ByteArrayOperatorEqual(unittest.TestCase):
+ '''TestCase for operator ByteArray == ByteArray.'''
+
+ def testDefault(self):
+ # ByteArray() == ByteArray()
+ obj1 = ByteArray()
+ obj2 = ByteArray()
+ self.assertEqual(obj1, obj2)
+
+ def testSimple(self):
+ # ByteArray(some_string) == ByteArray(some_string)
+ string = 'egg snakes'
+ self.assertEqual(ByteArray(string), ByteArray(string))
+
+ def testPyString(self):
+ # ByteArray(string) == string
+ string = 'my test string'
+ self.assertEqual(ByteArray(string), string)
+
+ def testQString(self):
+ # ByteArray(string) == string
+ string = 'another test string'
+ self.assertEqual(ByteArray(string), string)
+
+
+class ByteArrayOperatorAt(unittest.TestCase):
+ '''TestCase for operator ByteArray[]'''
+
+ def testInRange(self):
+ # ByteArray[x] where x is a valid index.
+ string = 'abcdefgh'
+ obj = ByteArray(string)
+ for i in range(len(string)):
+ self.assertEqual(obj[i], bytes(string[i], "UTF8"))
+
+ def testInRangeReverse(self):
+ # ByteArray[x] where x is a valid index (reverse order).
+ string = 'abcdefgh'
+ obj = ByteArray(string)
+ for i in range(len(string) - 1, 0, -1):
+ self.assertEqual(obj[i], bytes(string[i], "UTF8"))
+
+ def testOutOfRange(self):
+ # ByteArray[x] where x is out of index.
+ string = '1234567'
+ obj = ByteArray(string)
+ self.assertRaises(IndexError, lambda: obj[len(string)])
+
+ def testNullStrings(self):
+ ba = ByteArray('\x00')
+ self.assertEqual(ba.at(0), '\x00')
+ self.assertEqual(ba[0], bytes('\x00', "UTF8"))
+
+
+class ByteArrayOperatorLen(unittest.TestCase):
+ '''Test case for __len__ operator of ByteArray'''
+
+ def testBasic(self):
+ '''ByteArray __len__'''
+ self.assertEqual(len(ByteArray()), 0)
+ self.assertEqual(len(ByteArray('')), 0)
+ self.assertEqual(len(ByteArray(' ')), 1)
+ self.assertEqual(len(ByteArray('yabadaba')), 8)
+
+
+class ByteArrayAndPythonStr(unittest.TestCase):
+ '''Test case for __str__ operator of ByteArray'''
+
+ def testStrOperator(self):
+ '''ByteArray __str__'''
+ self.assertEqual(ByteArray().__str__(), '')
+ self.assertEqual(ByteArray('').__str__(), '')
+ self.assertEqual(ByteArray('aaa').__str__(), 'aaa')
+
+ def testPythonStrAndNull(self):
+ s1 = bytes('123\000321', "UTF8")
+ ba = ByteArray(s1)
+ s2 = ba.data()
+ self.assertEqual(s1, s2)
+ self.assertEqual(type(s1), type(s2))
+ self.assertEqual(s1, ba)
+ self.assertNotEqual(type(s1), type(ba))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/child_return_test.py b/sources/shiboken6/tests/samplebinding/child_return_test.py
new file mode 100644
index 000000000..f0ac70626
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/child_return_test.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''The BlackBox class has cases of ownership transference between C++ and Python.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class ReturnOfChildTest(unittest.TestCase):
+ '''The BlackBox class has cases of ownership transference between C++ and Python.'''
+
+ def testKillParentKeepingChild(self):
+ '''Ownership transference from Python to C++ and back again.'''
+ o1 = ObjectType.createWithChild()
+ child = o1.children()[0]
+ del o1
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertRaises(RuntimeError, child.objectName)
+
+ def testKillParentKeepingChild2(self):
+ '''Ownership transference from Python to C++ and back again.'''
+ o1 = ObjectType.createWithChild()
+ child = o1.findChild("child")
+ del o1
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertRaises(RuntimeError, child.objectName)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/class_fields_test.py b/sources/shiboken6/tests/samplebinding/class_fields_test.py
new file mode 100644
index 000000000..1eeb3d446
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/class_fields_test.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Simple test case for accessing the exposed C++ class fields.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Derived, Point, ObjectType
+
+
+class TestAccessingCppFields(unittest.TestCase):
+ '''Simple test case for accessing the exposed C++ class fields.'''
+
+ def testAccessingPrimitiveTypeField(self):
+ '''Reads and writes a primitive type (in this case an 'int') field.'''
+ d = Derived()
+ self.assertEqual(type(d.primitiveField), int)
+
+ # attribution
+ old_value = d.primitiveField
+ new_value = 2255
+ d.primitiveField = new_value
+ self.assertEqual(d.primitiveField, new_value)
+ self.assertNotEqual(d.primitiveField, old_value)
+
+ # attribution with a convertible type
+ value = 1.2
+ d.primitiveField = value
+ self.assertEqual(d.primitiveField, int(value))
+
+ # attribution with invalid type
+ self.assertRaises(TypeError, lambda: setattr(d, 'primitiveField', None))
+
+ def testAccessingRenamedFields(self):
+ '''Reads and writes a renamed field.'''
+ d = Derived()
+ self.assertEqual(type(d.renamedField), int)
+ old_value = d.renamedField
+ new_value = 2255
+ d.renamedField = new_value
+ self.assertEqual(d.renamedField, new_value)
+ self.assertNotEqual(d.renamedField, old_value)
+
+ def testAccessingReadOnlyFields(self):
+ '''Tests a read-only field.'''
+ d = Derived()
+ self.assertEqual(type(d.readOnlyField), int)
+ old_value = d.readOnlyField
+ try:
+ d.readOnlyField = 25555
+ except AttributeError:
+ pass
+ self.assertEqual(d.readOnlyField, old_value)
+
+ def testAccessingUsersPrimitiveTypeField(self):
+ '''Reads and writes an user's primitive type (in this case an 'Complex') field.'''
+ d = Derived()
+ self.assertEqual(type(d.userPrimitiveField), complex)
+
+ # attribution
+ old_value = d.userPrimitiveField
+ new_value = complex(1.1, 2.2)
+ d.userPrimitiveField = new_value
+ self.assertEqual(d.userPrimitiveField, new_value)
+ self.assertNotEqual(d.userPrimitiveField, old_value)
+
+ # attribution with invalid type
+ self.assertRaises(TypeError, lambda: setattr(d, 'userPrimitiveField', None))
+
+ def testAccessingValueTypeField(self):
+ '''Reads and writes a value type (in this case a 'Point') field.'''
+ d = Derived()
+ self.assertEqual(type(d.valueTypeField), Point)
+
+ # attribution
+ old_value = d.valueTypeField # noqa: F841
+ new_value = Point(-10, 537)
+ d.valueTypeField = new_value
+ self.assertEqual(d.valueTypeField, new_value)
+
+ #object modify
+ d.valueTypeField.setX(10)
+ d.valueTypeField.setY(20)
+ self.assertEqual(d.valueTypeField.x(), 10)
+ self.assertEqual(d.valueTypeField.y(), 20)
+
+ # attribution with invalid type
+ self.assertRaises(TypeError, lambda: setattr(d, 'valueTypeField', 123))
+
+ def testAccessingObjectTypeField(self):
+ '''Reads and writes a object type (in this case an 'ObjectType') field.'''
+ d = Derived()
+
+ # attribution
+ old_value = d.objectTypeField
+ new_value = ObjectType()
+ d.objectTypeField = new_value
+ self.assertEqual(d.objectTypeField, new_value)
+ self.assertNotEqual(d.objectTypeField, old_value)
+
+ # attribution with a convertible type
+ value = None
+ d.objectTypeField = value
+ self.assertEqual(d.objectTypeField, value)
+
+ # attribution with invalid type
+ self.assertRaises(TypeError, lambda: setattr(d, 'objectTypeField', 123))
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testRefCountingAccessingObjectTypeField(self):
+ '''Accessing a object type field should respect the reference counting rules.'''
+ d = Derived()
+
+ # attributing object to instance's field should increase its reference count
+ o1 = ObjectType()
+ refcount1 = sys.getrefcount(o1)
+ d.objectTypeField = o1
+ self.assertEqual(d.objectTypeField, o1)
+ self.assertEqual(sys.getrefcount(d.objectTypeField), refcount1 + 1)
+
+ # attributing a new object to instance's field should decrease the previous
+ # object's reference count
+ o2 = ObjectType()
+ refcount2 = sys.getrefcount(o2)
+ d.objectTypeField = o2
+ self.assertEqual(d.objectTypeField, o2)
+ self.assertEqual(sys.getrefcount(o1), refcount1)
+ self.assertEqual(sys.getrefcount(d.objectTypeField), refcount2 + 1)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testRefCountingOfReferredObjectAfterDeletingReferrer(self):
+ '''Deleting the object referring to other object should decrease the
+ reference count of the referee.'''
+ d = Derived()
+ o = ObjectType()
+ refcount = sys.getrefcount(o)
+ d.objectTypeField = o
+ self.assertEqual(sys.getrefcount(o), refcount + 1)
+ del d
+ self.assertEqual(sys.getrefcount(o), refcount)
+
+ def testStaticField(self):
+ self.assertEqual(Derived.staticPrimitiveField, 0)
+
+ def testAccessingUnsignedIntBitField(self):
+ d = Derived()
+
+ # attribution
+ old_value = d.bitField
+ new_value = 1
+ d.bitField = new_value
+ self.assertEqual(d.bitField, new_value)
+ self.assertNotEqual(d.bitField, old_value)
+
+ # attribution with a convertible type
+ value = 1.2
+ d.bitField = value
+ self.assertEqual(d.bitField, int(value))
+
+ # attribution with invalid type
+ self.assertRaises(TypeError, lambda: setattr(d, 'bitField', None))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/collector_test.py b/sources/shiboken6/tests/samplebinding/collector_test.py
new file mode 100644
index 000000000..4caebc62a
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/collector_test.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for Collector class' shift operators.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Collector, IntWrapper, ObjectType
+
+
+class CollectorTest(unittest.TestCase):
+ '''Test cases for Collector class' shift operators.'''
+
+ def testLShiftOperatorSingleUse(self):
+ '''Test case for using the Collector.__lshift__ operator just one time.'''
+ collector = Collector()
+ collector << 13
+ self.assertEqual(collector.size(), 1)
+ self.assertEqual(collector.items(), [13])
+
+ def testLShiftOperatorMultipleUses(self):
+ '''Test case for using the Collector.__lshift__ operator many times in the same line.'''
+ collector = Collector()
+ collector << 2 << 3 << 5 << 7 << 11
+ self.assertEqual(collector.size(), 5)
+ self.assertEqual(collector.items(), [2, 3, 5, 7, 11])
+
+
+class CollectorExternalOperator(unittest.TestCase):
+ '''Test cases for external operators of Collector'''
+
+ def testLShiftExternal(self):
+ '''Collector external operator'''
+ collector = Collector()
+ collector << IntWrapper(5)
+ self.assertEqual(collector.size(), 1)
+ self.assertEqual(collector.items(), [5])
+
+
+class CollectorObjectType(unittest.TestCase):
+ '''Test cases for Collector ObjectType'''
+
+ def testBasic(self):
+ '''Collector << ObjectType # greedy collector'''
+ collector = Collector()
+ obj = ObjectType()
+ collector << obj
+ self.assertEqual(collector.items()[0], obj.identifier())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/complex_test.py b/sources/shiboken6/tests/samplebinding/complex_test.py
new file mode 100644
index 000000000..454aff100
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/complex_test.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for Complex class'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+import sample
+from sample import Point
+
+
+class ComplexTest(unittest.TestCase):
+ '''Test case for conversions between C++ Complex class to Python complex class'''
+
+ def testFunctionReturningComplexObject(self):
+ '''Test function returning a C++ Complex object.'''
+ cpx = sample.transmutePointIntoComplex(Point(5.0, 2.3))
+ self.assertEqual(cpx, complex(5.0, 2.3))
+
+ def testFunctionReceivingComplexObjectAsArgument(self):
+ '''Test function returning a C++ Complex object.'''
+ pt = sample.transmuteComplexIntoPoint(complex(1.2, 3.4))
+ # these assertions intentionally avoids to test the == operator,
+ # it should have its own test cases.
+ self.assertEqual(pt.x(), 1.2)
+ self.assertEqual(pt.y(), 3.4)
+
+ def testComplexList(self):
+ '''Test list of C++ Complex objects conversion to a list of Python complex objects.'''
+ # the global function gimmeComplexList() is expected to return a list
+ # containing the following Complex values: [0j, 1.1+2.2j, 1.3+2.4j]
+ cpxlist = sample.gimmeComplexList()
+ self.assertEqual(cpxlist, [complex(), complex(1.1, 2.2), complex(1.3, 2.4)])
+
+ def testSumComplexPair(self):
+ '''Test sum of a tuple containing two complex objects.'''
+ cpx1 = complex(1.2, 3.4)
+ cpx2 = complex(5.6, 7.8)
+ self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), cpx1 + cpx2)
+
+ def testUsingTuples(self):
+ cpx1, cpx2 = (1.2, 3.4), (5.6, 7.8)
+ self.assertEqual(sample.sumComplexPair((cpx1, cpx2)),
+ sample.sumComplexPair((complex(*cpx1), complex(*cpx2))))
+ cpx1, cpx2 = (1, 3), (5, 7)
+ self.assertEqual(sample.sumComplexPair((cpx1, cpx2)),
+ sample.sumComplexPair((complex(*cpx1), complex(*cpx2))))
+ cpx1, cpx2 = (1.2, 3), (5.6, 7)
+ self.assertEqual(sample.sumComplexPair((cpx1, cpx2)),
+ sample.sumComplexPair((complex(*cpx1), complex(*cpx2))))
+ cpx1, cpx2 = (1, 2, 3), (4, 5, 7)
+ self.assertRaises(TypeError, sample.sumComplexPair, (cpx1, cpx2))
+ cpx1, cpx2 = ('1', '2'), ('4', '5')
+ self.assertRaises(TypeError, sample.sumComplexPair, (cpx1, cpx2))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/conversion_operator_test.py b/sources/shiboken6/tests/samplebinding/conversion_operator_test.py
new file mode 100644
index 000000000..7e76245b1
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/conversion_operator_test.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for implicit conversion generated by conversion operator.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Time, StrList
+
+
+class ConversionOperatorTest(unittest.TestCase):
+ '''Test cases for implicit conversion generated by conversion operator.'''
+
+ def testConversionOperator(self):
+ '''Time defined an conversion operator for Str, so passing a Time object
+ to a method expecting a Str should work.'''
+ t = Time(1, 2, 3)
+ t_str = t.toString()
+ sl = StrList()
+
+ # StrList.append expects a Str object.
+ sl.append(t)
+
+ self.assertEqual(len(sl), 1)
+ self.assertEqual(sl[0], t_str)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/copy_test.py b/sources/shiboken6/tests/samplebinding/copy_test.py
new file mode 100644
index 000000000..db539d1b9
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/copy_test.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for deep copy of objects'''
+
+import copy
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+
+from sample import Point
+
+
+class SimpleCopy(unittest.TestCase):
+ '''Simple copy of objects'''
+
+ def testCopy(self):
+ point = Point(0.1, 2.4)
+ new_point = copy.copy(point)
+
+ self.assertTrue(point is not new_point)
+ self.assertEqual(point, new_point)
+
+
+class DeepCopy(unittest.TestCase):
+ '''Deep copy with shiboken objects'''
+
+ def testDeepCopy(self):
+ '''Deep copy of value types'''
+ point = Point(3.1, 4.2)
+ new_point = copy.deepcopy([point])[0]
+
+ self.assertTrue(point is not new_point)
+ self.assertEqual(point, new_point)
+
+
+class PicklingTest(unittest.TestCase):
+ '''Support pickling'''
+
+ def testSimple(self):
+ '''Simple pickling and unpickling'''
+
+ point = Point(10.2, 43.5)
+
+ data = pickle.dumps(point)
+ new_point = pickle.loads(data)
+
+ self.assertEqual(point, new_point)
+ self.assertTrue(point is not new_point)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ctorconvrule_test.py b/sources/shiboken6/tests/samplebinding/ctorconvrule_test.py
new file mode 100644
index 000000000..5e2695d72
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ctorconvrule_test.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for proper generation of constructor altered by conversion-rule tag.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import CtorConvRule
+
+
+class TestCtorConvRule(unittest.TestCase):
+ '''Simple test case for CtorConvRule'''
+
+ def testCtorConvRule(self):
+ '''Test CtorConvRule argument modification through conversion-rule tag.'''
+ value = 123
+ obj = CtorConvRule(value)
+ self.assertEqual(obj.value(), value + 1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/cyclic_test.py b/sources/shiboken6/tests/samplebinding/cyclic_test.py
new file mode 100644
index 000000000..4e4ae2603
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/cyclic_test.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import ObjectType
+from sample import ObjectView
+from sample import ObjectModel
+
+
+class ObjTest(unittest.TestCase):
+
+ def test_cyclic_dependency_withParent(self):
+ """Create 2 objects with a cyclic dependency, so that they can
+ only be removed by the garbage collector, and then invoke the
+ garbage collector in a different thread.
+ """
+ class CyclicChildObject(ObjectType):
+ def __init__(self, parent):
+ super(CyclicChildObject, self).__init__(parent)
+ self._parent = parent
+
+ class CyclicObject(ObjectType):
+ def __init__(self):
+ super(CyclicObject, self).__init__()
+ CyclicChildObject(self)
+
+ # turn off automatic garbage collection, to be able to trigger it
+ # at the 'right' time
+ gc.disable()
+ alive = lambda: sum(isinstance(o, CyclicObject) for o in gc.get_objects()) # noqa: E731
+
+ #
+ # first proof that the wizard is only destructed by the garbage
+ # collector
+ #
+ cycle = CyclicObject()
+ self.assertTrue(alive())
+ del cycle
+ if not hasattr(sys, "pypy_version_info"):
+ # PYSIDE-535: the semantics of gc.enable/gc.disable is different for PyPy
+ self.assertTrue(alive())
+ gc.collect()
+ self.assertFalse(alive())
+
+ def test_cyclic_dependency_withKeepRef(self):
+ """Create 2 objects with a cyclic dependency, so that they can
+ only be removed by the garbage collector, and then invoke the
+ garbage collector in a different thread.
+ """
+ class CyclicChildObject(ObjectView):
+ def __init__(self, model):
+ super(CyclicChildObject, self).__init__(None)
+ self.setModel(model)
+
+ class CyclicObject(ObjectModel):
+ def __init__(self):
+ super(CyclicObject, self).__init__()
+ self._view = CyclicChildObject(self)
+
+ # turn off automatic garbage collection, to be able to trigger it
+ # at the 'right' time
+ gc.disable()
+ alive = lambda: sum(isinstance(o, CyclicObject) for o in gc.get_objects()) # noqa: E731
+
+ #
+ # first proof that the wizard is only destructed by the garbage
+ # collector
+ #
+ cycle = CyclicObject()
+ self.assertTrue(alive())
+ del cycle
+ if not hasattr(sys, "pypy_version_info"):
+ # PYSIDE-535: the semantics of gc.enable/gc.disable is different for PyPy
+ self.assertTrue(alive())
+ gc.collect()
+ self.assertFalse(alive())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/date_test.py b/sources/shiboken6/tests/samplebinding/date_test.py
new file mode 100644
index 000000000..2b6efcf18
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/date_test.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for python conversions types '''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from datetime import date
+
+from sample import SbkDate
+
+
+class DateConversionTest(unittest.TestCase):
+
+ def testConstructorWithDateObject(self):
+ pyDate = date(2010, 12, 12)
+ cDate = SbkDate(pyDate)
+ self.assertTrue(cDate.day(), pyDate.day)
+ self.assertTrue(cDate.month(), pyDate.month)
+ self.assertTrue(cDate.year(), pyDate.year)
+
+ def testToPythonFunction(self):
+ cDate = SbkDate(2010, 12, 12)
+ pyDate = cDate.toPython()
+ self.assertTrue(cDate.day(), pyDate.day)
+ self.assertTrue(cDate.month(), pyDate.month)
+ self.assertTrue(cDate.year(), pyDate.year)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/decisor_test.py b/sources/shiboken6/tests/samplebinding/decisor_test.py
new file mode 100644
index 000000000..0d39c5f96
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/decisor_test.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for the method overload decisor.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import SampleNamespace, Point, ObjectType, ObjectModel
+
+
+class DecisorTest(unittest.TestCase):
+ '''Test cases for the method overload decisor.'''
+
+ def testCallWithInvalidParametersSideA(self):
+ '''Call a method missing with the last argument missing.
+ This can trigger the bug #262, which means using an argument
+ not provided by the user.'''
+ pt = Point()
+ # This exception may move from a TypeError to a ValueError.
+ self.assertRaises((TypeError, ValueError), SampleNamespace.forceDecisorSideA, pt)
+
+ def testCallWithInvalidParametersSideB(self):
+ '''Same as the previous test, but with an integer as first argument,
+ just to complicate things for the overload method decisor.'''
+ pt = Point()
+ # This exception may move from a TypeError to a ValueError.
+ self.assertRaises((TypeError, ValueError), SampleNamespace.forceDecisorSideB, 1, pt)
+
+ def testDecideCallWithInheritance(self):
+ '''Call methods overloads that receive parent and inheritor classes' instances.'''
+ objecttype = ObjectType()
+ objectmodel = ObjectModel()
+ self.assertEqual(ObjectModel.receivesObjectTypeFamily(objecttype),
+ ObjectModel.ObjectTypeCalled)
+ self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objecttype),
+ ObjectModel.ObjectModelCalled)
+ self.assertEqual(ObjectModel.receivesObjectTypeFamily(objectmodel),
+ ObjectModel.ObjectModelCalled)
+ self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objectmodel),
+ ObjectModel.ObjectTypeCalled)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/delete_test.py b/sources/shiboken6/tests/samplebinding/delete_test.py
new file mode 100644
index 000000000..57a792ae2
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/delete_test.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+import sample
+from shiboken6 import Shiboken
+
+
+class DeleteTest(unittest.TestCase):
+ def testNonCppWrapperClassDelete(self):
+ """Would segfault when shiboken.delete called on obj not created from Python."""
+ obj = sample.ObjectType()
+ child = obj.createChild(None)
+ Shiboken.delete(child)
+ assert not Shiboken.isValid(child)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/deprecated_test.py b/sources/shiboken6/tests/samplebinding/deprecated_test.py
new file mode 100644
index 000000000..c371df94f
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/deprecated_test.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+import warnings
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class TestDeprecatedCall(unittest.TestCase):
+ def testCallWithError(self):
+ o = ObjectType()
+ warnings.simplefilter('error')
+ self.assertRaises(DeprecationWarning, o.deprecatedFunction)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/derived_test.py b/sources/shiboken6/tests/samplebinding/derived_test.py
new file mode 100644
index 000000000..346f29136
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/derived_test.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for Derived class'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+import sample
+from sample import Abstract, Derived, DerivedUsingCt, OverloadedFuncEnum
+
+
+class Deviant(Derived):
+ def __init__(self):
+ Derived.__init__(self)
+ self.pure_virtual_called = False
+ self.unpure_virtual_called = False
+
+ def pureVirtual(self):
+ self.pure_virtual_called = True
+
+ def unpureVirtual(self):
+ self.unpure_virtual_called = True
+
+ def className(self):
+ return 'Deviant'
+
+
+class ImplementVirtualWithOutParameter(Derived):
+ def __init__(self, value):
+ super().__init__()
+ self._value = value
+
+ def virtualWithOutParameter(self):
+ return self._value
+
+
+class DerivedTest(unittest.TestCase):
+ '''Test case for Derived class'''
+
+ def testParentClassMethodsAvailability(self):
+ '''Test if Derived class really inherits its methods from parent.'''
+ inherited_methods = set(['callPureVirtual', 'callUnpureVirtual',
+ 'id_', 'pureVirtual', 'unpureVirtual'])
+ self.assertTrue(inherited_methods.issubset(dir(Derived)))
+
+ def testOtherOverloadedMethodCall(self):
+ '''Another test to check overloaded method calling, just to double check.'''
+ derived = Derived()
+
+ result = derived.otherOverloaded(1, 2, True, 3.3)
+ self.assertEqual(type(result), Derived.OtherOverloadedFuncEnum)
+ self.assertEqual(result, sample.Derived.OtherOverloadedFunc_iibd)
+
+ result = derived.otherOverloaded(1, 2.2)
+ self.assertEqual(type(result), Derived.OtherOverloadedFuncEnum)
+ self.assertEqual(result, Derived.OtherOverloadedFunc_id)
+
+ def testOverloadedMethodCallWithDifferentNumericTypes(self):
+ '''Test if the correct overloaded method accepts a different numeric type as argument.'''
+ derived = Derived()
+ result = derived.overloaded(1.1, 2.2)
+ self.assertEqual(type(result), OverloadedFuncEnum)
+
+ def testOverloadedMethodCallWithWrongNumberOfArguments(self):
+ '''Test if a call to an overloaded method with the wrong number of arguments
+ raises an exception.'''
+ derived = Derived()
+ self.assertRaises(TypeError, derived.otherOverloaded, 1, 2, True)
+
+ def testReimplementedPureVirtualMethodCall(self):
+ '''Test if a Python override of a implemented pure virtual method is
+ correctly called from C++.'''
+ d = Deviant()
+ d.callPureVirtual()
+ self.assertTrue(d.pure_virtual_called)
+
+ def testReimplementedVirtualMethodCall(self):
+ '''Test if a Python override of a reimplemented virtual method is
+ correctly called from C++.'''
+ d = Deviant()
+ d.callUnpureVirtual()
+ self.assertTrue(d.unpure_virtual_called)
+
+ def testVirtualMethodCallString(self):
+ '''Test virtual method call returning string.'''
+ d = Derived()
+ self.assertEqual(d.className(), 'Derived')
+ self.assertEqual(d.getClassName(), 'Derived')
+
+ def testReimplementedVirtualMethodCallReturningString(self):
+ '''Test if a Python override of a reimplemented virtual method is
+ correctly called from C++.'''
+ d = Deviant()
+ self.assertEqual(d.className(), 'Deviant')
+ self.assertEqual(d.getClassName(), 'Deviant')
+
+ def testSingleArgument(self):
+ '''Test singleArgument call.'''
+ d = Derived()
+ self.assertTrue(d.singleArgument(False))
+ self.assertTrue(not d.singleArgument(True))
+
+ def testMethodCallWithDefaultValue(self):
+ '''Test method call with default value.'''
+ d = Derived()
+ self.assertEqual(d.defaultValue(3), 3.1)
+ self.assertEqual(d.defaultValue(), 0.1)
+
+ def testCallToMethodWithAbstractArgument(self):
+ '''Call to method that expects an Abstract argument.'''
+ objId = 123
+ d = Derived(objId)
+ self.assertEqual(Abstract.getObjectId(d), objId)
+
+ def testObjectCreationWithParentType(self):
+ '''Derived class creates an instance of itself in C++ and returns it as
+ a pointer to its ancestor Abstract.'''
+ obj = Derived.createObject()
+ self.assertEqual(type(obj), Derived)
+
+ def testDerivedUsingCt(self):
+ '''Test whether a constructor of the base class declared by using works'''
+ obj = DerivedUsingCt(42)
+ self.assertEqual(obj.value(), 42)
+
+ def testVirtualWithOutParameter(self):
+ d = Derived()
+ self.assertEqual(d.callVirtualWithOutParameter(), 42)
+
+ d = ImplementVirtualWithOutParameter(1)
+ self.assertEqual(d.callVirtualWithOutParameter(), 1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/duck_punching_test.py b/sources/shiboken6/tests/samplebinding/duck_punching_test.py
new file mode 100644
index 000000000..aa21a0f7e
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/duck_punching_test.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for virtual methods.'''
+
+import os
+import sys
+import types
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import VirtualMethods, SimpleFile, Point
+
+
+def MethodTypeCompat(func, instance):
+ return types.MethodType(func, instance)
+
+
+class Duck(VirtualMethods):
+ def __init__(self):
+ VirtualMethods.__init__(self)
+
+
+class Monkey(SimpleFile):
+ def __init__(self, filename):
+ SimpleFile.__init__(self, filename)
+
+
+class DuckPunchingTest(unittest.TestCase):
+ '''Test case for duck punching (aka "monkey patching").'''
+
+ def setUp(self):
+ self.multiplier = 2.0
+ self.duck_method_called = False
+ self.call_counter = 0
+
+ def testMonkeyPatchOnVirtualMethod(self):
+ '''Injects new 'virtualMethod0' on a VirtualMethods instance and makes C++ call it.'''
+ vm = VirtualMethods()
+ pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True
+
+ result1 = vm.virtualMethod0(pt, val, cpx, b)
+ result2 = vm.callVirtualMethod0(pt, val, cpx, b)
+ self.assertEqual(result1, result2)
+ self.assertEqual(result1, VirtualMethods.virtualMethod0(vm, pt, val, cpx, b))
+
+ def myVirtualMethod0(obj, pt, val, cpx, b):
+ self.duck_method_called = True
+ return VirtualMethods.virtualMethod0(obj, pt, val, cpx, b) * self.multiplier
+ vm.virtualMethod0 = MethodTypeCompat(myVirtualMethod0, vm)
+
+ result1 = vm.callVirtualMethod0(pt, val, cpx, b)
+ self.assertTrue(self.duck_method_called)
+
+ result2 = vm.virtualMethod0(pt, val, cpx, b)
+ self.assertEqual(result1, result2)
+ self.assertEqual(result1,
+ VirtualMethods.virtualMethod0(vm, pt, val, cpx, b) * self.multiplier)
+
+ # This is done to decrease the refcount of the vm object
+ # allowing the object wrapper to be deleted before the
+ # BindingManager. This is useful when compiling Shiboken
+ # for debug, since the BindingManager destructor has an
+ # assert that checks if the wrapper mapper is empty.
+ vm.virtualMethod0 = None
+
+ def testMonkeyPatchOnVirtualMethodWithInheritance(self):
+ '''Injects new 'virtualMethod0' on an object that inherits from
+ VirtualMethods and makes C++ call it.'''
+ duck = Duck()
+ pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True
+
+ result1 = duck.virtualMethod0(pt, val, cpx, b)
+ result2 = duck.callVirtualMethod0(pt, val, cpx, b)
+ self.assertEqual(result1, result2)
+ self.assertEqual(result1, VirtualMethods.virtualMethod0(duck, pt, val, cpx, b))
+
+ def myVirtualMethod0(obj, pt, val, cpx, b):
+ self.duck_method_called = True
+ return VirtualMethods.virtualMethod0(obj, pt, val, cpx, b) * self.multiplier
+ duck.virtualMethod0 = MethodTypeCompat(myVirtualMethod0, duck)
+
+ result1 = duck.callVirtualMethod0(pt, val, cpx, b)
+ self.assertTrue(self.duck_method_called)
+
+ result2 = duck.virtualMethod0(pt, val, cpx, b)
+ self.assertEqual(result1, result2)
+ self.assertEqual(result1,
+ VirtualMethods.virtualMethod0(duck, pt, val, cpx, b) * self.multiplier)
+
+ duck.virtualMethod0 = None
+
+ def testMonkeyPatchOnMethodWithStaticAndNonStaticOverloads(self):
+ '''Injects new 'exists' on a SimpleFile instance and makes C++ call it.'''
+ simplefile = SimpleFile('foobar')
+
+ # Static 'exists'
+ simplefile.exists('sbrubbles')
+ self.assertFalse(self.duck_method_called)
+ # Non-static 'exists'
+ simplefile.exists()
+ self.assertFalse(self.duck_method_called)
+
+ def myExists(obj):
+ self.duck_method_called = True
+ return False
+ simplefile.exists = MethodTypeCompat(myExists, simplefile)
+
+ # Static 'exists' was overridden by the monkey patch, which accepts 0 arguments
+ self.assertRaises(TypeError, simplefile.exists, 'sbrubbles')
+ # Monkey patched exists
+ simplefile.exists()
+ self.assertTrue(self.duck_method_called)
+
+ simplefile.exists = None
+
+ def testMonkeyPatchOnMethodWithStaticAndNonStaticOverloadsWithInheritance(self):
+ '''Injects new 'exists' on an object that inherits from SimpleFile and makes C++ call it.'''
+ monkey = Monkey('foobar')
+
+ # Static 'exists'
+ monkey.exists('sbrubbles')
+ self.assertFalse(self.duck_method_called)
+ # Non-static 'exists'
+ monkey.exists()
+ self.assertFalse(self.duck_method_called)
+
+ def myExists(obj):
+ self.duck_method_called = True
+ return False
+ monkey.exists = MethodTypeCompat(myExists, monkey)
+
+ # Static 'exists' was overridden by the monkey patch, which accepts 0 arguments
+ self.assertRaises(TypeError, monkey.exists, 'sbrubbles')
+ # Monkey patched exists
+ monkey.exists()
+ self.assertTrue(self.duck_method_called)
+
+ monkey.exists = None
+
+ def testForInfiniteRecursion(self):
+ def myVirtualMethod0(obj, pt, val, cpx, b):
+ self.call_counter += 1
+ return VirtualMethods.virtualMethod0(obj, pt, val, cpx, b)
+ vm = VirtualMethods()
+ vm.virtualMethod0 = MethodTypeCompat(myVirtualMethod0, vm)
+ pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True
+ vm.virtualMethod0(pt, val, cpx, b)
+ self.assertEqual(self.call_counter, 1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/echo_test.py b/sources/shiboken6/tests/samplebinding/echo_test.py
new file mode 100644
index 000000000..f1859260e
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/echo_test.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for <add-function> with const char* as argument'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Echo
+
+
+class TestEcho(unittest.TestCase):
+ '''Simple test case for Echo.echo'''
+
+ def testEcho(self):
+ '''Test function added with const char * as arg'''
+ x = 'Foobar'
+ y = Echo().echo(x)
+ self.assertEqual(x, y)
+
+ def testCallOperator(self):
+ e = Echo()
+ self.assertEqual(e("Hello", 3), "Hello3")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/enum_test.py b/sources/shiboken6/tests/samplebinding/enum_test.py
new file mode 100644
index 000000000..276b8d894
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/enum_test.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for Python representation of C++ enums.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+# This is needed after the introduction of BUILD_DIR.
+
+import sample
+from sample import SampleNamespace, ObjectType, Event
+
+
+def createTempFile():
+ import tempfile
+ return tempfile.SpooledTemporaryFile(mode='rw')
+
+
+class EnumTest(unittest.TestCase):
+ '''Test case for Python representation of C++ enums.'''
+
+ def testHashability(self):
+ self.assertEqual(hash(SampleNamespace.TwoIn), hash(SampleNamespace.TwoOut))
+ self.assertNotEqual(hash(SampleNamespace.TwoIn), hash(SampleNamespace.OneIn))
+
+ def testEnumValuesInsideEnum(self):
+ '''Enum values should be accessible inside the enum as well as outside.'''
+ for value_name in SampleNamespace.Option.__members__:
+ enum_item1 = getattr(SampleNamespace.Option, value_name)
+ enum_item2 = getattr(SampleNamespace, value_name)
+ self.assertEqual(enum_item1, enum_item2)
+
+ def testPassingIntegerOnEnumArgument(self):
+ '''Tries to use an integer in place of an enum argument.'''
+ self.assertRaises(TypeError, SampleNamespace.getNumber, 1)
+
+ def testBuildingEnumFromIntegerValue(self):
+ '''Tries to build the proper enum using an integer.'''
+ SampleNamespace.getNumber(SampleNamespace.Option(1))
+
+ def testBuildingEnumWithDefaultValue(self):
+ '''Enum constructor with default value'''
+ enum = SampleNamespace.Option()
+ self.assertEqual(enum, SampleNamespace.None_)
+
+ def testEnumConversionToAndFromPython(self):
+ '''Conversion of enum objects from Python to C++ back again.'''
+ enumout = SampleNamespace.enumInEnumOut(SampleNamespace.TwoIn)
+ self.assertTrue(enumout, SampleNamespace.TwoOut)
+ self.assertEqual(repr(enumout), repr(SampleNamespace.TwoOut))
+
+ def testEnumConstructorWithTooManyParameters(self):
+ '''Calling the constructor of non-extensible enum with the wrong number of parameters.'''
+ self.assertRaises((TypeError, ValueError), SampleNamespace.InValue, 13, 14)
+
+ def testEnumConstructorWithNonNumberParameter(self):
+ '''Calling the constructor of non-extensible enum with a string.'''
+ self.assertRaises((TypeError, ValueError), SampleNamespace.InValue, '1')
+
+ def testEnumItemAsDefaultValueToIntArgument(self):
+ '''Calls function with an enum item as default value to an int argument.'''
+ self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(),
+ SampleNamespace.ZeroIn)
+ self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(SampleNamespace.ZeroOut), # noqa E:501
+ SampleNamespace.ZeroOut)
+ self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(123), 123)
+
+ def testAnonymousGlobalEnums(self):
+ '''Checks availability of anonymous global enum items.'''
+ self.assertEqual(sample.AnonymousGlobalEnum_Value0, 0)
+ self.assertEqual(sample.AnonymousGlobalEnum_Value1, 1)
+
+ def testAnonymousClassEnums(self):
+ '''Checks availability of anonymous class enum items.'''
+ self.assertEqual(SampleNamespace.AnonymousClassEnum_Value0, 0)
+ self.assertEqual(SampleNamespace.AnonymousClassEnum_Value1, 1)
+
+ def testEnumClasses(self):
+ # C++ 11: values of enum classes need to be fully qualified to match C++
+ sum = Event.EventTypeClass.Value1 + Event.EventTypeClass.Value2
+ self.assertEqual(sum, 1)
+
+ def testSetEnum(self):
+ event = Event(Event.ANY_EVENT)
+ self.assertEqual(event.eventType(), Event.ANY_EVENT)
+ event.setEventType(Event.BASIC_EVENT)
+ self.assertEqual(event.eventType(), Event.BASIC_EVENT)
+ event.setEventTypeByConstRef(Event.SOME_EVENT)
+ self.assertEqual(event.eventType(), Event.SOME_EVENT)
+ event.setEventTypeByConstPtr(Event.BASIC_EVENT)
+ self.assertEqual(event.eventType(), Event.BASIC_EVENT)
+
+ def testEnumArgumentWithDefaultValue(self):
+ '''Option enumArgumentWithDefaultValue(Option opt = UnixTime);'''
+ self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(), SampleNamespace.UnixTime)
+ self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(SampleNamespace.RandomNumber), # noqa E:501
+ SampleNamespace.RandomNumber)
+
+
+class MyEvent(Event):
+ def __init__(self):
+ Event.__init__(self, Event.EventType(3))
+
+
+class OutOfBoundsTest(unittest.TestCase):
+ def testValue(self):
+ e = MyEvent()
+ self.assertEqual(repr(e.eventType()), "<EventType.ANY_EVENT: 3>")
+
+
+class EnumOverloadTest(unittest.TestCase):
+ '''Test case for overloads involving enums'''
+
+ def testWithInt(self):
+ '''Overload with Enums and ints with default value'''
+ o = ObjectType()
+
+ self.assertEqual(o.callWithEnum('', Event.ANY_EVENT, 9), 81)
+ self.assertEqual(o.callWithEnum('', 9), 9)
+
+
+class EnumOperators(unittest.TestCase):
+ '''Test case for operations on enums'''
+
+ def testInequalitySameObject(self):
+ self.assertFalse(Event.ANY_EVENT != Event.ANY_EVENT)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py b/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py
new file mode 100644
index 000000000..42ae23961
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+import sample
+from shiboken_test_helper import objectFullname
+
+from shibokensupport.signature import get_signature
+
+
+class TestEnumFromRemovedNamespace(unittest.TestCase):
+
+ def testNames(self):
+ # Test if invisible namespace does not appear on type name
+ self.assertEqual(objectFullname(sample.RemovedNamespace1_Enum),
+ "sample.RemovedNamespace1_Enum")
+ self.assertEqual(objectFullname(sample.ObjectOnInvisibleNamespace),
+ "sample.ObjectOnInvisibleNamespace")
+
+ # Function arguments
+ signature = get_signature(sample.ObjectOnInvisibleNamespace.toInt)
+ self.assertEqual(objectFullname(signature.parameters['e'].annotation),
+ "sample.RemovedNamespace1_Enum")
+ signature = get_signature(sample.ObjectOnInvisibleNamespace.consume)
+ self.assertEqual(objectFullname(signature.parameters['other'].annotation),
+ "sample.ObjectOnInvisibleNamespace")
+
+ def testGlobalFunctionFromRemovedNamespace(self):
+ self.assertEqual(sample.mathSum(1, 2), 3)
+
+ def testEnumPromotedToUpperNamespace(self):
+ sample.UnremovedNamespace
+ sample.UnremovedNamespace.RemovedNamespace3_Enum
+ sample.UnremovedNamespace.RemovedNamespace3_Enum_Value0
+ sample.UnremovedNamespace.RemovedNamespace3_AnonymousEnum_Value0
+
+ def testNestedFunctionFromRemovedNamespace(self):
+ self.assertEqual(sample.UnremovedNamespace.nestedMathSum(1, 2), 3)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/event_loop_call_virtual_test.py b/sources/shiboken6/tests/samplebinding/event_loop_call_virtual_test.py
new file mode 100644
index 000000000..8e13d5d46
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/event_loop_call_virtual_test.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Simple event loop dispatcher test.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, Event
+
+
+class NoOverride(ObjectType):
+
+ pass
+
+
+class Override(ObjectType):
+
+ def __init__(self):
+ ObjectType.__init__(self)
+ self.called = False
+
+ def event(self, event):
+ self.called = True
+ return True
+
+
+class TestEventLoop(unittest.TestCase):
+
+ def testEventLoop(self):
+ '''Calling virtuals in a event loop'''
+ objs = [ObjectType(), NoOverride(), Override()]
+
+ evaluated = ObjectType.processEvent(objs,
+ Event(Event.BASIC_EVENT))
+
+ self.assertEqual(evaluated, 3)
+ self.assertTrue(objs[2].called)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/event_loop_thread_test.py b/sources/shiboken6/tests/samplebinding/event_loop_thread_test.py
new file mode 100644
index 000000000..8b854fca6
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/event_loop_thread_test.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+from random import random
+import sys
+import time
+import threading
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, Event
+
+
+class Producer(ObjectType):
+
+ def __init__(self):
+ ObjectType.__init__(self)
+ self.data = None
+ self.read = False
+
+ def event(self, event):
+ self.data = random()
+
+ while not self.read:
+ time.sleep(0.01)
+
+ return True
+
+
+class Collector(threading.Thread):
+
+ def __init__(self, objects):
+ threading.Thread.__init__(self)
+ self.max_runs = len(objects)
+ self.objects = objects
+ self.data = []
+
+ def run(self):
+ i = 0
+ while i < self.max_runs:
+ if self.objects[i].data is not None:
+ self.data.append(self.objects[i].data)
+ self.objects[i].read = True
+ i += 1
+ time.sleep(0.01)
+
+
+class TestEventLoopWithThread(unittest.TestCase):
+ '''Communication between a python thread and an simple
+ event loop in C++'''
+
+ def testBasic(self):
+ '''Allowing threads and calling virtuals from C++'''
+ number = 10
+ objs = [Producer() for x in range(number)]
+ thread = Collector(objs)
+
+ thread.start()
+
+ evaluated = ObjectType.processEvent(objs,
+ Event(Event.BASIC_EVENT))
+
+ thread.join()
+
+ producer_data = [x.data for x in objs]
+ self.assertEqual(evaluated, number)
+ self.assertEqual(producer_data, thread.data)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/exception_test.py b/sources/shiboken6/tests/samplebinding/exception_test.py
new file mode 100644
index 000000000..d9e6b377f
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/exception_test.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ExceptionTest
+
+
+class CppExceptionTest(unittest.TestCase):
+
+ def testVoid(self):
+ exceptionCount = 0
+ et = ExceptionTest()
+
+ et.voidThrowStdException(False)
+
+ try:
+ et.voidThrowStdException(True)
+ except: # noqa: E722
+ exceptionCount += 1
+
+ et.voidThrowInt(False)
+
+ try:
+ et.voidThrowInt(True)
+ except: # noqa: E722
+ exceptionCount += 1
+
+ self.assertEqual(exceptionCount, 2)
+
+ def testReturnValue(self):
+ exceptionCount = 0
+ et = ExceptionTest()
+
+ result = et.intThrowStdException(False)
+
+ try:
+ result = et.intThrowStdException(True)
+ except: # noqa: E722
+ exceptionCount += 1
+
+ result = et.intThrowInt(False)
+
+ try:
+ result = et.intThrowInt(True) # noqa: F841
+ except: # noqa: E722
+ exceptionCount += 1
+
+ self.assertEqual(exceptionCount, 2)
+
+ def testModifications(self):
+ """PYSIDE-1995, test whether exceptions are propagated
+ when return ownership modifications are generated."""
+ exceptionCount = 0
+ try:
+ et = ExceptionTest.create(True) # noqa: F841
+ except: # noqa: E722
+ exceptionCount += 1
+ self.assertEqual(exceptionCount, 1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/filter_test.py b/sources/shiboken6/tests/samplebinding/filter_test.py
new file mode 100644
index 000000000..df805093f
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/filter_test.py
@@ -0,0 +1,29 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Data, Intersection, Union
+
+
+class TestFilters(unittest.TestCase):
+
+ def testAnd(self):
+
+ f1 = Data(Data.Name, "joe")
+ f2 = Union()
+
+ inter = f1 & f2
+
+ self.assertEqual(type(inter), Intersection)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/global.h b/sources/shiboken6/tests/samplebinding/global.h
new file mode 100644
index 000000000..64806417a
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/global.h
@@ -0,0 +1,73 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "abstract.h"
+#include "blackbox.h"
+#include "bytearray.h"
+#include "bucket.h"
+#include "collector.h"
+#include "complex.h"
+#include "ctorconvrule.h"
+#include "ctparam.h"
+#include "cvlist.h"
+#include "sbkdate.h"
+#include "derived.h"
+#include "derivedusingct.h"
+#include "echo.h"
+#include "exceptiontest.h"
+#include "functions.h"
+#include "implicitconv.h"
+#include "nontypetemplate.h"
+#include "overloadsort.h"
+#include "handle.h"
+#include "injectcode.h"
+#include "list.h"
+#include "listuser.h"
+#include "mapuser.h"
+#include "modelindex.h"
+#include "modifications.h"
+#include "modified_constructor.h"
+#include "multiple_derived.h"
+#include "noimplicitconversion.h"
+#include "nondefaultctor.h"
+#include "objectmodel.h"
+#include "objecttype.h"
+#include "objecttypebyvalue.h"
+#include "objecttypeholder.h"
+#include "objecttypelayout.h"
+#include "objecttypeoperators.h"
+#include "objectview.h"
+#include "oddbool.h"
+#include "onlycopy.h"
+#include "overload.h"
+#include "pairuser.h"
+#include "pen.h"
+#include "photon.h"
+#include "point.h"
+#include "pointf.h"
+#include "pointerholder.h"
+#include "polygon.h"
+#include "privatector.h"
+#include "privatedtor.h"
+#include "protected.h"
+#include "rect.h"
+#include "reference.h"
+#include "renaming.h"
+#include "removednamespaces.h"
+#include "sample.h"
+#include "samplenamespace.h"
+#include "stdcomplex.h"
+#include "simplefile.h"
+#include "size.h"
+#include "snakecasetest.h"
+#include "str.h"
+#include "strlist.h"
+#include "sometime.h"
+#include "templateptr.h"
+#include "transform.h"
+#include "typesystypedef.h"
+#include "virtualmethods.h"
+#include "voidholder.h"
+#include "valueandvirtual.h"
+#include "expression.h"
+#include "filter.h"
diff --git a/sources/shiboken6/tests/samplebinding/handleholder_test.py b/sources/shiboken6/tests/samplebinding/handleholder_test.py
new file mode 100644
index 000000000..af22328c5
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/handleholder_test.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+''' Test case for a class that holds a unknown handle object.
+ Test case for BUG #1105.
+'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import HandleHolder
+
+
+class HandleHolderTest(unittest.TestCase):
+ def testCreation(self):
+ holder = HandleHolder(HandleHolder.createHandle())
+ holder2 = HandleHolder(HandleHolder.createHandle())
+ self.assertEqual(holder.compare(holder2), False)
+
+ def testTransfer(self):
+ holder = HandleHolder()
+ holder2 = HandleHolder(holder.handle())
+ self.assertTrue(holder.compare(holder2))
+
+ def testUseDefinedType(self):
+ holder = HandleHolder(8)
+ holder2 = HandleHolder(holder.handle2())
+ self.assertTrue(holder.compare2(holder2))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/hashabletype_test.py b/sources/shiboken6/tests/samplebinding/hashabletype_test.py
new file mode 100644
index 000000000..c41f5cc06
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/hashabletype_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for __hash__'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, Str
+
+
+class HashableTest(unittest.TestCase):
+
+ def testStrHash(self):
+ h = {}
+ s = Str("Hi")
+ h[s] = 2
+ self.assertTrue(h.get(s), 2)
+
+ def testObjectTypeHash(self):
+ h = {}
+ o = ObjectType()
+ h[o] = 2
+ self.assertTrue(h.get(o), 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ignorederefop_test.py b/sources/shiboken6/tests/samplebinding/ignorederefop_test.py
new file mode 100644
index 000000000..feb78d045
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ignorederefop_test.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import Reference
+
+
+class TestLackOfDereferenceOperators (unittest.TestCase):
+ def testIf(self):
+ r = Reference()
+ self.assertFalse(hasattr(r, "__mul__"))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/implicitconv_numerical_test.py b/sources/shiboken6/tests/samplebinding/implicitconv_numerical_test.py
new file mode 100644
index 000000000..081666281
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/implicitconv_numerical_test.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for inplicit converting C++ numeric types.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+import sys
+import sample
+
+# Hardcode the limits of the underlying C-types depending on architecture and memory
+# model (taking MSVC using LLP64 into account).
+cIntMin = -2147483648
+cIntMax = 2147483647
+cLongMin = cIntMin
+cLongMax = cIntMax
+maxRepresentableInt = sys.maxsize
+is64bitArchitecture = maxRepresentableInt > 2**32
+if is64bitArchitecture and sys.platform != 'win32':
+ cLongMin = -9223372036854775808
+ cLongMax = 9223372036854775807
+
+
+class NumericTester(unittest.TestCase):
+ '''Helper class for numeric comparison testing'''
+
+ def assertRaises(self, *args, **kwds):
+ if not hasattr(sys, "pypy_version_info"):
+ # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError"
+ return super().assertRaises(*args, **kwds)
+
+ def check_value(self, source, expected, callback, desired_type=None):
+ result = callback(source)
+ self.assertEqual(result, expected)
+
+ if desired_type:
+ self.assertEqual(type(result), desired_type)
+
+
+class FloatImplicitConvert(NumericTester):
+ '''Test case for implicit converting C++ numeric types.'''
+
+ def testFloatAsInt(self):
+ '''Float as Int'''
+ self.check_value(3.14, 3, sample.acceptInt, int)
+ self.assertRaises(OverflowError, sample.acceptInt, cIntMax + 400)
+
+ def testFloatAsLong(self):
+ '''Float as Long'''
+ #C++ longs are python ints for us
+ self.check_value(3.14, 3, sample.acceptLong, int)
+ self.assertRaises(OverflowError, sample.acceptLong, cLongMax + 400)
+
+ def testFloatAsUInt(self):
+ '''Float as unsigned Int'''
+ self.check_value(3.14, 3, sample.acceptUInt, int)
+ self.assertRaises(OverflowError, sample.acceptUInt, -3.14)
+
+ def testFloatAsULong(self):
+ '''Float as unsigned Long'''
+ #FIXME Breaking with SystemError "bad argument to internal function"
+ self.check_value(3.14, 3, sample.acceptULong, int)
+ self.assertRaises(OverflowError, sample.acceptULong, -3.14)
+
+ def testFloatAsDouble(self):
+ '''Float as double'''
+ self.check_value(3.14, 3.14, sample.acceptDouble, float)
+
+
+class IntImplicitConvert(NumericTester):
+ '''Test case for implicit converting C++ numeric types.'''
+
+ def testIntAsInt(self):
+ '''Int as Int'''
+ self.check_value(3, 3, sample.acceptInt, int)
+
+ def testIntAsLong(self):
+ '''Int as Long'''
+ self.check_value(3, 3, sample.acceptLong, int)
+
+ # cLongMax goes here as CPython implements int as a C long
+ self.check_value(cLongMax, cLongMax, sample.acceptLong, int)
+ self.check_value(cLongMin, cLongMin, sample.acceptLong, int)
+
+ def testIntAsUInt(self):
+ '''Int as unsigned Int'''
+ self.check_value(3, 3, sample.acceptUInt, int)
+ self.assertRaises(OverflowError, sample.acceptUInt, -3)
+
+ def testIntAsULong(self):
+ '''Int as unsigned Long'''
+ self.check_value(3, 3, sample.acceptULong, int)
+ self.assertRaises(OverflowError, sample.acceptULong, -3)
+
+ def testFloatAsDouble(self):
+ '''Float as double'''
+ self.check_value(3.14, 3.14, sample.acceptDouble, float)
+
+
+class LongImplicitConvert(NumericTester):
+ '''Test case for implicit converting C++ numeric types.'''
+
+ def testLongAsInt(self):
+ '''Long as Int'''
+ self.check_value(24224, 24224, sample.acceptInt, int)
+ self.assertRaises(OverflowError, sample.acceptInt, cIntMax + 20)
+
+ def testLongAsLong(self):
+ '''Long as Long'''
+ self.check_value(2405, 2405, sample.acceptLong, int)
+ self.assertRaises(OverflowError, sample.acceptLong, cLongMax + 20)
+
+ def testLongAsUInt(self):
+ '''Long as unsigned Int'''
+ self.check_value(260, 260, sample.acceptUInt, int)
+ self.assertRaises(OverflowError, sample.acceptUInt, -42)
+
+ def testLongAsULong(self):
+ '''Long as unsigned Long'''
+ self.check_value(128, 128, sample.acceptULong, int)
+ self.assertRaises(OverflowError, sample.acceptULong, -334)
+
+ def testLongAsDouble(self):
+ '''Float as double'''
+ self.check_value(42, 42, sample.acceptDouble, float)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/implicitconv_test.py b/sources/shiboken6/tests/samplebinding/implicitconv_test.py
new file mode 100644
index 000000000..ebafe0c52
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/implicitconv_test.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for implicit conversions'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ImplicitConv, ObjectType
+
+
+class ImplicitConvTest(unittest.TestCase):
+ '''Test case for implicit conversions'''
+
+ def testImplicitConversions(self):
+ '''Test if overloaded function call decisor takes implicit conversions into account.'''
+ ic = ImplicitConv.implicitConvCommon(ImplicitConv())
+ self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorNone)
+
+ ic = ImplicitConv.implicitConvCommon(3)
+ self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorOne)
+ self.assertEqual(ic.objId(), 3)
+
+ ic = ImplicitConv.implicitConvCommon(ImplicitConv.CtorThree)
+ self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorThree)
+
+ obj = ObjectType()
+ ic = ImplicitConv.implicitConvCommon(obj)
+ self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorObjectTypeReference)
+
+ ic = ImplicitConv.implicitConvCommon(42.42)
+ self.assertEqual(ic.value(), 42.42)
+
+ ic = ImplicitConv(None)
+ self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorPrimitiveType)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/inheritanceandscope_test.py b/sources/shiboken6/tests/samplebinding/inheritanceandscope_test.py
new file mode 100644
index 000000000..28d62486a
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/inheritanceandscope_test.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for finding scope in cases involving inheritance.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import SampleNamespace
+
+
+class ScopeAndInheritanceTest(unittest.TestCase):
+ '''Test cases for finding scope in cases involving inheritance.'''
+
+ def testMethodCorrectlyWrapper(self):
+ '''A method returning a type declared in the scope of the method's
+ class parent must be found and the method correctly exported.'''
+ meth = getattr(SampleNamespace.DerivedFromNamespace, # noqa: F841
+ 'methodReturningTypeFromParentScope')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/injectcode_test.py b/sources/shiboken6/tests/samplebinding/injectcode_test.py
new file mode 100644
index 000000000..f673a7807
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/injectcode_test.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for std::list container conversions'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import InjectCode
+
+
+class MyInjectCode(InjectCode):
+ def __init__(self):
+ InjectCode.__init__(self)
+ self.multiplier = 2
+
+ def arrayMethod(self, values):
+ return self.multiplier * sum(values)
+
+
+class InjectCodeTest(unittest.TestCase):
+
+ @unittest.skipIf(hasattr(sys, "pypy_version_info"),
+ "PyPy type objects cannot be modified (yet) after creation")
+ def testTypeNativeBeginning_TypeTargetBeginning(self):
+ ic = InjectCode()
+ self.assertEqual(str(ic), "Hi! I'm the inject code dummy class.")
+
+ def testFunctionTargetBeginning_FunctionTargetEnd(self):
+ ic = InjectCode()
+ ret = ic.simpleMethod1(2, 1)
+ self.assertEqual(ret, "4end")
+ ret = ic.simpleMethod1(4, 2)
+ self.assertEqual(ret, "7end")
+
+ def testFunctionTargetBeginning(self):
+ ic = InjectCode()
+ ret = ic.simpleMethod2()
+ self.assertEqual(ret, "_end")
+
+ def testArgsModification(self):
+ ic = InjectCode()
+ ret = ic.overloadedMethod(["1", "2", "3", "4"])
+ self.assertEqual(ret, "1234")
+ ret = ic.overloadedMethod(2, 0.5)
+ self.assertEqual(ret, "2.5")
+ ret = ic.overloadedMethod(6, True)
+ self.assertEqual(ret, "6true")
+
+ def testArgsModification2(self):
+ ic = InjectCode()
+ ret = ic.simpleMethod3(["1", "2", "3", "4"])
+ self.assertEqual(ret, "1234")
+
+ def testArgumentRemovalAndArgumentTypeModification(self):
+ '''A method has its first argument removed and the second modified.'''
+ ic = InjectCode()
+ values = (1, 2, 3, 4, 5)
+ result = ic.arrayMethod(values)
+ self.assertEqual(result, sum(values))
+
+ def testCallVirtualMethodWithArgumentRemovalAndArgumentTypeModification(self):
+ '''A virtual method has its first argument removed and the second modified.'''
+ ic = InjectCode()
+ values = (1, 2, 3, 4, 5)
+ result = ic.callArrayMethod(values)
+ self.assertEqual(result, sum(values))
+
+ def testCallReimplementedVirtualMethodWithArgumentRemovalAndArgumentTypeModification(self):
+ '''Calls a reimplemented virtual method that had its first argument removed
+ and the second modified.'''
+ ic = MyInjectCode()
+ values = (1, 2, 3, 4, 5)
+ result = ic.callArrayMethod(values)
+ self.assertEqual(result, ic.multiplier * sum(values))
+
+ def testUsageOfTypeSystemCheckVariableOnPrimitiveType(self):
+ '''When the sequence item is convertible to an integer -1 is returned,
+ or -2 if its not convertible.'''
+ ic = InjectCode()
+ values = (1, 2, 3, 4, '5', 6.7)
+ result = ic.arrayMethod(values)
+
+ ints = [v for v in values if isinstance(v, int)]
+ floats = [-1 for v in values if isinstance(v, float)]
+ other = [-2 for v in values if not isinstance(v, int) and not isinstance(v, float)]
+ self.assertEqual(result, sum(ints + floats + other))
+
+
+class IntArrayTest(unittest.TestCase):
+ '''Test case for converting python sequence to int array'''
+
+ def testBasic(self):
+ '''Shiboken::sequenceToIntArray - basic case'''
+ args = [1, 2, 3, 4]
+ ic = InjectCode()
+ self.assertEqual(sum(args) + len(args), ic.sumArrayAndLength(args))
+
+ def testEmpty(self):
+ '''Shiboken::sequenceToIntArray - empty sequence'''
+ args = []
+ ic = InjectCode()
+ self.assertEqual(sum(args) + len(args), ic.sumArrayAndLength(args))
+
+ def testWithZero(self):
+ '''Shiboken::sequenceToIntArray - count only up to zero'''
+ args = [1, 2, 0, 3]
+ ic = InjectCode()
+ self.assertEqual(sum([1, 2]) + len([1, 2]), ic.sumArrayAndLength(args))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/innerclass_test.py b/sources/shiboken6/tests/samplebinding/innerclass_test.py
new file mode 100644
index 000000000..721f33483
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/innerclass_test.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Derived
+
+
+class TestInnerClass(unittest.TestCase):
+ def testInstaciate(self):
+ d = Derived.SomeInnerClass() # noqa: F841
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/intlist_test.py b/sources/shiboken6/tests/samplebinding/intlist_test.py
new file mode 100644
index 000000000..defa9ca71
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/intlist_test.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import IntList
+
+
+class IntListTest(unittest.TestCase):
+
+ def testAutoFunctionsToBaseList(self):
+ lst = IntList()
+ self.assertEqual(len(lst), 0)
+ lst.append(10)
+ self.assertEqual(lst[0], 10)
+ lst.append(20)
+ self.assertEqual(lst[1], 20)
+ lst.append(30)
+ self.assertEqual(lst[2], 30)
+ lst[1] = 25
+ self.assertEqual(lst[0], 10)
+ self.assertEqual(lst[1], 25)
+ self.assertEqual(lst[2], 30)
+ self.assertEqual(len(lst), 3)
+
+ def testIntListCtor_NoParams(self):
+ '''IntList constructor receives no parameter.'''
+ il = IntList()
+ self.assertEqual(len(il), 0)
+ self.assertEqual(il.constructorUsed(), IntList.NoParamsCtor)
+
+ def testIntListCtor_int(self):
+ '''IntList constructor receives an integer.'''
+ value = 123
+ il = IntList(value)
+ self.assertEqual(len(il), 1)
+ self.assertEqual(il[0], value)
+ self.assertEqual(il.constructorUsed(), IntList.IntCtor)
+
+ def testIntListCtor_IntList(self):
+ '''IntList constructor receives an IntList object.'''
+ il1 = IntList(123)
+ il2 = IntList(il1)
+ self.assertEqual(len(il1), len(il2))
+ for i in range(len(il1)):
+ self.assertEqual(il1[i], il2[i])
+ self.assertEqual(il2.constructorUsed(), IntList.CopyCtor)
+
+ def testIntListCtor_ListOfInts(self):
+ '''IntList constructor receives an integer list.'''
+ ints = [123, 456]
+ il = IntList(ints)
+ self.assertEqual(len(il), len(ints))
+ for i in range(len(il)):
+ self.assertEqual(il[i], ints[i])
+ self.assertEqual(il.constructorUsed(), IntList.ListOfIntCtor)
+
+ def testIntListAttributeTypeCheck(self):
+ '''Attribute values to IntList.'''
+ il = IntList([0, 1, 2])
+ self.assertEqual(len(il), 3)
+ il[0] = 123
+ self.assertEqual(len(il), 3)
+ self.assertEqual(il[0], 123)
+ il[1] = 432.1
+ self.assertEqual(len(il), 3)
+ self.assertEqual(il[1], int(432.1))
+ self.assertRaises(TypeError, il.__setitem__, 2, '78')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/intwrapper_test.py b/sources/shiboken6/tests/samplebinding/intwrapper_test.py
new file mode 100644
index 000000000..d883adf47
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/intwrapper_test.py
@@ -0,0 +1,39 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import IntWrapper
+
+
+class IntWrapperTest(unittest.TestCase):
+
+ def testOperators(self):
+ ten1 = IntWrapper(10)
+ ten2 = IntWrapper(10)
+ twenty = IntWrapper(20)
+ self.assertTrue(ten1 == ten2)
+ self.assertTrue(ten1 != twenty)
+ self.assertTrue(ten1 + ten2 == twenty)
+ self.assertTrue(ten1 - ten2 == IntWrapper(0))
+ i = IntWrapper(ten1.toInt())
+ i += ten2
+ self.assertTrue(i == twenty)
+ i -= ten2
+ self.assertTrue(i == ten1)
+
+ def testAddPyMethodDef(self):
+ """Test of added free function (PYSIDE-1905)."""
+ i = IntWrapper(10)
+ self.assertEqual(i.add_ints(10, 20), 30)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/invalid_virtual_return_test.py b/sources/shiboken6/tests/samplebinding/invalid_virtual_return_test.py
new file mode 100644
index 000000000..bb35b2bb1
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/invalid_virtual_return_test.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for returning invalid types in a virtual function'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import ObjectModel, ObjectType, ObjectView
+
+import warnings
+
+
+class MyObject(ObjectType):
+ pass
+
+
+class ListModelWrong(ObjectModel):
+
+ def __init__(self, parent=None):
+ ObjectModel.__init__(self, parent)
+ self.obj = 0
+
+ def data(self):
+ warnings.simplefilter('error')
+ # Shouldn't segfault. Must set TypeError
+ return self.obj
+
+
+class ModelWrongReturnTest(unittest.TestCase):
+
+ def testWrongTypeReturn(self):
+ model = ListModelWrong()
+ view = ObjectView(model)
+ self.assertRaises(RuntimeWarning, view.getRawModelData) # calls model.data()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/keep_reference_test.py b/sources/shiboken6/tests/samplebinding/keep_reference_test.py
new file mode 100644
index 000000000..10591fec6
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/keep_reference_test.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectModel, ObjectView
+
+
+class TestKeepReference(unittest.TestCase):
+ '''Test case for objects that keep references to other object without
+ owning them (e.g. model/view relationships).'''
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testReferenceCounting(self):
+ '''Tests reference count of model-like object referred by view-like objects.'''
+ model1 = ObjectModel()
+ refcount1 = sys.getrefcount(model1)
+ view1 = ObjectView()
+ view1.setModel(model1)
+ self.assertEqual(sys.getrefcount(view1.model()), refcount1 + 1)
+
+ view2 = ObjectView()
+ view2.setModel(model1)
+ self.assertEqual(sys.getrefcount(view2.model()), refcount1 + 2)
+
+ model2 = ObjectModel()
+ view2.setModel(model2)
+ self.assertEqual(sys.getrefcount(view1.model()), refcount1 + 1)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testReferenceCountingWhenDeletingReferrer(self):
+ '''Tests reference count of model-like object referred by deceased view-like object.'''
+ model = ObjectModel()
+ refcount1 = sys.getrefcount(model)
+ view = ObjectView()
+ view.setModel(model)
+ self.assertEqual(sys.getrefcount(view.model()), refcount1 + 1)
+
+ del view
+ self.assertEqual(sys.getrefcount(model), refcount1)
+
+ def testReferreedObjectSurvivalAfterContextEnd(self):
+ '''Model-like object assigned to a view-like object must survive
+ after get out of context.'''
+ def createModelAndSetToView(view):
+ model = ObjectModel()
+ model.setObjectName('created model')
+ view.setModel(model)
+ view = ObjectView()
+ createModelAndSetToView(view)
+ model = view.model() # noqa: F841
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/list_test.py b/sources/shiboken6/tests/samplebinding/list_test.py
new file mode 100644
index 000000000..b668bfd90
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/list_test.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for std::list container conversions'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ListUser, Point, PointF
+
+
+class ExtendedListUser(ListUser):
+ def __init__(self):
+ ListUser.__init__(self)
+ self.create_list_called = False
+
+ def createList(self):
+ self.create_list_called = True
+ return [2, 3, 5, 7, 13]
+
+
+class ListConversionTest(unittest.TestCase):
+ '''Test case for std::list container conversions'''
+
+ def testReimplementedVirtualMethodCall(self):
+ '''Test if a Python override of a virtual method is correctly called from C++.'''
+ lu = ExtendedListUser()
+ lst = lu.callCreateList()
+ self.assertTrue(lu.create_list_called)
+ self.assertEqual(type(lst), list)
+ for item in lst:
+ self.assertEqual(type(item), int)
+
+ def testPrimitiveConversionInsideContainer(self):
+ '''Test primitive type conversion inside conversible std::list container.'''
+ cpx0 = complex(1.2, 3.4)
+ cpx1 = complex(5.6, 7.8)
+ lst = ListUser.createComplexList(cpx0, cpx1)
+ self.assertEqual(type(lst), list)
+ for item in lst:
+ self.assertEqual(type(item), complex)
+ self.assertEqual(lst, [cpx0, cpx1])
+
+ def testSumListIntegers(self):
+ '''Test method that sums a list of integer values.'''
+ lu = ListUser()
+ lst = [3, 5, 7]
+ result = lu.sumList(lst)
+ self.assertEqual(result, sum(lst))
+
+ def testSumListFloats(self):
+ '''Test method that sums a list of float values.'''
+ lu = ListUser()
+ lst = [3.3, 4.4, 5.5]
+ result = lu.sumList(lst)
+ self.assertEqual(result, sum(lst))
+
+ def testConversionInBothDirections(self):
+ '''Test converting a list from Python to C++ and back again.'''
+ lu = ListUser()
+ lst = [3, 5, 7]
+ lu.setList(lst)
+ result = lu.getList()
+ self.assertEqual(result, lst)
+
+ def testConversionInBothDirectionsWithSimilarContainer(self):
+ '''Test converting a tuple, instead of the expected list,
+ from Python to C++ and back again.'''
+ lu = ListUser()
+ lst = (3, 5, 7)
+ lu.setList(lst)
+ result = lu.getList()
+ self.assertNotEqual(result, lst)
+ self.assertEqual(result, list(lst))
+
+ def testConversionOfListOfObjectsPassedAsArgument(self):
+ '''Calls method with a Python list of wrapped objects to be converted to a C++ list.'''
+ mult = 3
+ pts0 = (Point(1.0, 2.0), Point(3.3, 4.4), Point(5, 6))
+ pts1 = (Point(1.0, 2.0), Point(3.3, 4.4), Point(5, 6))
+ ListUser.multiplyPointList(pts1, mult)
+ for pt0, pt1 in zip(pts0, pts1):
+ self.assertEqual(pt0.x() * mult, pt1.x())
+ self.assertEqual(pt0.y() * mult, pt1.y())
+
+ def testConversionOfInvalidLists(self):
+ mult = 3
+ pts = (Point(1.0, 2.0), 3, Point(5, 6))
+ self.assertRaises(TypeError, ListUser.multiplyPointList, pts, mult)
+
+ def testOverloadMethodReceivingRelatedContainerTypes(self):
+ self.assertEqual(ListUser.ListOfPointF, ListUser.listOfPoints([PointF()]))
+ self.assertEqual(ListUser.ListOfPoint, ListUser.listOfPoints([Point()]))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/lock_test.py b/sources/shiboken6/tests/samplebinding/lock_test.py
new file mode 100644
index 000000000..acd47634a
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/lock_test.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Simple test with a blocking C++ method that should allow python
+ threads to run.'''
+
+import os
+import sys
+import threading
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Bucket
+
+
+class Unlocker(threading.Thread):
+
+ def __init__(self, bucket):
+ threading.Thread.__init__(self)
+ self.bucket = bucket
+
+ def run(self):
+ while not self.bucket.locked():
+ pass
+
+ self.bucket.unlock()
+
+
+class MyBucket(Bucket):
+
+ def __init__(self):
+ Bucket.__init__(self)
+
+ def virtualBlockerMethod(self):
+ self.lock()
+ return True
+
+
+class TestLockUnlock(unittest.TestCase):
+
+ def testBasic(self):
+ '''Locking in C++ and releasing in a python thread'''
+ bucket = Bucket()
+ unlocker = Unlocker(bucket)
+
+ unlocker.start()
+ bucket.lock()
+ unlocker.join()
+
+ def testVirtualBlocker(self):
+ '''Same as the basic case but blocker method is a C++ virtual called from C++.'''
+ bucket = Bucket()
+ unlocker = Unlocker(bucket)
+
+ unlocker.start()
+ result = bucket.callVirtualBlockerMethodButYouDontKnowThis()
+ unlocker.join()
+ self.assertTrue(result)
+
+ def testReimplementedVirtualBlocker(self):
+ '''Same as the basic case but blocker method is a C++ virtual reimplemented
+ in Python and called from C++.'''
+ mybucket = MyBucket()
+ unlocker = Unlocker(mybucket)
+
+ unlocker.start()
+ result = mybucket.callVirtualBlockerMethodButYouDontKnowThis()
+ unlocker.join()
+ self.assertTrue(result)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/map_test.py b/sources/shiboken6/tests/samplebinding/map_test.py
new file mode 100644
index 000000000..fa99ad2e7
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/map_test.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for std::map container conversions'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import MapUser
+
+
+class ExtendedMapUser(MapUser):
+ def __init__(self):
+ MapUser.__init__(self)
+ self.create_map_called = False
+
+ def createMap(self):
+ self.create_map_called = True
+ return {'two': (complex(2.2, 2.2), 2),
+ 'three': (complex(3.3, 3.3), 3),
+ 'five': (complex(5.5, 5.5), 5),
+ 'seven': (complex(7.7, 7.7), 7)}
+
+
+class MapConversionTest(unittest.TestCase):
+ '''Test case for std::map container conversions'''
+
+ def testReimplementedVirtualMethodCall(self):
+ '''Test if a Python override of a virtual method is correctly called from C++.'''
+ mu = ExtendedMapUser()
+ map_ = mu.callCreateMap()
+ self.assertTrue(mu.create_map_called)
+ self.assertEqual(type(map_), dict)
+ for key, value in map_.items():
+ self.assertEqual(type(key), str)
+ self.assertEqual(type(value[0]), complex)
+ self.assertEqual(type(value[1]), int)
+
+ def testConversionInBothDirections(self):
+ '''Test converting a map from Python to C++ and back again.'''
+ mu = MapUser()
+ map_ = {'odds': [2, 4, 6], 'evens': [3, 5, 7], 'primes': [3, 4, 6]}
+ mu.setMap(map_)
+ result = mu.getMap()
+ self.assertEqual(result, map_)
+
+ def testConversionMapIntKeyValueTypeValue(self):
+ '''C++ signature: MapUser::passMapIntValueType(const std::map<int, const ByteArray>&)'''
+ mu = MapUser()
+ map_ = {0: 'string'}
+ result = mu.passMapIntValueType(map_)
+ self.assertEqual(map_, result)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/metaclass_test.py b/sources/shiboken6/tests/samplebinding/metaclass_test.py
new file mode 100644
index 000000000..4d7eeda96
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/metaclass_test.py
@@ -0,0 +1,52 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point
+
+
+class MetaA(type):
+ pass
+
+
+class A(object):
+ __metaclass__ = MetaA
+
+
+MetaB = type(Point)
+B = Point
+
+
+class MetaC(MetaA, MetaB):
+ pass
+
+
+class C(A, B):
+ __metaclass__ = MetaC
+
+
+class D(C):
+ pass
+
+
+class TestMetaClass(unittest.TestCase):
+ def testIt(self):
+ w1 = C() # works
+ w1.setX(1)
+ w1.setY(2)
+
+ w2 = D() # should work!
+ w2.setX(3)
+ w2.setY(4)
+
+ w3 = w1 + w2
+ self.assertEqual(w3.x(), 4)
+ self.assertEqual(w3.y(), 6)
diff --git a/sources/shiboken6/tests/samplebinding/mi_virtual_methods_test.py b/sources/shiboken6/tests/samplebinding/mi_virtual_methods_test.py
new file mode 100644
index 000000000..8d324db59
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/mi_virtual_methods_test.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for virtual methods in multiple inheritance scenarios'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import VirtualMethods, ObjectType, Event
+
+
+class ImplementsNone(ObjectType, VirtualMethods):
+ '''Implements no virtual methods'''
+
+ def __init__(self):
+ ObjectType.__init__(self)
+ VirtualMethods.__init__(self)
+
+
+class ImplementsBoth(ObjectType, VirtualMethods):
+ '''Implements ObjectType.event and VirtualMethods.sum1'''
+
+ def __init__(self):
+ ObjectType.__init__(self)
+ VirtualMethods.__init__(self)
+ self.event_processed = False
+
+ def event(self, event):
+ self.event_processed = True
+ return True
+
+ def sum1(self, arg0, arg1, arg2):
+ return (arg0 + arg1 + arg2) * 2
+
+
+class CppVirtualTest(unittest.TestCase):
+ '''Virtual method defined in c++ called from C++'''
+
+ def testCpp(self):
+ '''C++ calling C++ virtual method in multiple inheritance scenario'''
+ obj = ImplementsNone()
+ self.assertTrue(ObjectType.processEvent([obj], Event(Event.BASIC_EVENT)))
+ self.assertRaises(AttributeError, getattr, obj, 'event_processed')
+
+ self.assertEqual(obj.callSum0(1, 2, 3), 6)
+
+
+class PyVirtualTest(unittest.TestCase):
+ '''Virtual method reimplemented in python called from C++'''
+
+ def testEvent(self):
+ '''C++ calling Python reimplementation of virtual in multiple inheritance'''
+ obj = ImplementsBoth()
+ self.assertTrue(ObjectType.processEvent([obj], Event(Event.BASIC_EVENT)))
+ self.assertTrue(obj.event_processed)
+
+ self.assertEqual(obj.callSum1(1, 2, 3), 12)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/mixed_mi_test.py b/sources/shiboken6/tests/samplebinding/mixed_mi_test.py
new file mode 100644
index 000000000..fa8481600
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/mixed_mi_test.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for multiple inheritance in mixed Python/C++ scenarios'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class Base(object):
+ '''Base Python class'''
+
+ def __init__(self):
+ self.name = ''
+
+ def pythonName(self):
+ return self.name
+
+ def setPythonName(self, name):
+ self.name = name
+
+
+class Child(Base, ObjectType):
+ '''Dummy class with mixed parents'''
+
+ def __init__(self):
+ Base.__init__(self)
+ ObjectType.__init__(self)
+
+
+class MixedInheritanceTest(unittest.TestCase):
+
+ def testMixed(self):
+ '''Mixed Python/C++ multiple inheritance'''
+ obj = Child()
+
+ obj.setObjectName('aaa')
+ self.assertEqual(obj.objectName(), 'aaa')
+
+ obj.setPythonName('python')
+ self.assertEqual(obj.pythonName(), 'python')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/modelindex_test.py b/sources/shiboken6/tests/samplebinding/modelindex_test.py
new file mode 100644
index 000000000..e23503eff
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/modelindex_test.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ModelIndex, ReferentModelIndex, PersistentModelIndex
+
+
+class TestCastOperator(unittest.TestCase):
+
+ def testCastOperatorReturningValue(self):
+ index = PersistentModelIndex()
+ index.setValue(123)
+ self.assertEqual(index.value(), 123)
+ self.assertEqual(index.value(), ModelIndex.getValue(index))
+
+ def testCastOperatorReturningReference(self):
+ index = ReferentModelIndex()
+ index.setValue(123)
+ self.assertEqual(index.value(), 123)
+ self.assertEqual(index.value(), ModelIndex.getValue(index))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/modelview_test.py b/sources/shiboken6/tests/samplebinding/modelview_test.py
new file mode 100644
index 000000000..b5663a04e
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/modelview_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for objects that keep references to other object without owning them
+ (e.g. model/view relationships).'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import ObjectModel, ObjectType, ObjectView
+
+
+object_name = 'test object'
+
+
+class MyObject(ObjectType):
+ pass
+
+
+class ListModelKeepsReference(ObjectModel):
+ def __init__(self, parent=None):
+ ObjectModel.__init__(self, parent)
+ self.obj = MyObject()
+ self.obj.setObjectName(object_name)
+
+ def data(self):
+ return self.obj
+
+
+class ListModelDoesntKeepsReference(ObjectModel):
+ def data(self):
+ obj = MyObject()
+ obj.setObjectName(object_name)
+ return obj
+
+
+class ModelViewTest(unittest.TestCase):
+
+ def testListModelDoesntKeepsReference(self):
+ model = ListModelDoesntKeepsReference()
+ view = ObjectView(model)
+ obj = view.getRawModelData()
+ self.assertEqual(type(obj), MyObject)
+ self.assertEqual(obj.objectName(), object_name)
+
+ def testListModelKeepsReference(self):
+ model = ListModelKeepsReference()
+ view = ObjectView(model)
+ obj = view.getRawModelData()
+ self.assertEqual(type(obj), MyObject)
+ self.assertEqual(obj.objectName(), object_name)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/modifications_test.py b/sources/shiboken6/tests/samplebinding/modifications_test.py
new file mode 100644
index 000000000..dced14396
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/modifications_test.py
@@ -0,0 +1,224 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for method modifications performed as described on type system. '''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Modifications, Point, ByteArray
+
+
+class ExtModifications(Modifications):
+ def __init__(self):
+ Modifications.__init__(self)
+ self.multiplier = 3.0
+ self.increment = 10.0
+
+ def name(self):
+ return 'ExtModifications'
+
+ def differenceOfPointCoordinates(self, point):
+ ok, res = Modifications.differenceOfPointCoordinates(self, point)
+ return ok, res * self.multiplier + self.increment
+
+
+class ModificationsTest(unittest.TestCase):
+ '''Test cases for method modifications performed as described on type system. '''
+
+ def setUp(self):
+ self.mods = Modifications()
+
+ def tearDown(self):
+ del self.mods
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ def testRenamedMethodAvailability(self):
+ '''Test if Modification class really have renamed the 'className'
+ virtual method to 'name'.'''
+ self.assertTrue('className' not in dir(Modifications))
+ self.assertTrue('name' in dir(Modifications))
+
+ def testReimplementationOfRenamedVirtualMethod(self):
+ '''Test if class inheriting from Modification class have the reimplementation
+ of renamed virtual method called.'''
+ em = ExtModifications()
+ self.assertEqual(self.mods.name(), 'Modifications')
+ self.assertEqual(em.name(), 'ExtModifications')
+
+ def testRegularMethodRenaming(self):
+ '''Test if Modifications::cppMultiply was correctly renamed to calculateArea.'''
+ self.assertTrue('cppMultiply' not in dir(Modifications))
+ self.assertTrue('calculateArea' in dir(Modifications))
+ self.assertEqual(self.mods.calculateArea(3, 6), 3 * 6)
+
+ def testRegularMethodRemoval(self):
+ '''Test if 'Modifications::exclusiveCppStuff' was removed from Python bindings.'''
+ self.assertTrue('exclusiveCppStuff' not in dir(Modifications))
+
+ def testArgumentRemoval(self):
+ '''Test if second argument of Modifications::doublePlus(int, int) was removed.'''
+ self.assertRaises(TypeError, self.mods.doublePlus, 3, 7)
+ self.assertEqual(self.mods.doublePlus(7), 14)
+
+ def testDefaultValueRemoval(self):
+ '''Test if default value was removed from first argument of
+ Modifications::increment(int).'''
+ self.assertRaises(TypeError, self.mods.increment)
+ self.assertEqual(self.mods.increment(7), 8)
+
+ def testDefaultValueReplacement(self):
+ '''Test if default values for both arguments of Modifications::power(int, int)
+ were modified.'''
+ # original default values: int power(int base = 1, int exponent = 0);
+ self.assertNotEqual(self.mods.power(4), 1)
+ # modified default values: int power(int base = 2, int exponent = 1);
+ self.assertEqual(self.mods.power(), 2)
+ self.assertEqual(self.mods.power(3), 3)
+ self.assertEqual(self.mods.power(5, 3), 5**3)
+
+ def testSetNewDefaultValue(self):
+ '''Test if default value was correctly set to 10 for first argument of
+ Modifications::timesTen(int).'''
+ self.assertEqual(self.mods.timesTen(7), 70)
+ self.assertEqual(self.mods.timesTen(), 100)
+
+ def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates1(self):
+ '''Test modifications to method signature and return value using type
+ system templates (case 1).'''
+ result, ok = self.mods.pointToPair(Point(2, 5))
+ self.assertEqual(type(ok), bool)
+ self.assertEqual(type(result), tuple)
+ self.assertEqual(len(result), 2)
+ self.assertEqual(type(result[0]), float)
+ self.assertEqual(type(result[1]), float)
+ self.assertEqual(result[0], 2.0)
+ self.assertEqual(result[1], 5.0)
+
+ def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates2(self):
+ '''Test modifications to method signature and return value using
+ type system templates (case 2).'''
+ result, ok = self.mods.multiplyPointCoordsPlusValue(Point(2, 5), 4.1)
+ self.assertEqual(type(ok), bool)
+ self.assertEqual(type(result), float)
+ self.assertEqual(result, 14.1)
+
+ def testOverloadedMethodModifications(self):
+ '''Tests modifications to an overloaded method'''
+ # overloaded(int, bool[removed], int, double)
+ self.assertEqual(self.mods.overloaded(1, 2, 3.1), Modifications.Overloaded_ibid)
+ # overloaded(int, bool, int[removed,default=321], int)
+ self.assertEqual(self.mods.overloaded(1, True, 2), Modifications.Overloaded_ibii)
+ # the others weren't modified
+ self.assertEqual(self.mods.overloaded(1, True, 2, False), Modifications.Overloaded_ibib)
+ self.assertEqual(self.mods.overloaded(1, False, 2, Point(3, 4)),
+ Modifications.Overloaded_ibiP)
+ self.assertRaises(TypeError, self.mods.overloaded, 1, True, Point(2, 3), Point(4, 5))
+ self.assertEqual(self.mods.over(1, True, Point(2, 3), Point(4, 5)),
+ Modifications.Overloaded_ibPP)
+
+ def testPointArrayModification(self):
+ points = (Point(1, 1), Point(2, 2))
+ summedPoint = Point(1, 1) + Point(2, 2)
+ self.assertEqual(self.mods.sumPointArray(points), summedPoint)
+
+ def testTypeSystemVariableReplacementInFunctionModification(self):
+ ba = ByteArray('12345')
+ self.assertEqual(self.mods.getSize(ba), len(ba))
+ self.assertEqual(self.mods.getSize(ba, 20), 20)
+
+ def testNoNulPointerTag(self):
+ point = Point(12, 34)
+ self.assertEqual(self.mods.sumPointCoordinates(point), 12 + 34)
+ self.assertRaises(TypeError, self.mods.sumPointCoordinates, None)
+
+ def testNonConversionRuleForArgumentWithDefaultValue(self):
+ status, obj = self.mods.nonConversionRuleForArgumentWithDefaultValue()
+ self.assertTrue(status)
+ self.assertEqual(obj, self.mods.getObject())
+ self.assertEqual(obj.objectName(), 'MyObject')
+
+ def testInjectCodeWithConversionVariableForUserPrimitive(self):
+ self.assertTrue(Modifications.invertBoolean(False))
+ self.assertFalse(Modifications.invertBoolean(True))
+
+ def testConversionRuleForReturnType(self):
+ x, y = 11, 2
+ diff = float(abs(x - y))
+ point = Point(x, y)
+
+ ok, res = self.mods.differenceOfPointCoordinates(point)
+ self.assertTrue(isinstance(ok, bool))
+ self.assertTrue(isinstance(res, float))
+ self.assertEqual(res, diff)
+
+ ok, res = self.mods.callDifferenceOfPointCoordinates(point)
+ self.assertTrue(isinstance(ok, bool))
+ self.assertTrue(isinstance(res, float))
+ self.assertEqual(res, diff)
+
+ ok, res = self.mods.differenceOfPointCoordinates(None)
+ self.assertTrue(isinstance(ok, bool))
+ self.assertTrue(isinstance(res, float))
+ self.assertEqual(res, 0.0)
+
+ ok, res = self.mods.callDifferenceOfPointCoordinates(None)
+ self.assertTrue(isinstance(ok, bool))
+ self.assertTrue(isinstance(res, float))
+ self.assertEqual(res, 0.0)
+
+ def testConversionRuleForReturnTypeOnExtendedClass(self):
+ x, y = 11, 2
+ diff = float(abs(x - y))
+ point = Point(x, y)
+ em = ExtModifications()
+
+ ok, res = em.differenceOfPointCoordinates(point)
+ self.assertTrue(isinstance(ok, bool))
+ self.assertTrue(isinstance(res, float))
+ self.assertEqual(res, diff * em.multiplier + em.increment)
+
+ ok, res = em.callDifferenceOfPointCoordinates(point)
+ self.assertTrue(isinstance(ok, bool))
+ self.assertTrue(isinstance(res, float))
+ self.assertEqual(res, diff * em.multiplier + em.increment)
+
+ ok, res = em.differenceOfPointCoordinates(None)
+ self.assertTrue(isinstance(ok, bool))
+ self.assertTrue(isinstance(res, float))
+ self.assertEqual(res, em.increment)
+
+ ok, res = em.callDifferenceOfPointCoordinates(None)
+ self.assertTrue(isinstance(ok, bool))
+ self.assertTrue(isinstance(res, float))
+ self.assertEqual(res, em.increment)
+
+ def testDefaultValueModifications(self):
+ # PSYIDE-1095: setEnumValue() has the default value modified to
+ # calling defaultEnumValue() which returns Modifications.TestEnumValue2.
+ # This used to generated broken code since defaultEnumValue() was
+ # qualified by the enum scope.
+ modifications = Modifications()
+ modifications.setEnumValue()
+ self.assertEqual(modifications.enumValue(), Modifications.TestEnumValue2)
+
+ def testSetGetAttro(self):
+ modifications = Modifications()
+ self.assertFalse(modifications.wasSetAttroCalled())
+ setattr(modifications, 'Foo', 'Bar')
+ self.assertTrue(modifications.wasSetAttroCalled())
+ self.assertEqual(getattr(modifications, 'Foo'), 'Bar')
+ self.assertTrue(modifications.wasGetAttroCalled())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/modified_constructor_test.py b/sources/shiboken6/tests/samplebinding/modified_constructor_test.py
new file mode 100644
index 000000000..9791a3491
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/modified_constructor_test.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests cases for ConstructorWithModifiedArgument class.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ModifiedConstructor
+
+
+class ConstructorWithModifiedArgumentTest(unittest.TestCase):
+ '''Test cases for ConstructorWithModifiedArgument class.'''
+
+ def testConstructorWithModifiedArgument(self):
+ sampleClass = ModifiedConstructor("10")
+ self.assertTrue(sampleClass.retrieveValue(), 10)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/modifiedvirtualmethods_test.py b/sources/shiboken6/tests/samplebinding/modifiedvirtualmethods_test.py
new file mode 100644
index 000000000..dcb487f1a
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/modifiedvirtualmethods_test.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for modified virtual methods.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import VirtualMethods, Str
+
+
+class ExtendedVirtualMethods(VirtualMethods):
+ def __init__(self):
+ VirtualMethods.__init__(self)
+ self.name_called = False
+ self.sum0_called = False
+ self.sum1_called = False
+ self.sum2_called = False
+ self.sum3_called = False
+ self.sum4_called = False
+ self.sumThree_called = False
+ self.callMe_called = 0
+ self.multiplier = 12345
+
+ def sum0(self, a0, a1, a2):
+ self.sum0_called = True
+ return VirtualMethods.sumThree(self, a0, a1, a2) * self.multiplier
+
+ def sumThree(self, a0, a1, a2):
+ self.sumThree_called = True
+ return VirtualMethods.sumThree(self, a0, a1, a2) * self.multiplier
+
+ def sum1(self, a0, a1, a2):
+ self.sum1_called = True
+ return VirtualMethods.sum1(self, a0, a1, a2) * self.multiplier
+
+ def sum2(self, a0, a1):
+ self.sum2_called = True
+ return VirtualMethods.sum2(self, a0, a1) * self.multiplier
+
+ def sum3(self, a0, a1):
+ self.sum3_called = True
+ return VirtualMethods.sum3(self, a0, a1) * self.multiplier
+
+ def sum4(self, a0, a1):
+ self.sum4_called = True
+ return VirtualMethods.sum4(self, a0, a1) * self.multiplier
+
+ def name(self):
+ self.name_called = True
+ return Str('ExtendedVirtualMethods')
+
+ def callMe(self):
+ self.callMe_called += 1
+
+ def getMargins(self):
+ return tuple([m * 2 for m in VirtualMethods.getMargins(self)])
+
+
+class VirtualMethodsTest(unittest.TestCase):
+ '''Test case for modified virtual methods.'''
+
+ def setUp(self):
+ self.vm = VirtualMethods()
+ self.evm = ExtendedVirtualMethods()
+
+ def tearDown(self):
+ del self.vm
+ del self.evm
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ def testModifiedVirtualMethod0(self):
+ '''Renamed virtual method.'''
+ a0, a1, a2 = 2, 3, 5
+ result0 = self.vm.callSum0(a0, a1, a2)
+ result1 = self.vm.sumThree(a0, a1, a2)
+ self.assertEqual(result0, a0 + a1 + a2)
+ self.assertEqual(result0, result1)
+ self.assertRaises(AttributeError, getattr, self.vm, 'sum0')
+
+ def testReimplementedModifiedVirtualMethod0(self):
+ '''Override of a renamed virtual method.'''
+ a0, a1, a2 = 2, 3, 5
+ result0 = self.vm.callSum0(a0, a1, a2)
+ result1 = self.vm.sumThree(a0, a1, a2)
+ result2 = self.evm.callSum0(a0, a1, a2)
+ self.assertEqual(result0, result1)
+ self.assertEqual(result0 * self.evm.multiplier, result2)
+ self.assertTrue(self.evm.sumThree_called)
+ self.assertFalse(self.evm.sum0_called)
+
+ def testModifiedVirtualMethod1(self):
+ '''Virtual method with three arguments and the last one
+ changed to have the default value set to 1000.'''
+ a0, a1, a2 = 2, 3, 5
+ result0 = self.vm.sum1(a0, a1)
+ self.assertEqual(result0, a0 + a1 + 1000)
+ result1 = self.vm.sum1(a0, a1, a2)
+ result2 = self.vm.callSum1(a0, a1, a2)
+ self.assertEqual(result1, result2)
+
+ def testReimplementedModifiedVirtualMethod1(self):
+ '''Override of the virtual method with three arguments and
+ the last one changed to have the default value set to 1000.'''
+ a0, a1 = 2, 3
+ result0 = self.vm.sum1(a0, a1)
+ result1 = self.evm.callSum1(a0, a1, 1000)
+ self.assertEqual(result0 * self.evm.multiplier, result1)
+ self.assertTrue(self.evm.sum1_called)
+
+ def testModifiedVirtualMethod2(self):
+ '''Virtual method originally with three arguments, the last
+ one was removed and the default value set to 2000.'''
+ a0, a1 = 1, 2
+ result0 = self.vm.sum2(a0, a1)
+ self.assertEqual(result0, a0 + a1 + 2000)
+ result1 = self.vm.sum2(a0, a1)
+ result2 = self.vm.callSum2(a0, a1, 2000)
+ self.assertEqual(result1, result2)
+ self.assertRaises(TypeError, self.vm.sum2, 1, 2, 3)
+
+ def testReimplementedModifiedVirtualMethod2(self):
+ '''Override of the virtual method originally with three arguments,
+ the last one was removed and the default value set to 2000.'''
+ a0, a1 = 1, 2
+ ignored = 54321
+ result0 = self.vm.sum2(a0, a1)
+ result1 = self.evm.callSum2(a0, a1, ignored)
+ self.assertEqual(result0 * self.evm.multiplier, result1)
+ self.assertTrue(self.evm.sum2_called)
+
+ def testModifiedVirtualMethod3(self):
+ '''Virtual method originally with three arguments have the second
+ one removed and replaced by custom code that replaces it by the sum
+ of the first and the last arguments.'''
+ a0, a1 = 1, 2
+ result0 = self.vm.sum3(a0, a1)
+ self.assertEqual(result0, a0 + (a0 + a1) + a1)
+ result1 = self.vm.callSum3(a0, 10, a1)
+ self.assertNotEqual(result0, result1)
+ result2 = self.vm.callSum3(a0, a0 + a1, a1)
+ self.assertEqual(result0, result2)
+ self.assertRaises(TypeError, self.vm.sum3, 1, 2, 3)
+
+ def testReimplementedModifiedVirtualMethod3(self):
+ '''Override of the virtual method originally with three arguments
+ have the second one removed and replaced by custom code that
+ replaces it by the sum of the first and the last arguments.'''
+ a0, a1 = 1, 2
+ ignored = 54321
+ result0 = self.vm.sum3(a0, a1)
+ result1 = self.evm.callSum3(a0, ignored, a1)
+ self.assertEqual(result0 * self.evm.multiplier, result1)
+ self.assertTrue(self.evm.sum3_called)
+
+ def testModifiedVirtualMethod4(self):
+ '''Virtual method originally with three arguments, the
+ last one was removed and the default value set to 3000.'''
+ a0, a1 = 1, 2
+ default_value = 3000
+ result0 = self.vm.sum4(a0, a1)
+ self.assertEqual(result0, a0 + default_value + a1)
+ removed_arg_value = 100
+ result1 = self.vm.callSum4(a0, removed_arg_value, a1)
+ self.assertEqual(result1, a0 + removed_arg_value + a1)
+ self.assertRaises(TypeError, self.vm.sum4, 1, 2, 3)
+
+ def testReimplementedModifiedVirtualMethod4(self):
+ '''Override of the virtual method originally with three arguments,
+ the last one was removed and the default value set to 3000.
+ The method was modified with code injection on the binding override
+ (the one that receives calls from C++ with the original signature
+ and forwards it to Python overrides) that subtracts the value of the
+ second argument (removed in Python) from the value of the first
+ before sending them to Python.'''
+ a0, a1 = 1, 2
+ removed_arg_value = 2011
+ default_value = 3000
+ result = self.evm.callSum4(a0, removed_arg_value, a1)
+ self.assertEqual(result,
+ (a0 - removed_arg_value + a1 + default_value) * self.evm.multiplier)
+ self.assertTrue(self.evm.sum4_called)
+
+ def testOverridenMethodResultModification(self):
+ '''Injected code modifies the result of a call to a virtual
+ method overridden in Python.'''
+ orig_name = self.vm.callName()
+ self.assertEqual(orig_name, 'VirtualMethods')
+ name = self.evm.callName()
+ self.assertEqual(name, 'PimpedExtendedVirtualMethods')
+ self.assertEqual(name, Str('PimpedExtendedVirtualMethods'))
+ self.assertTrue(self.evm.name_called)
+
+ def testInjectCodeCallsPythonVirtualMethodOverride(self):
+ '''When injected code calls the Python override by itself
+ no code for the method call should be generated.'''
+ self.evm.callCallMe()
+ self.assertEqual(self.evm.callMe_called, 1)
+
+ def testAllArgumentsRemoved(self):
+ values = (10, 20, 30, 40)
+ self.vm.setMargins(*values)
+ self.assertEqual(self.vm.getMargins(), values)
+
+ def testAllArgumentsRemovedCallVirtual(self):
+ values = (10, 20, 30, 40)
+ self.vm.setMargins(*values)
+ self.assertEqual(self.vm.callGetMargins(), values)
+
+ def testExtendedAllArgumentsRemoved(self):
+ values = (10, 20, 30, 40)
+ self.evm.setMargins(*values)
+ double = tuple([m * 2 for m in values])
+ self.assertEqual(self.evm.getMargins(), double)
+
+ def testExtendedAllArgumentsRemovedCallVirtual(self):
+ values = (10, 20, 30, 40)
+ self.evm.setMargins(*values)
+ double = tuple([m * 2 for m in values])
+ self.assertEqual(self.evm.callGetMargins(), double)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/multi_cpp_inheritance_test.py b/sources/shiboken6/tests/samplebinding/multi_cpp_inheritance_test.py
new file mode 100644
index 000000000..fc6b26c3f
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/multi_cpp_inheritance_test.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for multiple inheritance'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, Point, Str
+
+
+class SimpleUseCase(ObjectType, Str):
+ def __init__(self, name):
+ ObjectType.__init__(self)
+ Str.__init__(self, name)
+
+
+class SimpleUseCaseReverse(Str, ObjectType):
+ def __init__(self, name):
+ ObjectType.__init__(self)
+ Str.__init__(self, name)
+
+
+class SimpleUseCase2(SimpleUseCase):
+ def __init__(self, name):
+ SimpleUseCase.__init__(self, name)
+
+
+class ComplexUseCase(SimpleUseCase2, Point):
+ def __init__(self, name):
+ SimpleUseCase2.__init__(self, name)
+ Point.__init__(self)
+
+
+class ComplexUseCaseReverse(Point, SimpleUseCase2):
+ def __init__(self, name):
+ SimpleUseCase2.__init__(self, name)
+ Point.__init__(self)
+
+
+class MultipleCppDerivedTest(unittest.TestCase):
+ def testInstantiation(self):
+ s = SimpleUseCase("Hi")
+ self.assertEqual(s, "Hi")
+ s.setObjectName(s)
+ self.assertEqual(s.objectName(), "Hi")
+
+ def testInstantiation2(self):
+ s = SimpleUseCase2("Hi")
+ self.assertEqual(s, "Hi")
+ s.setObjectName(s)
+ self.assertEqual(s.objectName(), "Hi")
+
+ def testComplexInstantiation(self):
+ c = ComplexUseCase("Hi")
+ self.assertEqual(c, "Hi")
+ c.setObjectName(c)
+ self.assertEqual(c.objectName(), "Hi")
+ c.setX(2)
+ self.assertEqual(c.x(), 2)
+
+
+class MultipleCppDerivedReverseTest(unittest.TestCase):
+ def testInstantiation(self):
+ s = SimpleUseCaseReverse("Hi")
+ self.assertEqual(s, "Hi")
+ s.setObjectName(s)
+ self.assertEqual(s.objectName(), "Hi")
+
+ def testInstantiation2(self):
+ s = SimpleUseCase2("Hi")
+ self.assertEqual(s, "Hi")
+ s.setObjectName(s)
+ self.assertEqual(s.objectName(), "Hi")
+
+ def testComplexInstantiation(self):
+ # PYSIDE-1564: This test can no longer work because of this MRO:
+ # ('ComplexUseCaseReverse', 'Point', 'SimpleUseCase2', 'SimpleUseCase',
+ # 'ObjectType', 'Str', 'Object', 'object')
+ # By multiple inheritance Point would be called first but has no argument.
+ with self.assertRaises(TypeError):
+ c = ComplexUseCaseReverse("Hi") # noqa: F841
+ # c.setObjectName(c)
+ # self.assertEqual(c.objectName(), "Hi")
+ # c.setX(2);
+ # self.assertEqual(c, Point(2, 0))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/multiple_derived_test.py b/sources/shiboken6/tests/samplebinding/multiple_derived_test.py
new file mode 100644
index 000000000..7497714a8
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/multiple_derived_test.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for multiple inheritance'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Base1, Base2
+from sample import MDerived1, MDerived2, MDerived3, MDerived4, MDerived5, SonOfMDerived1
+
+
+class ExtMDerived1(MDerived1):
+ def __init__(self):
+ MDerived1.__init__(self)
+ self.multiplier = 20
+ self.base2Method_called = False
+
+ def base2Method(self):
+ return Base2.base2Method(self) * self.multiplier
+
+
+class MultipleDerivedTest(unittest.TestCase):
+ '''Test cases for multiple inheritance'''
+
+ def testIsInstance(self):
+ '''MDerived1 is instance of its parents Base1 and Base2.'''
+ a = MDerived1()
+ self.assertTrue(isinstance(a, MDerived1))
+ self.assertTrue(isinstance(a, Base1))
+ self.assertTrue(isinstance(a, Base2))
+
+ def testIsSubclass(self):
+ '''MDerived1 is subclass of its parents Base1 and Base2.'''
+ self.assertTrue(issubclass(MDerived1, Base1))
+ self.assertTrue(issubclass(MDerived1, Base2))
+
+ def testCallToFunctionWithBase1ArgumentThatCastsBackToMDerived1(self):
+ '''MDerived1 is passed as an Base1 argument to a method that returns
+ it casted back to MDerived1.'''
+ a = MDerived1()
+ b = MDerived1.transformFromBase1(a)
+ self.assertEqual(a, b)
+
+ def testCallToFunctionWithBase2ArgumentThatCastsBackToMDerived1(self):
+ '''MDerived1 is passed as an Base2 argument to a method that returns
+ it casted back to MDerived1.'''
+ a = MDerived1()
+ b = MDerived1.transformFromBase2(a)
+ self.assertEqual(a, b)
+
+ def testPythonClassIsInstance(self):
+ '''Python defined class ExtMDerived1 is instance of its parents
+ MDerived1, Base1 and Base2.'''
+ a = ExtMDerived1()
+ self.assertTrue(isinstance(a, ExtMDerived1))
+ self.assertTrue(isinstance(a, MDerived1))
+ self.assertTrue(isinstance(a, Base1))
+ self.assertTrue(isinstance(a, Base2))
+
+ def testPythonClassIsSubclass(self):
+ '''Python defined class ExtMDerived1 is subclass of its parents
+ MDerived1, Base1 and Base2.'''
+ self.assertTrue(issubclass(ExtMDerived1, MDerived1))
+ self.assertTrue(issubclass(ExtMDerived1, Base1))
+ self.assertTrue(issubclass(ExtMDerived1, Base2))
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testCastFromMDerived1ToBases(self):
+ '''MDerived1 is casted by C++ to its parents and the binding must return the
+ MDerived1 wrapper.'''
+ a = MDerived1()
+ refcnt = sys.getrefcount(a)
+ b1 = a.castToBase1()
+ b2 = a.castToBase2()
+ self.assertTrue(isinstance(b1, MDerived1))
+ self.assertTrue(isinstance(b2, MDerived1))
+ self.assertEqual(a, b1)
+ self.assertEqual(a, b2)
+ self.assertEqual(sys.getrefcount(a), refcnt + 2)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testCastFromExtMDerived1ToMDerived1Bases(self):
+ '''Python defined class ExtMDerived1 is casted by C++ to MDerived1 parents
+ and the binding must return the correct ExtMDerived1 instance.'''
+ a = ExtMDerived1()
+ refcnt = sys.getrefcount(a)
+ b1 = a.castToBase1()
+ self.assertTrue(isinstance(b1, MDerived1))
+ self.assertTrue(isinstance(b1, ExtMDerived1))
+ b2 = a.castToBase2()
+ self.assertTrue(isinstance(b2, MDerived1))
+ self.assertTrue(isinstance(b2, ExtMDerived1))
+ self.assertEqual(a, b1)
+ self.assertEqual(a, b2)
+ self.assertEqual(sys.getrefcount(a), refcnt + 2)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testCastFromSonOfMDerived1ToBases(self):
+ '''SonOfMDerived1 is casted by C++ to its parents and the binding must return
+ the SonOfMDerived1 wrapper.'''
+ a = SonOfMDerived1()
+ refcnt = sys.getrefcount(a)
+ md1 = a.castToMDerived1()
+ b1 = a.castToBase1()
+ b2 = a.castToBase2()
+ self.assertTrue(isinstance(md1, SonOfMDerived1))
+ self.assertTrue(isinstance(b2, SonOfMDerived1))
+ self.assertTrue(isinstance(b2, SonOfMDerived1))
+ self.assertEqual(a, md1)
+ self.assertEqual(a, b1)
+ self.assertEqual(a, b2)
+ self.assertEqual(sys.getrefcount(a), refcnt + 3)
+
+ def testReimplementedBase2VirtualMethodOnClassInheritingFromMDerived1(self):
+ a = ExtMDerived1()
+ value = a.base2Method()
+ self.assertTrue(value, Base2.base2Method(a) * a.multiplier)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testCastFromMDerived2ToBases(self):
+ '''MDerived2 is casted by C++ to its parents and the binding must
+ return the MDerived2 wrapper.'''
+ a = MDerived2()
+ refcnt = sys.getrefcount(a)
+ b3 = a.castToBase3()
+ b4 = a.castToBase4()
+ b5 = a.castToBase5()
+ b6 = a.castToBase6()
+ self.assertTrue(isinstance(b3, MDerived2))
+ self.assertTrue(isinstance(b4, MDerived2))
+ self.assertTrue(isinstance(b5, MDerived2))
+ self.assertTrue(isinstance(b6, MDerived2))
+ self.assertEqual(a, b3)
+ self.assertEqual(a, b4)
+ self.assertEqual(a, b5)
+ self.assertEqual(a, b6)
+ self.assertEqual(sys.getrefcount(a), refcnt + 4)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testCastFromMDerived3ToBases(self):
+ '''MDerived3 is casted by C++ to its parents and the binding must
+ return the MDerived3 wrapper.'''
+ a = MDerived3()
+ refcnt = sys.getrefcount(a)
+ md1 = a.castToMDerived1()
+ md2 = a.castToMDerived2()
+ b1 = a.castToBase1()
+ b2 = a.castToBase2()
+ b3 = a.castToBase3()
+ b4 = a.castToBase4()
+ b5 = a.castToBase5()
+ b6 = a.castToBase6()
+ self.assertTrue(isinstance(md1, MDerived3))
+ self.assertTrue(isinstance(md2, MDerived3))
+ self.assertTrue(isinstance(b1, MDerived3))
+ self.assertTrue(isinstance(b2, MDerived3))
+ self.assertTrue(isinstance(b3, MDerived3))
+ self.assertTrue(isinstance(b4, MDerived3))
+ self.assertTrue(isinstance(b5, MDerived3))
+ self.assertTrue(isinstance(b6, MDerived3))
+ self.assertEqual(a, md1)
+ self.assertEqual(a, md2)
+ self.assertEqual(a, b1)
+ self.assertEqual(a, b2)
+ self.assertEqual(a, b3)
+ self.assertEqual(a, b4)
+ self.assertEqual(a, b5)
+ self.assertEqual(a, b6)
+ self.assertEqual(sys.getrefcount(a), refcnt + 8)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testCastFromMDerived4ToBases(self):
+ '''MDerived4 is casted by C++ to its parents and the binding must
+ return the MDerived4 wrapper.'''
+ a = MDerived4()
+ refcnt = sys.getrefcount(a)
+ b3 = a.castToBase3()
+ b4 = a.castToBase4()
+ self.assertTrue(isinstance(b3, MDerived4))
+ self.assertTrue(isinstance(b4, MDerived4))
+ self.assertEqual(a, b3)
+ self.assertEqual(a, b4)
+ self.assertEqual(sys.getrefcount(a), refcnt + 2)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testCastFromMDerived5ToBases(self):
+ '''MDerived5 is casted by C++ to its parents and the binding must
+ return the MDerived5 wrapper.'''
+ a = MDerived5()
+ refcnt = sys.getrefcount(a)
+ b3 = a.castToBase3()
+ b4 = a.castToBase4()
+ self.assertTrue(isinstance(b3, MDerived5))
+ self.assertTrue(isinstance(b4, MDerived5))
+ self.assertEqual(a, b3)
+ self.assertEqual(a, b4)
+ self.assertEqual(sys.getrefcount(a), refcnt + 2)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testCastFromMDerived3ToBase3(self):
+ '''MDerived3 is casted by C++ to Base3 grandparent using both the inherited
+ and reimplement castToBase3 methods.'''
+ a = MDerived3()
+ refcnt = sys.getrefcount(a)
+ b3_reimplemented = a.castToBase3()
+ b3_inherited = MDerived2.castToBase3(a)
+ self.assertTrue(isinstance(b3_reimplemented, MDerived3))
+ self.assertTrue(isinstance(b3_inherited, MDerived3))
+ self.assertEqual(a, b3_reimplemented)
+ self.assertEqual(a, b3_inherited)
+ self.assertEqual(sys.getrefcount(a), refcnt + 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/namespace_test.py b/sources/shiboken6/tests/samplebinding/namespace_test.py
new file mode 100644
index 000000000..64a6792ac
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/namespace_test.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for std::map container conversions'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import SampleNamespace
+from shiboken_test_helper import objectFullname
+
+from shibokensupport.signature import get_signature
+
+# For tests of invisible namespaces, see
+# enumfromremovednamespace_test.py / removednamespaces.h
+
+
+class TestVariablesUnderNamespace(unittest.TestCase):
+ def testIt(self):
+ self.assertEqual(SampleNamespace.variableInNamespace, 42)
+
+
+class TestClassesUnderNamespace(unittest.TestCase):
+ def testIt(self):
+ c1 = SampleNamespace.SomeClass() # noqa F841
+ e1 = SampleNamespace.SomeClass.ProtectedEnum() # noqa F841
+ c2 = SampleNamespace.SomeClass.SomeInnerClass() # noqa F841
+ e2 = SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum() # noqa F841
+ c3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough() # noqa F841
+ e3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum(0) # noqa F841
+
+ def testFunctionAddedOnNamespace(self):
+ res = SampleNamespace.ImInsideANamespace(2, 2)
+ self.assertEqual(res, 4)
+
+ def testTpNames(self):
+ self.assertEqual(str(SampleNamespace.SomeClass),
+ "<class 'sample.SampleNamespace.SomeClass'>")
+ self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum),
+ "<enum 'ProtectedEnum'>")
+ self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum),
+ "<enum 'ProtectedEnum'>")
+ self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough),
+ "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>") # noqa: E501
+ self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), # noqa: E501
+ "<enum 'NiceEnum'>")
+
+ # Test if enum inside of class is correct represented
+ an = objectFullname(get_signature(SampleNamespace.enumInEnumOut).parameters['in_'].annotation) # noqa: E501
+ self.assertEqual(an, "sample.SampleNamespace.InValue")
+ an = objectFullname(get_signature(SampleNamespace.enumAsInt).parameters['value'].annotation)
+ self.assertEqual(an, "sample.SampleNamespace.SomeClass.PublicScopedEnum")
+
+ def testInlineNamespaces(self):
+ cls = SampleNamespace.ClassWithinInlineNamespace()
+ cls.setValue(SampleNamespace.EWIN_Value1)
+ self.assertEqual(cls.value(), SampleNamespace.EWIN_Value1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/newdivision_test.py b/sources/shiboken6/tests/samplebinding/newdivision_test.py
new file mode 100644
index 000000000..0e7dfbee1
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/newdivision_test.py
@@ -0,0 +1,25 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point
+
+
+class TestNewDivision(unittest.TestCase):
+
+ def testIt(self):
+ p = Point(4, 4)
+ p2 = p / 2
+ self.assertEqual(p2, Point(2, 2))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/nondefaultctor_test.py b/sources/shiboken6/tests/samplebinding/nondefaultctor_test.py
new file mode 100644
index 000000000..bc8d29e50
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/nondefaultctor_test.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for ...'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import NonDefaultCtor
+
+
+class DerivedNonDefaultCtor (NonDefaultCtor):
+ def returnMyselfVirtual(self):
+ return NonDefaultCtor(self.value() + 1)
+
+
+class AnotherDerivedNonDefaultCtor (NonDefaultCtor):
+ def __init__(self, some_string):
+ pass
+
+
+class NonDefaultCtorTest(unittest.TestCase):
+
+ def testNonDefaultCtor(self):
+ c = NonDefaultCtor(2)
+ # these functions returns NonDefaultCtor by value, so a PyObjecy is created every time
+ self.assertNotEqual(c.returnMyself(), c)
+ self.assertEqual(c.returnMyself().value(), 2)
+ self.assertNotEqual(c.returnMyself(3), c)
+ self.assertEqual(c.returnMyself(3).value(), 2)
+ self.assertNotEqual(c.returnMyself(4, c), c)
+ self.assertEqual(c.returnMyself(4, c).value(), 2)
+
+ def testVirtuals(self):
+ c = DerivedNonDefaultCtor(3)
+ # these functions returns NonDefaultCtor by value, so a PyObjecy is created every time
+ self.assertNotEqual(c.returnMyselfVirtual(), c)
+ self.assertEqual(c.returnMyselfVirtual().value(), 4)
+ self.assertEqual(c.callReturnMyselfVirtual().value(), 4)
+
+ def testCtorOverload(self):
+ c = AnotherDerivedNonDefaultCtor("testing") # noqa: F841
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/nontypetemplate_test.py b/sources/shiboken6/tests/samplebinding/nontypetemplate_test.py
new file mode 100644
index 000000000..a10547728
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/nontypetemplate_test.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+hasNumPy = False
+
+try:
+ import numpy
+ hasNumPy = True
+except ImportError:
+ pass
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import IntArray2, IntArray3
+
+
+class NonTypeTemplateTest(unittest.TestCase):
+
+ def testNonTypeTemplate(self):
+ array2 = IntArray2(3)
+ self.assertEqual(array2.sum(), 6)
+ array3 = IntArray3(5)
+ self.assertEqual(array3.sum(), 15)
+
+ def testArrayInitializer(self):
+ if not hasNumPy:
+ return
+ array3 = IntArray3(numpy.array([1, 2, 3], dtype='int32'))
+ self.assertEqual(array3.sum(), 6)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/nonzero_test.py b/sources/shiboken6/tests/samplebinding/nonzero_test.py
new file mode 100644
index 000000000..7be239fc4
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/nonzero_test.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Color, Brush
+
+
+class TestNonZeroOperator(unittest.TestCase):
+ def testColor(self):
+ """Color has a Qt-style isNull()"""
+ c = Color()
+ self.assertFalse(c)
+ c = Color(2)
+ self.assertTrue(c)
+
+ def testBrush(self):
+ """Brush enables its operator bool in the typesystem XML"""
+ b = Brush()
+ self.assertFalse(b)
+ b = Brush(Color(2))
+ self.assertTrue(b)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/numericaltypedef_test.py b/sources/shiboken6/tests/samplebinding/numericaltypedef_test.py
new file mode 100644
index 000000000..f714a4fc8
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/numericaltypedef_test.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import SizeF
+
+
+class NumericalTypedefTest(unittest.TestCase):
+
+ def testNumericalTypedefExact(self):
+ width, height = (1.1, 2.2)
+ size = SizeF(width, height)
+ self.assertEqual(size.width(), width)
+ self.assertEqual(size.height(), height)
+
+ def testNumericalTypedefConvertible(self):
+ width, height = (1, 2)
+ size = SizeF(width, height)
+ self.assertEqual(size.width(), float(width))
+ self.assertEqual(size.height(), float(height))
+
+ def testNumericalTypedefOfUnsignedShort(self):
+ self.assertEqual(SizeF.passTypedefOfUnsignedShort(123), 123)
+ self.assertEqual(SizeF.passTypedefOfUnsignedShort(321), 321)
+ self.assertNotEqual(SizeF.passTypedefOfUnsignedShort(123), 0)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/numpy_test.py b/sources/shiboken6/tests/samplebinding/numpy_test.py
new file mode 100644
index 000000000..42094a463
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/numpy_test.py
@@ -0,0 +1,41 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import sys
+
+try:
+ import sysconfig
+ if bool(sysconfig.get_config_var('Py_DEBUG')):
+ sys.exit(0)
+ import numpy
+except: # noqa: E722
+ sys.exit(0)
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import PointF
+
+
+class TestNumpyTypes(unittest.TestCase):
+
+ def testNumpyConverted(self):
+ x, y = (0.1, 0.2)
+ p = PointF(float(numpy.float32(x)), float(numpy.float32(y)))
+ self.assertAlmostEqual(p.x(), x)
+ self.assertAlmostEqual(p.y(), y)
+
+ def testNumpyAsIs(self):
+ x, y = (0.1, 0.2)
+ p = PointF(numpy.float32(x), numpy.float32(y))
+ self.assertAlmostEqual(p.x(), x)
+ self.assertAlmostEqual(p.y(), y)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/objecttype_test.py b/sources/shiboken6/tests/samplebinding/objecttype_test.py
new file mode 100644
index 000000000..ead68ba13
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/objecttype_test.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests ObjectType class of object-type with privates copy constructor and = operator.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+import sys
+
+from sample import ObjectType, Str
+from shiboken6 import Shiboken
+
+
+class ObjectTypeTest(unittest.TestCase):
+ '''Test cases ObjectType class of object-type with privates copy constructor and = operator.'''
+
+ def testObjectTypeSetObjectNameWithStrVariable(self):
+ '''ObjectType.setObjectName with Str variable as argument.'''
+ s = Str('object name')
+ o = ObjectType()
+ o.setObjectName(s)
+ self.assertEqual(str(o.objectName()), str(s))
+
+ def testObjectTypeSetObjectNameWithStrInstantiation(self):
+ '''ObjectType.setObjectName with Str instantiation as argument.'''
+ s = 'object name'
+ o = ObjectType()
+ o.setObjectName(Str(s))
+ self.assertEqual(str(o.objectName()), s)
+
+ def testObjectTypeSetObjectNameWithPythonString(self):
+ '''ObjectType.setObjectName with Python string as argument.'''
+ o = ObjectType()
+ o.setObjectName('object name')
+ self.assertEqual(str(o.objectName()), 'object name')
+
+ def testNullOverload(self):
+ o = ObjectType()
+ o.setObject(None)
+ self.assertEqual(o.callId(), 0)
+ o.setNullObject(None)
+ self.assertEqual(o.callId(), 1)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testParentFromCpp(self):
+ o = ObjectType()
+ self.assertEqual(sys.getrefcount(o), 2)
+ o.getCppParent().setObjectName('parent')
+ self.assertEqual(sys.getrefcount(o), 3)
+ o.getCppParent().setObjectName('parent')
+ self.assertEqual(sys.getrefcount(o), 3)
+ o.getCppParent().setObjectName('parent')
+ self.assertEqual(sys.getrefcount(o), 3)
+ o.getCppParent().setObjectName('parent')
+ self.assertEqual(sys.getrefcount(o), 3)
+ o.getCppParent().setObjectName('parent')
+ self.assertEqual(sys.getrefcount(o), 3)
+ o.destroyCppParent()
+ self.assertEqual(sys.getrefcount(o), 2)
+
+ def testNextInFocusChainCycle(self):
+ parent = ObjectType()
+ child = ObjectType(parent)
+ next_focus = child.nextInFocusChain() # noqa: F841
+
+ Shiboken.invalidate(parent)
+
+ def testNextInFocusChainCycleList(self):
+ '''As above but in for a list of objects'''
+ parents = []
+ children = []
+ focus_chains = []
+ for i in range(10):
+ parent = ObjectType()
+ child = ObjectType(parent)
+ next_focus = child.nextInFocusChain()
+ parents.append(parent)
+ children.append(child)
+ focus_chains.append(next_focus)
+
+ Shiboken.invalidate(parents)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testClassDecref(self):
+ # Bug was that class PyTypeObject wasn't decrefed when instance died
+ before = sys.getrefcount(ObjectType)
+
+ for i in range(1000):
+ obj = ObjectType()
+ Shiboken.delete(obj)
+
+ after = sys.getrefcount(ObjectType)
+
+ self.assertLess(abs(before - after), 5)
+
+ def testInvalidProperty(self):
+ o = ObjectType()
+ with self.assertRaises(AttributeError):
+ o.typo
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/objecttype_with_named_args_test.py b/sources/shiboken6/tests/samplebinding/objecttype_with_named_args_test.py
new file mode 100644
index 000000000..285e2313b
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/objecttype_with_named_args_test.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class NamedArgsTest(unittest.TestCase):
+
+ def testOneArgument(self):
+ p = ObjectType()
+ o = ObjectType(parent=p)
+ self.assertEqual(o.parent(), p)
+
+ def testMoreArguments(self):
+ o = ObjectType()
+
+ o.setObjectSplittedName("", prefix="pys", suffix="ide")
+ self.assertEqual(o.objectName(), "pyside")
+
+ o.setObjectSplittedName("", suffix="ide", prefix="pys")
+ self.assertEqual(o.objectName(), "pyside")
+
+ o.setObjectNameWithSize(name="pyside", size=6)
+ self.assertEqual(o.objectName(), "pyside")
+
+ o.setObjectNameWithSize(size=6, name="pyside")
+ self.assertEqual(o.objectName(), "pyside")
+
+ def testUseDefaultValues(self):
+ o = ObjectType()
+
+ o.setObjectNameWithSize(size=3)
+ self.assertEqual(o.objectName(), "<un") # use name='unknown' default argument
+
+ o.setObjectSplittedName("")
+ self.assertEqual(o.objectName(), "<unknown>") # user prefix='<unk' and suffix='nown>'
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/objecttypebyvalue_test.py b/sources/shiboken6/tests/samplebinding/objecttypebyvalue_test.py
new file mode 100644
index 000000000..8f74af3ab
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/objecttypebyvalue_test.py
@@ -0,0 +1,27 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectTypeByValue
+
+
+class ObjectTypeByValueTest (unittest.TestCase):
+ def testIt(self):
+ factory = ObjectTypeByValue()
+ obj = factory.returnSomeKindOfMe()
+ # This should crash!
+ obj.prop.protectedValueTypeProperty.setX(1.0)
+ # just to make sure it will segfault
+ obj.prop.protectedValueTypeProperty.setY(2.0)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/objecttypelayout_test.py b/sources/shiboken6/tests/samplebinding/objecttypelayout_test.py
new file mode 100644
index 000000000..677b89281
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/objecttypelayout_test.py
@@ -0,0 +1,301 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests cases for ObjectTypeLayout class.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, ObjectTypeLayout
+
+
+class ObjectTypeLayoutTest(unittest.TestCase):
+ '''Test cases for ObjectTypeLayout class.'''
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testOwnershipOverride(self):
+ lt = ObjectTypeLayout()
+
+ o1 = ObjectType(lt)
+ o1.setObjectName('o1')
+
+ self.assertEqual(sys.getrefcount(o1), 3)
+ lt.takeChild('o1')
+ self.assertEqual(sys.getrefcount(o1), 2)
+
+ def testSetNullLayout(self):
+ '''ObjectType.setLayout(0).'''
+ o2 = ObjectType()
+ o2.setLayout(None)
+
+ def testSetNullLayoutToObjectTypeCreatedInCpp(self):
+ '''ObjectType.setLayout(0) to object created in C++.'''
+ o1 = ObjectType.create()
+ o1.setLayout(None)
+
+ def testObjectTypeLayout(self):
+ '''ObjectType.setLayout.'''
+ p1 = ObjectType()
+ c1 = ObjectType()
+ c2 = ObjectType()
+ c3 = ObjectType()
+ layout = ObjectTypeLayout()
+ layout.addObject(c1)
+ layout.addObject(c2)
+ layout.addObject(c3)
+ self.assertEqual(c1.parent(), None)
+ self.assertEqual(c2.parent(), None)
+ self.assertEqual(c3.parent(), None)
+
+ p1.setLayout(layout)
+ del p1 # This must kill c1, c2 and c3
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ self.assertRaises(RuntimeError, c1.objectName)
+ self.assertRaises(RuntimeError, c2.objectName)
+ self.assertRaises(RuntimeError, c3.objectName)
+ self.assertRaises(RuntimeError, layout.objectName)
+
+ def testObjectTypeLayoutWithObjectsCreatedInCpp(self):
+ '''ObjectType.setLayout with objects created in C++.'''
+ p1 = ObjectType.create()
+ c1 = ObjectType.create()
+ c2 = ObjectType.create()
+ c3 = ObjectType.create()
+ layout = ObjectTypeLayout()
+ layout.addObject(c1)
+ layout.addObject(c2)
+ layout.addObject(c3)
+ self.assertEqual(c1.parent(), None)
+ self.assertEqual(c2.parent(), None)
+ self.assertEqual(c3.parent(), None)
+
+ p1.setLayout(layout)
+ del p1 # This must kill c1, c2 and c3
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ self.assertRaises(RuntimeError, c1.objectName)
+ self.assertRaises(RuntimeError, c2.objectName)
+ self.assertRaises(RuntimeError, c3.objectName)
+ self.assertRaises(RuntimeError, layout.objectName)
+
+ def testObjectTypeLayoutTransference(self):
+ '''Transfer a layout from one ObjectType to another, so that all the items in
+ the layout get reparented.'''
+ p1 = ObjectType()
+ p2 = ObjectType()
+ c1 = ObjectType()
+ c2 = ObjectType()
+
+ layout = ObjectTypeLayout()
+ layout.addObject(c1)
+ layout.addObject(c2)
+
+ p1.setLayout(layout)
+
+ self.assertEqual(len(p2.children()), 0)
+ self.assertEqual(c1.parent(), p1)
+ self.assertEqual(c2.parent(), p1)
+ self.assertEqual(set(p1.children()), set([c1, c2, layout]))
+
+ p2.setLayout(layout)
+
+ self.assertEqual(len(p1.children()), 0)
+ self.assertEqual(c1.parent(), p2)
+ self.assertEqual(c2.parent(), p2)
+ self.assertEqual(set(p2.children()), set([c1, c2, layout]))
+
+ def testObjectTypeLayoutInsideAnotherLayout(self):
+ '''Adds one ObjectTypeLayout to another and sets the parent to an ObjectType.'''
+ p1 = ObjectType()
+
+ l1 = ObjectTypeLayout()
+ c1 = ObjectType()
+ l1.addObject(c1)
+ c2 = ObjectType()
+ l1.addObject(c2)
+
+ l2 = ObjectTypeLayout()
+ c3 = ObjectType()
+ l2.addObject(c3)
+ c4 = ObjectType()
+ l2.addObject(c4)
+
+ l1.addObject(l2)
+
+ p1.setLayout(l1)
+
+ self.assertEqual(c1.parent(), p1)
+ self.assertEqual(c2.parent(), p1)
+ self.assertEqual(c3.parent(), p1)
+ self.assertEqual(c4.parent(), p1)
+ self.assertEqual(l1.parent(), p1)
+ self.assertEqual(l2.parent(), l1)
+
+ del p1
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ self.assertRaises(RuntimeError, c1.objectName)
+ self.assertRaises(RuntimeError, c2.objectName)
+ self.assertRaises(RuntimeError, c3.objectName)
+ self.assertRaises(RuntimeError, c4.objectName)
+ self.assertRaises(RuntimeError, l1.objectName)
+ self.assertRaises(RuntimeError, l2.objectName)
+
+ def testObjectTypeLayoutInsideAnotherLayoutAndEveryoneCreatedInCpp(self):
+ '''Adds one ObjectTypeLayout to another and sets the parent to an ObjectType.
+ All the objects are created in C++.'''
+ p1 = ObjectType.create()
+
+ l1 = ObjectTypeLayout.create()
+ c1 = ObjectType.create()
+ l1.addObject(c1)
+ c2 = ObjectType.create()
+ l1.addObject(c2)
+
+ l2 = ObjectTypeLayout.create()
+ c3 = ObjectType.create()
+ l2.addObject(c3)
+ c4 = ObjectType.create()
+ l2.addObject(c4)
+
+ l1.addObject(l2)
+
+ p1.setLayout(l1)
+
+ self.assertEqual(c1.parent(), p1)
+ self.assertEqual(c2.parent(), p1)
+ self.assertEqual(c3.parent(), p1)
+ self.assertEqual(c4.parent(), p1)
+ self.assertEqual(l1.parent(), p1)
+ self.assertEqual(l2.parent(), l1)
+
+ del p1
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ self.assertRaises(RuntimeError, c1.objectName)
+ self.assertRaises(RuntimeError, c2.objectName)
+ self.assertRaises(RuntimeError, c3.objectName)
+ self.assertRaises(RuntimeError, c4.objectName)
+ self.assertRaises(RuntimeError, l1.objectName)
+ self.assertRaises(RuntimeError, l2.objectName)
+
+ def testTransferNestedLayoutsBetweenObjects(self):
+ '''Adds one ObjectTypeLayout to another, sets the parent to an ObjectType
+ and then transfer it to another object.'''
+ p1 = ObjectType()
+ p2 = ObjectType()
+
+ l1 = ObjectTypeLayout()
+ c1 = ObjectType()
+ l1.addObject(c1)
+ c2 = ObjectType()
+ l1.addObject(c2)
+
+ l2 = ObjectTypeLayout()
+ c3 = ObjectType()
+ l2.addObject(c3)
+ c4 = ObjectType()
+ l2.addObject(c4)
+
+ l1.addObject(l2)
+
+ p1.setLayout(l1)
+
+ self.assertEqual(c1.parent(), p1)
+ self.assertEqual(c2.parent(), p1)
+ self.assertEqual(c3.parent(), p1)
+ self.assertEqual(c4.parent(), p1)
+ self.assertEqual(l1.parent(), p1)
+ self.assertEqual(l2.parent(), l1)
+
+ p2.setLayout(l1)
+ del p1
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ self.assertEqual(c1.parent(), p2)
+ self.assertEqual(c2.parent(), p2)
+ self.assertEqual(c3.parent(), p2)
+ self.assertEqual(c4.parent(), p2)
+ self.assertEqual(l1.parent(), p2)
+ self.assertEqual(l2.parent(), l1)
+
+ del p2
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ self.assertRaises(RuntimeError, c1.objectName)
+ self.assertRaises(RuntimeError, c2.objectName)
+ self.assertRaises(RuntimeError, c3.objectName)
+ self.assertRaises(RuntimeError, c4.objectName)
+ self.assertRaises(RuntimeError, l1.objectName)
+ self.assertRaises(RuntimeError, l2.objectName)
+
+ def testTransferNestedLayoutsBetweenObjectsAndEveryoneCreatedInCpp(self):
+ '''Adds one ObjectTypeLayout to another, sets the parent to an ObjectType and then
+ transfer it to another object. All the objects are created in C++.'''
+ p1 = ObjectType.create()
+ p2 = ObjectType.create()
+
+ l1 = ObjectTypeLayout.create()
+ c1 = ObjectType.create()
+ l1.addObject(c1)
+ c2 = ObjectType.create()
+ l1.addObject(c2)
+
+ l2 = ObjectTypeLayout.create()
+ c3 = ObjectType.create()
+ l2.addObject(c3)
+ c4 = ObjectType.create()
+ l2.addObject(c4)
+
+ l1.addObject(l2)
+
+ p1.setLayout(l1)
+
+ self.assertEqual(c1.parent(), p1)
+ self.assertEqual(c2.parent(), p1)
+ self.assertEqual(c3.parent(), p1)
+ self.assertEqual(c4.parent(), p1)
+ self.assertEqual(l1.parent(), p1)
+ self.assertEqual(l2.parent(), l1)
+
+ p2.setLayout(l1)
+ del p1
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ self.assertEqual(c1.parent(), p2)
+ self.assertEqual(c2.parent(), p2)
+ self.assertEqual(c3.parent(), p2)
+ self.assertEqual(c4.parent(), p2)
+ self.assertEqual(l1.parent(), p2)
+ self.assertEqual(l2.parent(), l1)
+
+ del p2
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ self.assertRaises(RuntimeError, c1.objectName)
+ self.assertRaises(RuntimeError, c2.objectName)
+ self.assertRaises(RuntimeError, c3.objectName)
+ self.assertRaises(RuntimeError, c4.objectName)
+ self.assertRaises(RuntimeError, l1.objectName)
+ self.assertRaises(RuntimeError, l2.objectName)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/objecttypeoperators_test.py b/sources/shiboken6/tests/samplebinding/objecttypeoperators_test.py
new file mode 100644
index 000000000..ceeee6c8d
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/objecttypeoperators_test.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import ObjectTypeOperators
+
+
+class ObjectTypeOperatorsTest(unittest.TestCase):
+
+ def testIt(self):
+ a = ObjectTypeOperators("a")
+ b = ObjectTypeOperators("b")
+ self.assertFalse(a == b)
+ self.assertEqual(a, a < b)
+
+ # this should change a.key() and return nothing.
+ self.assertEqual(None, a > b)
+ self.assertEqual(a.key(), "aoperator>")
+
+ def testPointerOpeators(self):
+ a = ObjectTypeOperators("a")
+ b = ObjectTypeOperators("b") # noqa: F841
+ self.assertEqual(a + "bc", "abc")
+ self.assertEqual("bc" + a, "bca")
+ self.assertEqual("a", a)
+ self.assertEqual(a, "a")
+
+ def testOperatorInjection(self):
+ a = ObjectTypeOperators("a")
+ self.assertNotEqual(a, "b")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py b/sources/shiboken6/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py
new file mode 100644
index 000000000..5fa6f824e
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import ObjectTypeHolder
+
+
+class TestObjectTypeReferenceAsVirtualMethodArgument(unittest.TestCase):
+
+ def testBasic(self):
+ holder = ObjectTypeHolder('TheObjectFromC++')
+ self.assertEqual(holder.callPassObjectTypeAsReference(), 'TheObjectFromC++')
+
+ def testExtended(self):
+ class Holder(ObjectTypeHolder):
+ def passObjectTypeAsReference(self, objectType):
+ return objectType.objectName().prepend(('ThisIs'))
+ holder = Holder('TheObjectFromC++')
+ self.assertEqual(holder.callPassObjectTypeAsReference(), 'ThisIsTheObjectFromC++')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/oddbool_test.py b/sources/shiboken6/tests/samplebinding/oddbool_test.py
new file mode 100644
index 000000000..87a8cdb1f
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/oddbool_test.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for OddBool user's primitive type conversion.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import OddBoolUser, ComparisonTester, SpaceshipComparisonTester
+
+
+class DerivedOddBoolUser (OddBoolUser):
+ def returnMyselfVirtual(self):
+ return OddBoolUser()
+ pass
+
+
+class OddBoolTest(unittest.TestCase):
+
+ def testOddBoolUser(self):
+ obuTrue = OddBoolUser()
+ obuFalse = OddBoolUser()
+ obuTrue.setOddBool(True)
+ self.assertEqual(obuFalse.oddBool(), False)
+ self.assertEqual(obuTrue.oddBool(), True)
+ self.assertEqual(obuTrue.callInvertedOddBool(), False)
+
+ self.assertTrue(obuTrue.oddBool())
+ self.assertFalse(obuFalse.oddBool())
+ self.assertTrue(obuTrue.oddBool() != obuFalse.oddBool())
+
+ self.assertFalse(obuFalse.oddBool())
+ self.assertFalse(obuFalse.oddBool())
+ self.assertTrue(obuTrue.oddBool() != obuFalse.oddBool())
+
+ def testVirtuals(self):
+ dobu = DerivedOddBoolUser()
+ self.assertEqual(dobu.invertedOddBool(), True)
+
+ def testImplicitConversionWithUsersPrimitiveType(self):
+ obu = OddBoolUser(True)
+ self.assertTrue(obu.oddBool())
+ obu = OddBoolUser(False)
+ self.assertFalse(obu.oddBool())
+ cpx = complex(1.0, 0.0)
+ obu = OddBoolUser(cpx)
+ self.assertTrue(obu.oddBool())
+ cpx = complex(0.0, 0.0)
+ obu = OddBoolUser(cpx)
+ self.assertFalse(obu.oddBool())
+
+ def testOddOperators(self):
+ t1 = ComparisonTester(42)
+ t2 = ComparisonTester(42)
+ self.assertEqual(t1, t2)
+
+ def testSpaceshipOperator(self):
+ if not SpaceshipComparisonTester.HasSpaceshipOperator:
+ print("Skipping Spaceship Operator test")
+ return
+ t1 = SpaceshipComparisonTester(42)
+ t2 = SpaceshipComparisonTester(42)
+ self.assertEqual(t1, t2)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t1 >= t2)
+ t2 = SpaceshipComparisonTester(43)
+ self.assertTrue(t1 < t2)
+ self.assertFalse(t1 > t2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/onlycopyclass_test.py b/sources/shiboken6/tests/samplebinding/onlycopyclass_test.py
new file mode 100644
index 000000000..bcb154c52
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/onlycopyclass_test.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import OnlyCopy, FriendOfOnlyCopy
+
+
+class ClassWithOnlyCopyCtorTest(unittest.TestCase):
+ def testGetOne(self):
+ obj = FriendOfOnlyCopy.createOnlyCopy(123)
+ self.assertEqual(type(obj), OnlyCopy)
+ self.assertEqual(obj.value(), 123)
+
+ def testGetMany(self):
+ objs = FriendOfOnlyCopy.createListOfOnlyCopy(3)
+ self.assertEqual(type(objs), list)
+ self.assertEqual(len(objs), 3)
+ for value, obj in enumerate(objs):
+ self.assertEqual(obj.value(), value)
+
+ def testPassAsValue(self):
+ obj = FriendOfOnlyCopy.createOnlyCopy(123)
+ self.assertEqual(obj.value(), OnlyCopy.getValue(obj))
+
+ def testPassAsReference(self):
+ obj = FriendOfOnlyCopy.createOnlyCopy(123)
+ self.assertEqual(obj.value(), OnlyCopy.getValueFromReference(obj))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/overflow_test.py b/sources/shiboken6/tests/samplebinding/overflow_test.py
new file mode 100644
index 000000000..84442306a
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/overflow_test.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for overflowing C++ numeric types.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import (Point, doubleLongLong, doubleShort, doubleUnsignedInt,
+ doubleUnsignedLongLong)
+
+
+class OverflowTest(unittest.TestCase):
+ '''Test case for overflowing C++ numeric types.'''
+
+ def assertRaises(self, *args, **kwds):
+ if not hasattr(sys, "pypy_version_info"):
+ # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError"
+ return super().assertRaises(*args, **kwds)
+
+ def testUnsignedInt(self):
+ '''C++ function receives an unsigned int argument and raise OverflowError
+ if the value is negative.'''
+ val = 100
+ self.assertEqual(doubleUnsignedInt(val), 2 * val)
+ val *= -1
+ self.assertRaises(OverflowError, doubleUnsignedInt, val)
+
+ def testLongLong(self):
+ '''C++ function receives an long long argument and raise OverflowError
+ if the value is negative.'''
+ val = 100
+ self.assertEqual(doubleLongLong(val), 2 * val)
+ val = int(100)
+ self.assertEqual(doubleLongLong(val), 2 * val)
+ val = (2 << 64) + 1
+ self.assertRaises(OverflowError, doubleLongLong, val)
+
+ def testUnsignedLongLong(self):
+ '''C++ function receives an unsigned long long argument and raise OverflowError
+ if the value is negative.'''
+ val = 100
+ self.assertEqual(doubleUnsignedLongLong(val), 2 * val)
+ val = int(100)
+ self.assertEqual(doubleUnsignedLongLong(val), 2 * val)
+ val = -100
+ self.assertRaises(OverflowError, doubleUnsignedLongLong, val)
+ val = int(-200)
+ self.assertRaises(OverflowError, doubleUnsignedLongLong, val)
+
+ def testOverflow(self):
+ '''Calls function with unsigned int parameter using an overflowing value.'''
+ self.assertRaises(OverflowError, doubleUnsignedInt, 42415335332353253)
+ doubleUnsignedInt(0xdeadbeef)
+
+ def testShortOverflow(self):
+ '''Calls function with short parameter using an overflowing value.'''
+ doubleShort(-3)
+ self.assertRaises(OverflowError, doubleShort, 0xFFFF * -1)
+ self.assertRaises(OverflowError, doubleShort, 0xFFFF + 1)
+
+ def testOverflowOnCtor(self):
+ '''Calls object ctor with int parameter using overflowing values.'''
+ self.assertRaises(OverflowError, Point, 42415335332353253, 42415335332353253)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/overload_sorting_test.py b/sources/shiboken6/tests/samplebinding/overload_sorting_test.py
new file mode 100644
index 000000000..060d91510
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/overload_sorting_test.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for overload sorting'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import (CustomOverloadSequence, ImplicitBase, ImplicitConv,
+ ImplicitTarget, SortedOverload)
+
+
+class Dummy(object):
+ pass
+
+
+class SimpleOverloadSorting(unittest.TestCase):
+
+ def setUp(self):
+ self.obj = SortedOverload()
+
+ def testIntDouble(self):
+ '''Overloads with int and double'''
+ self.assertEqual(self.obj.overload(3), "int")
+ self.assertEqual(self.obj.overload(3.14), "double")
+
+ def testImplicitConvert(self):
+ '''Overloads with implicit convertible types'''
+ self.assertEqual(self.obj.overload(ImplicitTarget()), "ImplicitTarget")
+ self.assertEqual(self.obj.overload(ImplicitBase()), "ImplicitBase")
+
+ def testContainer(self):
+ '''Overloads with containers arguments'''
+ self.assertEqual(self.obj.overload([ImplicitBase()]), "list(ImplicitBase)")
+
+ def testPyObject(self):
+ '''Overloads with PyObject args'''
+ self.assertEqual(self.obj.overload(Dummy()), "PyObject")
+
+ def testImplicitOnly(self):
+ '''Passing an implicit convertible object to an overload'''
+ self.assertTrue(self.obj.implicit_overload(ImplicitTarget()))
+
+ def testPyObjectSort(self):
+ self.assertEqual(self.obj.pyObjOverload(1, 2), "int,int")
+ self.assertEqual(self.obj.pyObjOverload(object(), 2), "PyObject,int")
+
+
+class DeepOverloadSorting(unittest.TestCase):
+
+ def setUp(self):
+ self.obj = SortedOverload()
+
+ def testPyObject(self):
+ '''Deep Overload - (int, PyObject *)'''
+ self.assertEqual(self.obj.overloadDeep(1, Dummy()), "PyObject")
+
+ def testImplicit(self):
+ '''Deep Overload - (int, ImplicitBase *)'''
+ self.assertEqual(self.obj.overloadDeep(1, ImplicitBase()), "ImplicitBase")
+
+
+class EnumOverIntSorting(unittest.TestCase):
+ def testEnumOverInt(self):
+ ic = ImplicitConv(ImplicitConv.CtorTwo)
+ self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorTwo)
+
+
+class TestCustomOverloadSequence(unittest.TestCase):
+ '''Ensure the int-overload (returning v + sizeof(v)) is first as specified via
+ overload-number in XML.'''
+ def testCustomOverloadSequence(self):
+ s = CustomOverloadSequence()
+ self.assertEqual(s.overload(42), 46)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/overload_test.py b/sources/shiboken6/tests/samplebinding/overload_test.py
new file mode 100644
index 000000000..62fa8d8d2
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/overload_test.py
@@ -0,0 +1,189 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for Overload class'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import Echo, Overload, Point, PointF, Polygon, Rect, RectF, Size, Str
+
+
+def raisesWithErrorMessage(func, arguments, errorType, errorMsg):
+ '''NOTE: Using 'try' because assertRaisesRegexp is not available
+ to check the error message.'''
+ try:
+ func(*arguments)
+ return False
+ except TypeError as err:
+ return errorMsg in str(err)
+ except Exception:
+ return False
+ return True
+
+
+class OverloadTest(unittest.TestCase):
+ '''Test case for Overload class'''
+
+ def testOverloadMethod0(self):
+ '''Check overloaded method call for signature "overloaded()".'''
+ overload = Overload()
+ self.assertEqual(overload.overloaded(), Overload.Function0)
+
+ def testOverloadMethod1(self):
+ '''Check overloaded method call for signature "overloaded(Size*)".'''
+ overload = Overload()
+ size = Size()
+ self.assertEqual(overload.overloaded(size), Overload.Function1)
+
+ def testOverloadMethod2(self):
+ '''Check overloaded method call for signature "overloaded(Point*, ParamEnum)".'''
+ overload = Overload()
+ point = Point()
+ self.assertEqual(overload.overloaded(point, Overload.Param1), Overload.Function2)
+
+ def testOverloadMethod3(self):
+ '''Check overloaded method call for signature "overloaded(const Point&)".'''
+ overload = Overload()
+ point = Point()
+ self.assertEqual(overload.overloaded(point), Overload.Function3)
+
+ def testDifferentReturnTypes(self):
+ '''Check method calls for overloads with different return types.'''
+ overload = Overload()
+ self.assertEqual(overload.differentReturnTypes(), None)
+ self.assertEqual(overload.differentReturnTypes(Overload.Param1), None)
+ self.assertEqual(overload.differentReturnTypes(Overload.Param0, 13), 13)
+
+ def testIntOverloads(self):
+ overload = Overload()
+ self.assertEqual(overload.intOverloads(2, 3), 2)
+ self.assertEqual(overload.intOverloads(2, 4.5), 3)
+ self.assertEqual(overload.intOverloads(Point(0, 0), 3), 1)
+
+ def testIntDoubleOverloads(self):
+ overload = Overload()
+ self.assertEqual(overload.intDoubleOverloads(1, 2), Overload.Function0)
+ self.assertEqual(overload.intDoubleOverloads(1, 2.0), Overload.Function0)
+ self.assertEqual(overload.intDoubleOverloads(1.0, 2), Overload.Function1)
+ self.assertEqual(overload.intDoubleOverloads(1.0, 2.0), Overload.Function1)
+
+ def testWrapperIntIntOverloads(self):
+ overload = Overload()
+ self.assertEqual(overload.wrapperIntIntOverloads(Point(), 1, 2), Overload.Function0)
+ self.assertEqual(overload.wrapperIntIntOverloads(Polygon(), 1, 2), Overload.Function1)
+
+ def testDrawTextPointAndStr(self):
+ overload = Overload()
+ self.assertEqual(overload.drawText(Point(), Str()), Overload.Function0)
+ self.assertEqual(overload.drawText(Point(), ''), Overload.Function0)
+ self.assertEqual(overload.drawText(PointF(), Str()), Overload.Function1)
+ self.assertEqual(overload.drawText(PointF(), ''), Overload.Function1)
+
+ def testDrawTextRectIntStr(self):
+ overload = Overload()
+ self.assertEqual(overload.drawText(Rect(), 1, Str()), Overload.Function2)
+ self.assertEqual(overload.drawText(Rect(), 1, ''), Overload.Function2)
+ self.assertEqual(overload.drawText(RectF(), 1, Str()), Overload.Function3)
+ self.assertEqual(overload.drawText(RectF(), 1, ''), Overload.Function3)
+
+ def testDrawTextRectFStrEcho(self):
+ overload = Overload()
+ self.assertEqual(overload.drawText(RectF(), Str()), Overload.Function4)
+ self.assertEqual(overload.drawText(RectF(), ''), Overload.Function4)
+ self.assertEqual(overload.drawText(RectF(), Str(), Echo()), Overload.Function4)
+ self.assertEqual(overload.drawText(RectF(), '', Echo()), Overload.Function4)
+ self.assertEqual(overload.drawText(Rect(), Str()), Overload.Function4)
+ self.assertEqual(overload.drawText(Rect(), ''), Overload.Function4)
+ self.assertEqual(overload.drawText(Rect(), Str(), Echo()), Overload.Function4)
+ self.assertEqual(overload.drawText(Rect(), '', Echo()), Overload.Function4)
+
+ def testDrawTextIntIntStr(self):
+ overload = Overload()
+ self.assertEqual(overload.drawText(1, 2, Str()), Overload.Function5)
+ self.assertEqual(overload.drawText(1, 2, ''), Overload.Function5)
+
+ def testDrawTextIntIntIntIntStr(self):
+ overload = Overload()
+ self.assertEqual(overload.drawText(1, 2, 3, 4, 5, Str()), Overload.Function6)
+ self.assertEqual(overload.drawText(1, 2, 3, 4, 5, ''), Overload.Function6)
+
+ def testDrawText2IntIntIntIntStr(self):
+ overload = Overload()
+ self.assertEqual(overload.drawText2(1, 2, 3, 4, 5, Str()), Overload.Function6)
+ self.assertEqual(overload.drawText2(1, 2, 3, 4, 5, ''), Overload.Function6)
+ self.assertEqual(overload.drawText2(1, 2, 3, 4, 5), Overload.Function6)
+ self.assertEqual(overload.drawText2(1, 2, 3, 4), Overload.Function6)
+ self.assertEqual(overload.drawText2(1, 2, 3), Overload.Function6)
+
+ def testDrawText3(self):
+ overload = Overload()
+ self.assertEqual(overload.drawText3(Str(), Str(), Str()), Overload.Function0)
+ self.assertEqual(overload.drawText3('', '', ''), Overload.Function0)
+ self.assertEqual(overload.drawText3(1, 2, 3, 4, 5), Overload.Function1)
+ self.assertEqual(overload.drawText3(1, 2, 3, 4, 5), Overload.Function1)
+
+ def testDrawText3Exception(self):
+ overload = Overload()
+ args = (Str(), Str(), Str(), 4, 5)
+ result = raisesWithErrorMessage(overload.drawText3, args,
+ TypeError, 'called with wrong argument types:')
+ self.assertTrue(result)
+
+ def testDrawText4(self):
+ overload = Overload()
+ self.assertEqual(overload.drawText4(1, 2, 3), Overload.Function0)
+ self.assertEqual(overload.drawText4(1, 2, 3, 4, 5), Overload.Function1)
+
+ def testAcceptSequence(self):
+ # Overload.acceptSequence()
+ overload = Overload()
+ self.assertEqual(overload.acceptSequence(), Overload.Function0)
+
+ def testAcceptSequenceIntInt(self):
+ # Overload.acceptSequence(int,int)
+ overload = Overload()
+ self.assertEqual(overload.acceptSequence(1, 2), Overload.Function1)
+
+ def testAcceptSequenceStrParamEnum(self):
+ # Overload.acceptSequence(Str,Overload::ParamEnum)
+ overload = Overload()
+ self.assertEqual(overload.acceptSequence(''), Overload.Function2)
+ self.assertEqual(overload.acceptSequence('', Overload.Param0), Overload.Function2)
+ self.assertEqual(overload.acceptSequence(Str('')), Overload.Function2)
+ self.assertEqual(overload.acceptSequence(Str(''), Overload.Param0), Overload.Function2)
+
+ def testAcceptSequenceSize(self):
+ # Overload.acceptSequence(Size)
+ overload = Overload()
+ self.assertEqual(overload.acceptSequence(Size()), Overload.Function3)
+
+ def testAcceptSequenceStringList(self):
+ # Overload.acceptSequence(const char**)
+ overload = Overload()
+ strings = ['line 1', 'line 2']
+ self.assertEqual(overload.acceptSequence(strings), Overload.Function4)
+ args = (['line 1', 2], )
+ result = raisesWithErrorMessage(overload.acceptSequence, args,
+ TypeError, 'The argument must be a sequence of strings.')
+ self.assertTrue(result)
+
+ def testAcceptSequencePyObject(self):
+ # Overload.acceptSequence(void*)
+ overload = Overload()
+
+ class Foo(object):
+ pass
+
+ foo = Foo()
+ self.assertEqual(overload.acceptSequence(foo), Overload.Function5)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/overloadwithdefault_test.py b/sources/shiboken6/tests/samplebinding/overloadwithdefault_test.py
new file mode 100644
index 000000000..269b97299
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/overloadwithdefault_test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Overload, Str
+
+
+class OverloadTest(unittest.TestCase):
+
+ def testNoArgument(self):
+ overload = Overload()
+ self.assertEqual(overload.strBufferOverloads(), Overload.Function2)
+
+ def testStrArgument(self):
+ overload = Overload()
+ self.assertEqual(overload.strBufferOverloads(Str('')), Overload.Function0)
+ self.assertEqual(overload.strBufferOverloads(Str(''), ''), Overload.Function0)
+ self.assertEqual(overload.strBufferOverloads(Str(''), '', False), Overload.Function0)
+
+ def testStringArgumentAsStr(self):
+ overload = Overload()
+ self.assertEqual(overload.strBufferOverloads('', ''), Overload.Function0)
+ self.assertEqual(overload.strBufferOverloads('', '', False), Overload.Function0)
+
+ def testStringArgumentAsBuffer(self):
+ overload = Overload()
+ self.assertEqual(overload.strBufferOverloads(bytes('', "UTF-8"), 0), Overload.Function1)
+
+ def testBufferArgument(self):
+ overload = Overload()
+ self.assertEqual(overload.strBufferOverloads(bytes('', "UTF-8"), 0), Overload.Function1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_argument_invalidation_test.py b/sources/shiboken6/tests/samplebinding/ownership_argument_invalidation_test.py
new file mode 100644
index 000000000..8a55d3ab8
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_argument_invalidation_test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Wrapper validity tests for arguments.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Polygon, Point
+
+
+class WrapperValidityOfArgumentsTest(unittest.TestCase):
+ '''Wrapper validity tests for arguments.'''
+
+ def testInvalidArgumentToMethod(self):
+ '''Call to method using invalidated Python wrapper as argument should raise RuntimeError.'''
+ poly = Polygon()
+ Polygon.stealOwnershipFromPython(poly)
+ self.assertRaises(RuntimeError, Polygon.doublePolygonScale, poly)
+
+ def testInvalidArgumentToConstructor(self):
+ '''Call to constructor using invalidated Python wrapper as argument
+ should raise RuntimeError.'''
+ pt = Point(1, 2)
+ Polygon.stealOwnershipFromPython(pt)
+ self.assertRaises(RuntimeError, Polygon, pt)
+
+ def testInvalidArgumentWithImplicitConversion(self):
+ '''Call to method using invalidated Python wrapper to be implicitly converted
+ should raise RuntimeError.'''
+ pt = Point(1, 2)
+ Polygon.stealOwnershipFromPython(pt)
+ self.assertRaises(RuntimeError, Polygon.doublePolygonScale, pt)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_cpp_test.py b/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_cpp_test.py
new file mode 100644
index 000000000..25c6fea26
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_cpp_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests for destroy a child object in C++'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class DeleteChildInCpp(unittest.TestCase):
+ '''Test case for destroying a child in c++'''
+
+ def testDeleteChild(self):
+ '''Delete child in C++ should invalidate child - using C++ wrapper'''
+ parent = ObjectType()
+ parent.setObjectName('parent')
+ child = ObjectType(parent)
+ child.setObjectName('child')
+
+ parent.killChild('child')
+ self.assertRaises(RuntimeError, child.objectName)
+ self.assertEqual(parent.objectName(), 'parent')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_python_test.py b/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_python_test.py
new file mode 100644
index 000000000..3ae186815
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_python_test.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests for deleting a child object in python'''
+
+import gc
+import os
+import random
+import string
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class DeleteChildInPython(unittest.TestCase):
+ '''Test case for deleting (unref) a child in python'''
+
+ def testDeleteChild(self):
+ '''Delete child in python should not invalidate child'''
+ parent = ObjectType()
+ child = ObjectType(parent)
+ name = ''.join(random.sample(string.ascii_letters, 5))
+ child.setObjectName(name)
+
+ del child
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ new_child = parent.children()[0]
+ self.assertEqual(new_child.objectName(), name)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_delete_parent_test.py b/sources/shiboken6/tests/samplebinding/ownership_delete_parent_test.py
new file mode 100644
index 000000000..8f654639c
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_delete_parent_test.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests for destroying the parent'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class DeleteParentTest(unittest.TestCase):
+ '''Test case for deleting a parent object'''
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testParentDestructor(self):
+ '''Delete parent object should invalidate child'''
+ parent = ObjectType()
+ child = ObjectType()
+ child.setParent(parent)
+
+ refcount_before = sys.getrefcount(child)
+
+ del parent
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertRaises(RuntimeError, child.objectName)
+ self.assertEqual(sys.getrefcount(child), refcount_before - 1)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testParentDestructorMultipleChildren(self):
+ '''Delete parent object should invalidate all children'''
+ parent = ObjectType()
+ children = [ObjectType() for _ in range(10)]
+
+ for child in children:
+ child.setParent(parent)
+
+ del parent
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ for i, child in enumerate(children):
+ self.assertRaises(RuntimeError, child.objectName)
+ self.assertEqual(sys.getrefcount(child), 4)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testRecursiveParentDelete(self):
+ '''Delete parent should invalidate grandchildren'''
+ parent = ObjectType()
+ child = ObjectType(parent)
+ grandchild = ObjectType(child)
+
+ del parent
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertRaises(RuntimeError, child.objectName)
+ self.assertEqual(sys.getrefcount(child), 2)
+ self.assertRaises(RuntimeError, grandchild.objectName)
+ self.assertEqual(sys.getrefcount(grandchild), 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_invalidate_after_use_test.py b/sources/shiboken6/tests/samplebinding/ownership_invalidate_after_use_test.py
new file mode 100644
index 000000000..37b7591e4
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_invalidate_after_use_test.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Ownership tests for cases of invalidation of Python wrapper after use.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, ObjectTypeDerived, Event
+
+
+class ExtObjectType(ObjectType):
+ def __init__(self):
+ ObjectType.__init__(self)
+ self.type_of_last_event = None
+ self.last_event = None
+
+ def event(self, event):
+ self.last_event = event
+ self.type_of_last_event = event.eventType()
+ return True
+
+
+class MyObjectType (ObjectType):
+ def __init__(self):
+ super(MyObjectType, self).__init__()
+ self.fail = False
+
+ def event(self, ev):
+ self.callInvalidateEvent(ev)
+ try:
+ ev.eventType()
+ except: # noqa: E722
+ self.fail = True
+ raise
+ return True
+
+ def invalidateEvent(self, ev):
+ pass
+
+
+class ExtObjectTypeDerived(ObjectTypeDerived):
+ def __init__(self):
+ ObjectTypeDerived.__init__(self)
+ self.type_of_last_event = None
+ self.last_event = None
+
+ def event(self, event):
+ self.last_event = event
+ self.type_of_last_event = event.eventType()
+ return True
+
+
+class OwnershipInvalidateAfterUseTest(unittest.TestCase):
+ '''Ownership tests for cases of invalidation of Python wrapper after use.'''
+
+ def testInvalidateAfterUse(self):
+ '''In ObjectType.event(Event*) the wrapper object created for Event
+ must me marked as invalid after the method is called.'''
+ eot = ExtObjectType()
+ eot.causeEvent(Event.SOME_EVENT)
+ self.assertEqual(eot.type_of_last_event, Event.SOME_EVENT)
+ self.assertRaises(RuntimeError, eot.last_event.eventType)
+
+ def testObjectInvalidatedAfterUseAsParameter(self):
+ '''Tries to use wrapper invalidated after use as a parameter to another method.'''
+ eot = ExtObjectType()
+ ot = ObjectType()
+ eot.causeEvent(Event.ANY_EVENT)
+ self.assertEqual(eot.type_of_last_event, Event.ANY_EVENT)
+ self.assertRaises(RuntimeError, ot.event, eot.last_event)
+
+ def testit(self):
+ obj = MyObjectType()
+ obj.causeEvent(Event.BASIC_EVENT)
+ self.assertFalse(obj.fail)
+
+ def testInvalidateAfterUseInDerived(self):
+ '''Invalidate was failing in a derived C++ class that also inherited
+ other base classes'''
+ eot = ExtObjectTypeDerived()
+ eot.causeEvent(Event.SOME_EVENT)
+ self.assertEqual(eot.type_of_last_event, Event.SOME_EVENT)
+ self.assertRaises(RuntimeError, eot.last_event.eventType)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_invalidate_child_test.py b/sources/shiboken6/tests/samplebinding/ownership_invalidate_child_test.py
new file mode 100644
index 000000000..77b7c576c
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_invalidate_child_test.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests for invalidating a C++ created child that was already on the care of a parent.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, BlackBox
+
+
+class InvalidateChildTest(unittest.TestCase):
+ '''Tests for invalidating a C++ created child that was already on the care of a parent.'''
+
+ def testInvalidateChild(self):
+ '''Invalidating method call should remove child from the care of a parent if it has one.'''
+ parent = ObjectType()
+ child1 = ObjectType(parent)
+ child1.setObjectName('child1')
+ child2 = ObjectType.create()
+ child2.setParent(parent)
+ child2.setObjectName('child2')
+
+ self.assertEqual(parent.children(), [child1, child2])
+
+ bbox = BlackBox()
+
+ # This method steals ownership from Python to C++.
+ bbox.keepObjectType(child1)
+ self.assertEqual(parent.children(), [child2])
+
+ bbox.keepObjectType(child2)
+ self.assertEqual(parent.children(), [])
+
+ del parent
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ # PYSIDE-535: Why do I need to do it twice, here?
+ gc.collect()
+
+ self.assertEqual(child1.objectName(), 'child1')
+ self.assertRaises(RuntimeError, child2.objectName)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py b/sources/shiboken6/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py
new file mode 100644
index 000000000..8cbefc30c
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''The BlackBox class has cases of ownership transference between Python and C++.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point, BlackBox
+
+
+class OwnershipInvalidateNonPolymorphicTest(unittest.TestCase):
+ '''The BlackBox class has cases of ownership transference between Python and C++.'''
+
+ def testOwnershipTransference(self):
+ '''Ownership transference from Python to C++ and back again.'''
+ p1 = Point(10, 20)
+ bb = BlackBox()
+ p1_ticket = bb.keepPoint(p1)
+ self.assertRaises(RuntimeError, p1.x)
+ p1_ret = bb.retrievePoint(p1_ticket)
+ self.assertEqual(p1_ret, Point(10, 20))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_invalidate_parent_test.py b/sources/shiboken6/tests/samplebinding/ownership_invalidate_parent_test.py
new file mode 100644
index 000000000..c721a212c
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_invalidate_parent_test.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests for invalidating a parent of other objects.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, BlackBox
+
+
+class InvalidateParentTest(unittest.TestCase):
+ '''Tests for invalidating a parent of other objects.'''
+
+ def testInvalidateParent(self):
+ '''Invalidate parent should invalidate children'''
+ parent = ObjectType.create()
+ child1 = ObjectType(parent)
+ child1.setObjectName("child1")
+ child2 = ObjectType.create()
+ child2.setObjectName("child2")
+ child2.setParent(parent)
+ grandchild1 = ObjectType(child1)
+ grandchild1.setObjectName("grandchild1")
+ grandchild2 = ObjectType.create()
+ grandchild2.setObjectName("grandchild2")
+ grandchild2.setParent(child2)
+ bbox = BlackBox()
+
+ bbox.keepObjectType(parent) # Should invalidate the parent
+
+ self.assertRaises(RuntimeError, parent.objectName)
+ # some children still valid they are wrapper classes
+ self.assertEqual(child1.objectName(), "child1")
+ self.assertRaises(RuntimeError, child2.objectName)
+ self.assertEqual(grandchild1.objectName(), "grandchild1")
+ self.assertRaises(RuntimeError, grandchild2.objectName)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_reparenting_test.py b/sources/shiboken6/tests/samplebinding/ownership_reparenting_test.py
new file mode 100644
index 000000000..304223063
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_reparenting_test.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests for object reparenting.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+import sys
+
+from sample import ObjectType
+
+
+class ExtObjectType(ObjectType):
+ def __init__(self):
+ ObjectType.__init__(self)
+
+
+class ReparentingTest(unittest.TestCase):
+ '''Tests for object reparenting.'''
+
+ def testReparentedObjectTypeIdentity(self):
+ '''Reparent children from one parent to another.'''
+ object_list = []
+ old_parent = ObjectType()
+ new_parent = ObjectType()
+ for i in range(3):
+ obj = ObjectType()
+ object_list.append(obj)
+ obj.setParent(old_parent)
+ for obj in object_list:
+ obj.setParent(new_parent)
+ for child in new_parent.children():
+ self.assertTrue(child in object_list)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testReparentWithTheSameParent(self):
+ '''Set the same parent twice to check if the ref continue the same'''
+ obj = ObjectType()
+ parent = ObjectType()
+ self.assertEqual(sys.getrefcount(obj), 2)
+ obj.setParent(parent)
+ self.assertEqual(sys.getrefcount(obj), 3)
+ obj.setParent(parent)
+ self.assertEqual(sys.getrefcount(obj), 3)
+
+ def testReparentedExtObjectType(self):
+ '''Reparent children from one extended parent to another.'''
+ object_list = []
+ old_parent = ExtObjectType()
+ new_parent = ExtObjectType()
+ for i in range(3):
+ obj = ExtObjectType()
+ object_list.append(obj)
+ obj.setParent(old_parent)
+ for obj in object_list:
+ obj.setParent(new_parent)
+ for orig, child in zip(object_list, new_parent.children()):
+ self.assertEqual(type(orig), type(child))
+
+ def testReparentedObjectTypeIdentityWithParentsCreatedInCpp(self):
+ '''Reparent children from one parent to another, both created in C++.'''
+ object_list = []
+ old_parent = ObjectType.create()
+ new_parent = ObjectType.create()
+ for i in range(3):
+ obj = ObjectType()
+ object_list.append(obj)
+ obj.setParent(old_parent)
+ for obj in object_list:
+ obj.setParent(new_parent)
+ for child in new_parent.children():
+ self.assertTrue(child in object_list)
+
+ def testReparentedObjectTypeIdentityWithChildrenCreatedInCpp(self):
+ '''Reparent children created in C++ from one parent to another.'''
+ object_list = []
+ old_parent = ObjectType()
+ new_parent = ObjectType()
+ for i in range(3):
+ obj = ObjectType.create()
+ object_list.append(obj)
+ obj.setParent(old_parent)
+ for obj in object_list:
+ obj.setParent(new_parent)
+ for child in new_parent.children():
+ self.assertTrue(child in object_list)
+
+ def testReparentedObjectTypeIdentityWithParentsAndChildrenCreatedInCpp(self):
+ '''Reparent children from one parent to another. Parents and children are created in C++.'''
+ object_list = []
+ old_parent = ObjectType.create()
+ new_parent = ObjectType.create()
+ for i in range(3):
+ obj = ObjectType.create()
+ object_list.append(obj)
+ obj.setParent(old_parent)
+ for obj in object_list:
+ obj.setParent(new_parent)
+ for child in new_parent.children():
+ self.assertTrue(child in object_list)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/ownership_transference_test.py b/sources/shiboken6/tests/samplebinding/ownership_transference_test.py
new file mode 100644
index 000000000..0e9f08b72
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/ownership_transference_test.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''The BlackBox class has cases of ownership transference between C++ and Python.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, BlackBox
+
+
+class BlackBoxTest(unittest.TestCase):
+ '''The BlackBox class has cases of ownership transference between C++ and Python.'''
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testOwnershipTransference(self):
+ '''Ownership transference from Python to C++ and back again.'''
+ o1 = ObjectType()
+ o1.setObjectName('object1')
+ o1_refcnt = sys.getrefcount(o1)
+ o2 = ObjectType()
+ o2.setObjectName('object2')
+ o2_refcnt = sys.getrefcount(o2)
+ bb = BlackBox()
+ o1_ticket = bb.keepObjectType(o1) # noqa: F841
+ o2_ticket = bb.keepObjectType(o2)
+ self.assertEqual(set(bb.objects()), set([o1, o2]))
+ self.assertEqual(str(o1.objectName()), 'object1')
+ self.assertEqual(str(o2.objectName()), 'object2')
+ # PySide give +1 ref to object with c++ ownership
+ self.assertEqual(sys.getrefcount(o1), o1_refcnt + 1)
+ self.assertEqual(sys.getrefcount(o2), o2_refcnt + 1)
+ o2 = bb.retrieveObjectType(o2_ticket)
+ self.assertEqual(sys.getrefcount(o2), o2_refcnt)
+ del bb
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertRaises(RuntimeError, o1.objectName)
+ self.assertEqual(str(o2.objectName()), 'object2')
+ self.assertEqual(sys.getrefcount(o2), o2_refcnt)
+
+ def testBlackBoxReleasingUnknownObjectType(self):
+ '''Asks BlackBox to release an unknown ObjectType.'''
+ o1 = ObjectType()
+ o2 = ObjectType() # noqa: F841
+ bb = BlackBox()
+ o1_ticket = bb.keepObjectType(o1) # noqa: F841
+ o3 = bb.retrieveObjectType(-5)
+ self.assertEqual(o3, None)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testOwnershipTransferenceCppCreated(self):
+ '''Ownership transference using a C++ created object.'''
+ o1 = ObjectType.create()
+ o1.setObjectName('object1')
+ o1_refcnt = sys.getrefcount(o1) # noqa: F841
+ bb = BlackBox()
+ o1_ticket = bb.keepObjectType(o1) # noqa: F841
+ self.assertRaises(RuntimeError, o1.objectName)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/pair_test.py b/sources/shiboken6/tests/samplebinding/pair_test.py
new file mode 100644
index 000000000..4bd5c697c
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/pair_test.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for std::pair container conversions'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import PairUser
+
+
+class ExtendedPairUser(PairUser):
+ def __init__(self):
+ PairUser.__init__(self)
+ self.create_pair_called = False
+
+ def createPair(self):
+ self.create_pair_called = True
+ return (7, 13)
+
+
+class PairConversionTest(unittest.TestCase):
+ '''Test case for std::pair container conversions'''
+
+ def testReimplementedVirtualMethodCall(self):
+ '''Test if a Python override of a virtual method is correctly called from C++.'''
+ pu = ExtendedPairUser()
+ pair = pu.callCreatePair()
+ self.assertTrue(pu.create_pair_called)
+ self.assertEqual(type(pair), tuple)
+ self.assertEqual(type(pair[0]), int)
+ self.assertEqual(type(pair[1]), int)
+ self.assertEqual(pair, (7, 13))
+
+ def testPrimitiveConversionInsideContainer(self):
+ '''Test primitive type conversion inside conversible std::pair container.'''
+ cpx0 = complex(1.2, 3.4)
+ cpx1 = complex(5.6, 7.8)
+ cp = PairUser.createComplexPair(cpx0, cpx1)
+ self.assertEqual(type(cp), tuple)
+ self.assertEqual(type(cp[0]), complex)
+ self.assertEqual(type(cp[1]), complex)
+ self.assertEqual(cp, (cpx0, cpx1))
+
+ def testSumPair(self):
+ '''Test method that sums the items of a pair using values of the types
+ expected by C++ (int and double)'''
+ pu = PairUser()
+ pair = (3, 7.13)
+ result = pu.sumPair(pair)
+ self.assertEqual(result, sum(pair))
+
+ def testSumPairDifferentTypes(self):
+ '''Test method that sums the items of a pair using values of types different
+ from the ones expected by C++ (int and double)'''
+ pu = PairUser()
+ pair = (3.3, 7)
+ result = pu.sumPair(pair)
+ self.assertNotEqual(result, sum(pair))
+ self.assertEqual(result, int(pair[0]) + pair[1])
+
+ def testConversionInBothDirections(self):
+ '''Test converting a pair from Python to C++ and the other way around.'''
+ pu = PairUser()
+ pair = (3, 5)
+ pu.setPair(pair)
+ result = pu.getPair()
+ self.assertEqual(result, pair)
+
+ def testConversionInBothDirectionsWithSimilarContainer(self):
+ '''Test converting a list, instead of the expected tuple, from Python to C++
+ and the other way around.'''
+ pu = PairUser()
+ pair = [3, 5]
+ pu.setPair(pair)
+ result = pu.getPair()
+ self.assertNotEqual(result, pair)
+ self.assertEqual(result, tuple(pair))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/pen_test.py b/sources/shiboken6/tests/samplebinding/pen_test.py
new file mode 100644
index 000000000..106f3bd61
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/pen_test.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for <add-function> with const char* as argument'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Color, Pen, SampleNamespace
+
+
+class TestPen(unittest.TestCase):
+ '''Simple test case for Pen.'''
+
+ def testPenWithEmptyConstructor(self):
+ pen = Pen()
+ self.assertEqual(pen.ctorType(), Pen.EmptyCtor)
+
+ def testPenWithEnumConstructor(self):
+ pen = Pen(SampleNamespace.RandomNumber)
+ self.assertEqual(pen.ctorType(), Pen.EnumCtor)
+
+ def testPenWithColorConstructor(self):
+ pen = Pen(Color())
+ self.assertEqual(pen.ctorType(), Pen.ColorCtor)
+
+ def testPenWithCopyConstructor(self):
+ pen = Pen(Pen())
+ self.assertEqual(pen.ctorType(), Pen.CopyCtor)
+
+ def testPenWithIntConvertedToColor(self):
+ pen = Pen(1)
+ self.assertEqual(pen.ctorType(), Pen.ColorCtor)
+ pen.drawLine(0, 0, 5, 5)
+
+ def testPenRenderHintsProperty(self):
+ """Exercise the generated property setter and getters, checking
+ against the C++ getter/setter functions."""
+ pen = Pen(1)
+ self.assertEqual(pen.getRenderHints(), Pen.RenderHints.None_)
+ self.assertEqual(pen.renderHints, Pen.RenderHints.None_)
+ pen.renderHints = Pen.RenderHints.TextAntialiasing
+ self.assertEqual(pen.getRenderHints(), Pen.RenderHints.TextAntialiasing)
+ self.assertEqual(pen.renderHints, Pen.RenderHints.TextAntialiasing)
+ pen.setRenderHints(Pen.RenderHints.Antialiasing)
+ self.assertEqual(pen.getRenderHints(), Pen.RenderHints.Antialiasing)
+ self.assertEqual(pen.renderHints, Pen.RenderHints.Antialiasing)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/point_test.py b/sources/shiboken6/tests/samplebinding/point_test.py
new file mode 100644
index 000000000..f86c0f423
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/point_test.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for Point class'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point
+
+
+class PointTest(unittest.TestCase):
+ '''Test case for Point class, including operator overloads.'''
+
+ def assertRaises(self, *args, **kwds):
+ if not hasattr(sys, "pypy_version_info"):
+ # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError"
+ return super().assertRaises(*args, **kwds)
+
+ def testConstructor(self):
+ '''Test Point class constructor.'''
+ pt = Point(5.0, 2.3)
+ self.assertEqual(pt.x(), 5.0)
+ self.assertEqual(pt.y(), 2.3)
+
+ def testPlusOperator(self):
+ '''Test Point class + operator.'''
+ pt1 = Point(5.0, 2.3)
+ pt2 = Point(0.5, 3.2)
+ self.assertEqual(pt1 + pt2, Point(5.0 + 0.5, 2.3 + 3.2))
+
+ def testEqualOperator(self):
+ '''Test Point class == operator.'''
+ pt1 = Point(5.0, 2.3)
+ pt2 = Point(5.0, 2.3)
+ pt3 = Point(0.5, 3.2)
+ self.assertTrue(pt1 == pt1)
+ self.assertTrue(pt1 == pt2)
+ self.assertFalse(pt1 == pt3)
+ self.assertFalse(pt1 == object())
+
+ def testNotEqualOperator(self):
+ '''Test Point class != operator.'''
+ pt1 = Point(5.0, 2.3)
+ pt2 = Point(5.0, 2.3)
+ # This test no longer makes sense because we always supply default `==`, `!=`.
+ #self.assertRaises(NotImplementedError, pt1.__ne__, pt2)
+ # Since we use the default identity comparison, this results in `!=` .
+ self.assertTrue(pt1 != pt2)
+
+ def testReturnNewCopy(self):
+ '''Point returns a copy of itself.'''
+ pt1 = Point(1.1, 2.3)
+ pt2 = pt1.copy()
+ self.assertEqual(pt1, pt2)
+ pt2 += pt1
+ self.assertFalse(pt1 == pt2)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testReturnConstPointer(self):
+ '''Point returns a const pointer for itself.'''
+ pt1 = Point(5.0, 2.3)
+ refcount1 = sys.getrefcount(pt1)
+ pt2 = pt1.getSelf()
+ self.assertEqual(pt1, pt2)
+ self.assertEqual(sys.getrefcount(pt1), refcount1 + 1)
+ self.assertEqual(sys.getrefcount(pt1), sys.getrefcount(pt2))
+
+ def testUintOverflow(self):
+ pt1 = Point(0.0, 0.0)
+ self.assertRaises(OverflowError, pt1.setXAsUint, 840835495615213080)
+ self.assertEqual(pt1.x(), 0.0)
+
+ def testAddedOperator(self):
+ p = Point(0.0, 0.0)
+ r = p - 'Hi'
+ self.assertEqual(r, 'Hi')
+
+ # now the reverse op.
+ r = 'Hi' - p
+ self.assertEqual(r, 'Hi')
+
+ def testModifiedMethod(self):
+ pt1 = Point(0.0, 0.0)
+ pt2 = Point(10.0, 10.0)
+ expected = Point((pt1.x() + pt2.x()) / 2.0, (pt1.y() + pt2.y()) / 2.0)
+ self.assertEqual(pt1.midpoint(pt2), expected)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/pointerholder_test.py b/sources/shiboken6/tests/samplebinding/pointerholder_test.py
new file mode 100644
index 000000000..633525a9c
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/pointerholder_test.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for a class that holds an arbitraty pointer and is modified to hold an PyObject.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import PointerHolder
+
+
+class TestPointerHolder(unittest.TestCase):
+ '''Test cases for a class that holds an arbitraty pointer and
+ is modified to hold an PyObject.'''
+
+ def testStoringAndRetrievingPointer(self):
+ ph = PointerHolder('Hello')
+ self.assertEqual(ph.pointer(), 'Hello')
+ a = (1, 2, 3)
+ ph = PointerHolder(a)
+ self.assertEqual(ph.pointer(), a)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testReferenceCounting(self):
+ '''Test reference counting when retrieving data with PointerHolder.pointer().'''
+ a = (1, 2, 3)
+ refcnt = sys.getrefcount(a)
+ ph = PointerHolder(a)
+ ptr = ph.pointer() # noqa: F841
+ self.assertEqual(sys.getrefcount(a), refcnt + 1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/pointerprimitivetype_test.py b/sources/shiboken6/tests/samplebinding/pointerprimitivetype_test.py
new file mode 100644
index 000000000..4da1a89c6
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/pointerprimitivetype_test.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+"""
+pointerprimitivetype_test.py
+
+check that the primitive types are correctly mapped by the signature module.
+
+Mapping
+-------
+IntArray2(const int*) -- <Signature (self, data: typing.Sequence)>
+getMargins(int*,int*,int*,int*)const -- <Signature (self) -> typing.Tuple[int, int, int, int]>
+
+We explicitly check only against typing.Iterable in the first test,
+because typing.Sequence is a subclass, but we will generalize this
+to typing.Iterable in the future.
+"""
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import IntArray2, VirtualMethods
+
+from shibokensupport.signature import get_signature
+
+import typing
+
+
+class PointerPrimitiveTypeTest(unittest.TestCase):
+
+ def testArraySignature(self):
+ # signature="IntArray2(const int*)"
+ found = False
+ for sig in get_signature(IntArray2):
+ if "data" in sig.parameters:
+ found = True
+ break
+ self.assertTrue(found)
+ ann = sig.parameters["data"].annotation
+ self.assertEqual(ann.__args__, (int,))
+ self.assertTrue(issubclass(ann.__origin__, typing.Iterable))
+
+ def testReturnVarSignature(self):
+ # signature="getMargins(int*,int*,int*,int*)const">
+ ann = get_signature(VirtualMethods.getMargins).return_annotation
+ self.assertEqual(ann, typing.Tuple[int, int, int, int])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/pointf_test.py b/sources/shiboken6/tests/samplebinding/pointf_test.py
new file mode 100644
index 000000000..91c58eb1d
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/pointf_test.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for PointF class'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import PointF
+
+
+class PointFTest(unittest.TestCase):
+ '''Test case for PointF class, including operator overloads.'''
+
+ def testConstructor(self):
+ '''Test PointF class constructor.'''
+ pt = PointF(5.0, 2.3)
+ self.assertEqual(pt.x(), 5.0)
+ self.assertEqual(pt.y(), 2.3)
+
+ def testPlusOperator(self):
+ '''Test PointF class + operator.'''
+ pt1 = PointF(5.0, 2.3)
+ pt2 = PointF(0.5, 3.2)
+ self.assertEqual(pt1 + pt2, PointF(5.0 + 0.5, 2.3 + 3.2))
+
+ def testEqualOperator(self):
+ '''Test PointF class == operator.'''
+ pt1 = PointF(5.0, 2.3)
+ pt2 = PointF(5.0, 2.3)
+ pt3 = PointF(0.5, 3.2)
+ self.assertTrue(pt1 == pt1)
+ self.assertTrue(pt1 == pt2)
+ self.assertFalse(pt1 == pt3)
+
+ def testModifiedMethod(self):
+ pt1 = PointF(0.0, 0.0)
+ pt2 = PointF(10.0, 10.0)
+ expected = PointF((pt1.x() + pt2.x()) / 2.0, (pt1.y() + pt2.y()) / 2.0)
+ self.assertEqual(pt1.midpoint(pt2), expected)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/primitivereferenceargument_test.py b/sources/shiboken6/tests/samplebinding/primitivereferenceargument_test.py
new file mode 100644
index 000000000..0b9fe2249
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/primitivereferenceargument_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+import sample
+
+
+class PrimitiveReferenceArgumentTest(unittest.TestCase):
+
+ def testIntReferenceArgument(self):
+ '''C++ signature: int acceptIntReference(int&)'''
+ self.assertEqual(sample.acceptIntReference(123), 123)
+
+ def testIntReturnPtr(self):
+ '''C++ signature: const int *acceptIntReturnPtr(int x)'''
+ self.assertEqual(sample.acceptIntReturnPtr(123), 123)
+
+ def testOddBoolReferenceArgument(self):
+ '''C++ signature: OddBool acceptOddBoolReference(OddBool&)'''
+ self.assertEqual(sample.acceptOddBoolReference(True), True)
+ self.assertEqual(sample.acceptOddBoolReference(False), False)
+ self.assertNotEqual(sample.acceptOddBoolReference(True), False)
+ self.assertNotEqual(sample.acceptOddBoolReference(False), True)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/privatector_test.py b/sources/shiboken6/tests/samplebinding/privatector_test.py
new file mode 100644
index 000000000..63040388d
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/privatector_test.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for a class with only a private constructor.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import PrivateCtor
+
+
+class PrivateCtorTest(unittest.TestCase):
+ '''Test case for PrivateCtor class'''
+
+ def assertRaises(self, *args, **kwds):
+ if not hasattr(sys, "pypy_version_info"):
+ # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError"
+ return super().assertRaises(*args, **kwds)
+
+ def testPrivateCtorInstanciation(self):
+ '''Test if instanciation of class with a private constructor raises an exception.'''
+ self.assertRaises(TypeError, PrivateCtor)
+
+ def testPrivateCtorInheritance(self):
+ '''Test if inheriting from PrivateCtor raises an exception.'''
+ def inherit():
+ class Foo(PrivateCtor):
+ pass
+ self.assertRaises(TypeError, inherit)
+
+ def testPrivateCtorInstanceMethod(self):
+ '''Test if PrivateCtor.instance() method return the proper singleton.'''
+ pd1 = PrivateCtor.instance()
+ calls = pd1.instanceCalls()
+ self.assertEqual(type(pd1), PrivateCtor)
+ pd2 = PrivateCtor.instance()
+ self.assertEqual(pd2, pd1)
+ self.assertEqual(pd2.instanceCalls(), calls + 1)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testPrivateCtorRefCounting(self):
+ '''Test refcounting of the singleton returned by PrivateCtor.instance().'''
+ pd1 = PrivateCtor.instance()
+ calls = pd1.instanceCalls()
+ refcnt = sys.getrefcount(pd1)
+ pd2 = PrivateCtor.instance()
+ self.assertEqual(pd2.instanceCalls(), calls + 1)
+ self.assertEqual(sys.getrefcount(pd2), sys.getrefcount(pd1))
+ self.assertEqual(sys.getrefcount(pd2), refcnt + 1)
+ del pd1
+ self.assertEqual(sys.getrefcount(pd2), refcnt)
+ del pd2
+ gc.collect()
+ pd3 = PrivateCtor.instance()
+ self.assertEqual(type(pd3), PrivateCtor)
+ self.assertEqual(pd3.instanceCalls(), calls + 2)
+ self.assertEqual(sys.getrefcount(pd3), refcnt)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/privatedtor_test.py b/sources/shiboken6/tests/samplebinding/privatedtor_test.py
new file mode 100644
index 000000000..651f63b15
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/privatedtor_test.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for a class with a private destructor.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from shiboken6 import Shiboken
+from sample import PrivateDtor
+
+
+class PrivateDtorTest(unittest.TestCase):
+ '''Test case for PrivateDtor class'''
+
+ def assertRaises(self, *args, **kwds):
+ if not hasattr(sys, "pypy_version_info"):
+ # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError"
+ return super().assertRaises(*args, **kwds)
+
+ def testPrivateDtorInstanciation(self):
+ '''Test if instanciation of class with a private destructor raises an exception.'''
+ self.assertRaises(TypeError, PrivateDtor)
+
+ def testPrivateDtorInheritance(self):
+ '''Test if inheriting from PrivateDtor raises an exception.'''
+ def inherit():
+ class Foo(PrivateDtor):
+ pass
+ self.assertRaises(TypeError, inherit)
+
+ def testPrivateDtorInstanceMethod(self):
+ '''Test if PrivateDtor.instance() method return the proper singleton.'''
+ pd1 = PrivateDtor.instance()
+ calls = pd1.instanceCalls()
+ self.assertEqual(type(pd1), PrivateDtor)
+ pd2 = PrivateDtor.instance()
+ self.assertEqual(pd2, pd1)
+ self.assertEqual(pd2.instanceCalls(), calls + 1)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testPrivateDtorRefCounting(self):
+ '''Test refcounting of the singleton returned by PrivateDtor.instance().'''
+ pd1 = PrivateDtor.instance()
+ calls = pd1.instanceCalls()
+ refcnt = sys.getrefcount(pd1)
+ pd2 = PrivateDtor.instance()
+ self.assertEqual(pd2.instanceCalls(), calls + 1)
+ self.assertEqual(sys.getrefcount(pd2), sys.getrefcount(pd1))
+ self.assertEqual(sys.getrefcount(pd2), refcnt + 1)
+ del pd1
+ self.assertEqual(sys.getrefcount(pd2), refcnt)
+ del pd2
+ gc.collect()
+ pd3 = PrivateDtor.instance()
+ self.assertEqual(type(pd3), PrivateDtor)
+ self.assertEqual(pd3.instanceCalls(), calls + 2)
+ self.assertEqual(sys.getrefcount(pd3), refcnt)
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
+ def testClassDecref(self):
+ # Bug was that class PyTypeObject wasn't decrefed when instance
+ # was invalidated
+
+ before = sys.getrefcount(PrivateDtor)
+
+ for i in range(1000):
+ obj = PrivateDtor.instance()
+ Shiboken.invalidate(obj)
+
+ after = sys.getrefcount(PrivateDtor)
+
+ self.assertLess(abs(before - after), 5)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/protected_test.py b/sources/shiboken6/tests/samplebinding/protected_test.py
new file mode 100644
index 000000000..e4ccf721d
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/protected_test.py
@@ -0,0 +1,401 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for protected methods.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import cacheSize
+from sample import ProtectedNonPolymorphic, ProtectedVirtualDestructor
+from sample import (ProtectedPolymorphic, ProtectedPolymorphicDaughter,
+ ProtectedPolymorphicGrandDaughter)
+from sample import createProtectedProperty, ProtectedProperty, ProtectedEnumClass
+from sample import PrivateDtor
+from sample import Event, ObjectType, Point
+
+
+class ExtendedProtectedPolymorphic(ProtectedPolymorphic):
+ def __init__(self, name):
+ ProtectedPolymorphic.__init__(self, name)
+ self.protectedName_called = False
+
+ def protectedName(self):
+ self.protectedName_called = True
+ self._name = 'Extended' + ProtectedPolymorphic.protectedName(self)
+ return self._name
+
+
+class ExtendedProtectedPolymorphicDaughter(ProtectedPolymorphicDaughter):
+ def __init__(self, name):
+ self.protectedName_called = False
+ ProtectedPolymorphicDaughter.__init__(self, name)
+
+ def protectedName(self):
+ self.protectedName_called = True
+ self._name = 'ExtendedDaughter' + ProtectedPolymorphicDaughter.protectedName(self)
+ return self._name
+
+
+class ExtendedProtectedPolymorphicGrandDaughter(ProtectedPolymorphicGrandDaughter):
+ def __init__(self, name):
+ self.protectedName_called = False
+ ProtectedPolymorphicGrandDaughter.__init__(self, name)
+
+ def protectedName(self):
+ self.protectedName_called = True
+ self._name = 'ExtendedGrandDaughter' + ProtectedPolymorphicGrandDaughter.protectedName(self)
+ return self._name
+
+
+class ExtendedProtectedVirtualDestructor(ProtectedVirtualDestructor):
+ def __init__(self):
+ ProtectedVirtualDestructor.__init__(self)
+
+
+class ProtectedNonPolymorphicTest(unittest.TestCase):
+ '''Test cases for protected method in a class without virtual methods.'''
+
+ def tearDown(self):
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(cacheSize(), 0)
+
+ def testProtectedCall(self):
+ '''Calls a non-virtual protected method.'''
+ p = ProtectedNonPolymorphic('NonPoly')
+ self.assertEqual(p.publicName(), p.protectedName())
+ a0, a1 = 1, 2
+ self.assertEqual(p.protectedSum(a0, a1), a0 + a1)
+
+ def testProtectedCallWithInstanceCreatedOnCpp(self):
+ '''Calls a non-virtual protected method on an instance created in C++.'''
+ p = ProtectedNonPolymorphic.create()
+ self.assertEqual(p.publicName(), p.protectedName())
+ a0, a1 = 1, 2
+ self.assertEqual(p.protectedSum(a0, a1), a0 + a1)
+
+ def testModifiedProtectedCall(self):
+ '''Calls a non-virtual protected method modified with code injection.'''
+ p = ProtectedNonPolymorphic('NonPoly')
+ self.assertEqual(p.dataTypeName(), 'integer')
+ self.assertEqual(p.dataTypeName(1), 'integer')
+ self.assertEqual(p.dataTypeName(Point(1, 2)), 'pointer')
+
+
+class ProtectedPolymorphicTest(unittest.TestCase):
+ '''Test cases for protected method in a class with virtual methods.'''
+
+ def tearDown(self):
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(cacheSize(), 0)
+
+ def testProtectedCall(self):
+ '''Calls a virtual protected method.'''
+ p = ProtectedNonPolymorphic('Poly')
+ self.assertEqual(p.publicName(), p.protectedName())
+ a0, a1 = 1, 2
+ self.assertEqual(p.protectedSum(a0, a1), a0 + a1)
+
+ def testProtectedCallWithInstanceCreatedOnCpp(self):
+ '''Calls a virtual protected method on an instance created in C++.'''
+ p = ProtectedPolymorphic.create()
+ self.assertEqual(p.publicName(), p.protectedName())
+ self.assertEqual(p.callProtectedName(), p.protectedName())
+
+ def testReimplementedProtectedCall(self):
+ '''Calls a reimplemented virtual protected method.'''
+ original_name = 'Poly'
+ p = ExtendedProtectedPolymorphic(original_name)
+ name = p.callProtectedName()
+ self.assertTrue(p.protectedName_called)
+ self.assertEqual(p.protectedName(), name)
+ self.assertEqual(ProtectedPolymorphic.protectedName(p), original_name)
+
+
+class ProtectedPolymorphicDaugherTest(unittest.TestCase):
+ '''Test cases for protected method in a class inheriting for a class with virtual methods.'''
+
+ def testProtectedCallWithInstanceCreatedOnCpp(self):
+ '''Calls a virtual protected method from parent class on an instance created in C++.'''
+ p = ProtectedPolymorphicDaughter.create()
+ self.assertEqual(p.publicName(), p.protectedName())
+ self.assertEqual(p.callProtectedName(), p.protectedName())
+
+ def testReimplementedProtectedCall(self):
+ '''Calls a reimplemented virtual protected method from parent class.'''
+ original_name = 'Poly'
+ p = ExtendedProtectedPolymorphicDaughter(original_name)
+ name = p.callProtectedName()
+ self.assertTrue(p.protectedName_called)
+ self.assertEqual(p.protectedName(), name)
+ self.assertEqual(ProtectedPolymorphicDaughter.protectedName(p), original_name)
+
+
+class ProtectedPolymorphicGrandDaugherTest(unittest.TestCase):
+ '''Test cases for protected method in a class inheriting for a class that inherits from
+ another with protected virtual methods.'''
+
+ def tearDown(self):
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(cacheSize(), 0)
+
+ def testProtectedCallWithInstanceCreatedOnCpp(self):
+ '''Calls a virtual protected method from parent class on an instance created in C++.'''
+ p = ProtectedPolymorphicGrandDaughter.create()
+ self.assertEqual(p.publicName(), p.protectedName())
+ self.assertEqual(p.callProtectedName(), p.protectedName())
+
+ def testReimplementedProtectedCall(self):
+ '''Calls a reimplemented virtual protected method from parent class.'''
+ original_name = 'Poly'
+ p = ExtendedProtectedPolymorphicGrandDaughter(original_name)
+ name = p.callProtectedName()
+ self.assertTrue(p.protectedName_called)
+ self.assertEqual(p.protectedName(), name)
+ self.assertEqual(ProtectedPolymorphicGrandDaughter.protectedName(p), original_name)
+
+
+class ProtectedVirtualDtorTest(unittest.TestCase):
+ '''Test cases for protected virtual destructor.'''
+
+ def setUp(self):
+ ProtectedVirtualDestructor.resetDtorCounter()
+
+ def tearDown(self):
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(cacheSize(), 0)
+
+ def testVirtualProtectedDtor(self):
+ '''Original protected virtual destructor is being called.'''
+ dtor_called = ProtectedVirtualDestructor.dtorCalled()
+ for i in range(1, 10):
+ pvd = ProtectedVirtualDestructor()
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ del pvd
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(ProtectedVirtualDestructor.dtorCalled(), dtor_called + i)
+
+ def testVirtualProtectedDtorOnCppCreatedObject(self):
+ '''Original protected virtual destructor is being called for a C++ created object.'''
+ dtor_called = ProtectedVirtualDestructor.dtorCalled()
+ for i in range(1, 10):
+ pvd = ProtectedVirtualDestructor.create()
+ del pvd
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(ProtectedVirtualDestructor.dtorCalled(), dtor_called + i)
+
+ def testProtectedDtorOnDerivedClass(self):
+ '''Original protected virtual destructor is being called for a derived class.'''
+ dtor_called = ExtendedProtectedVirtualDestructor.dtorCalled()
+ for i in range(1, 10):
+ pvd = ExtendedProtectedVirtualDestructor()
+ del pvd
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(ExtendedProtectedVirtualDestructor.dtorCalled(), dtor_called + i)
+
+
+class ExtendedProtectedEnumClass(ProtectedEnumClass):
+ def __init__(self):
+ ProtectedEnumClass.__init__(self)
+
+ def protectedEnumMethod(self, value):
+ if value == ProtectedEnumClass.ProtectedItem0:
+ return ProtectedEnumClass.ProtectedItem1
+ return ProtectedEnumClass.ProtectedItem0
+
+ def publicEnumMethod(self, value):
+ if value == ProtectedEnumClass.PublicItem0:
+ return ProtectedEnumClass.PublicItem1
+ return ProtectedEnumClass.PublicItem0
+
+
+class ProtectedEnumTest(unittest.TestCase):
+ '''Test cases for protected enum.'''
+
+ def tearDown(self):
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(cacheSize(), 0)
+
+ def testProtectedMethodWithProtectedEnumArgument(self):
+ '''Calls protected method with protected enum argument.'''
+ obj = ProtectedEnumClass()
+
+ self.assertEqual(type(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedEnum)
+
+ self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0),
+ ProtectedEnumClass.ProtectedItem0)
+ self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1),
+ ProtectedEnumClass.ProtectedItem1)
+ self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0),
+ ProtectedEnumClass.ProtectedItem0)
+ self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1),
+ ProtectedEnumClass.ProtectedItem1)
+
+ def testProtectedMethodWithPublicEnumArgument(self):
+ '''Calls protected method with public enum argument.'''
+ obj = ProtectedEnumClass()
+
+ self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0),
+ ProtectedEnumClass.PublicItem0)
+ self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1),
+ ProtectedEnumClass.PublicItem1)
+
+ self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0),
+ ProtectedEnumClass.PublicItem0)
+ self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1),
+ ProtectedEnumClass.PublicItem1)
+
+ def testOverriddenProtectedMethodWithProtectedEnumArgument(self):
+ '''Calls overridden protected method with protected enum argument.'''
+ obj = ExtendedProtectedEnumClass()
+
+ self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0),
+ ProtectedEnumClass.ProtectedItem1)
+ self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1),
+ ProtectedEnumClass.ProtectedItem0)
+
+ self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj, ProtectedEnumClass.ProtectedItem0), # noqa: E501
+ ProtectedEnumClass.ProtectedItem0)
+ self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj,
+ ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1)
+
+ self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0),
+ ProtectedEnumClass.ProtectedItem1)
+ self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1),
+ ProtectedEnumClass.ProtectedItem0)
+
+ def testOverriddenProtectedMethodWithPublicEnumArgument(self):
+ '''Calls overridden protected method with public enum argument.'''
+ obj = ExtendedProtectedEnumClass()
+
+ self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0),
+ ProtectedEnumClass.PublicItem1)
+ self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1),
+ ProtectedEnumClass.PublicItem0)
+
+ self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem0),
+ ProtectedEnumClass.PublicItem0)
+ self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem1),
+ ProtectedEnumClass.PublicItem1)
+
+ self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0),
+ ProtectedEnumClass.PublicItem1)
+ self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1),
+ ProtectedEnumClass.PublicItem0)
+
+
+class ProtectedPropertyTest(unittest.TestCase):
+ '''Test cases for a class with a protected property (or field in C++).'''
+
+ def setUp(self):
+ self.obj = ProtectedProperty()
+
+ def tearDown(self):
+ del self.obj
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(cacheSize(), 0)
+
+ def testProtectedProperty(self):
+ '''Writes and reads a protected integer property.'''
+ self.obj.protectedProperty = 3
+ self.assertEqual(self.obj.protectedProperty, 3)
+
+ def testProtectedContainerProperty(self):
+ '''Writes and reads a protected list of integers property.'''
+ lst = [1, 2, 3, 4]
+ self.obj.protectedContainerProperty = lst
+ self.assertEqual(self.obj.protectedContainerProperty, lst)
+
+ def testProtectedEnumProperty(self):
+ '''Writes and reads a protected enum property.'''
+ self.obj.protectedEnumProperty = Event.SOME_EVENT
+ self.assertEqual(self.obj.protectedEnumProperty, Event.SOME_EVENT)
+
+ def testProtectedValueTypeProperty(self):
+ '''Writes and reads a protected value type property.'''
+ point = Point(12, 34)
+ self.obj.protectedValueTypeProperty = point
+ self.assertEqual(self.obj.protectedValueTypeProperty, point)
+ self.assertFalse(self.obj.protectedValueTypeProperty is point)
+ pointProperty = self.obj.protectedValueTypeProperty
+ self.assertTrue(self.obj.protectedValueTypeProperty is pointProperty)
+
+ def testProtectedValueTypePropertyWrapperRegistration(self):
+ '''Access colocated protected value type property.'''
+ cache_size = cacheSize()
+ point = Point(12, 34)
+ obj = createProtectedProperty()
+ obj.protectedValueTypeProperty
+ self.assertEqual(obj.protectedValueTypeProperty.copy(),
+ obj.protectedValueTypeProperty)
+ obj.protectedValueTypeProperty = point
+ self.assertEqual(obj.protectedValueTypeProperty, point)
+ self.assertFalse(obj.protectedValueTypeProperty is point)
+ pointProperty = obj.protectedValueTypeProperty
+ self.assertTrue(obj.protectedValueTypeProperty is pointProperty)
+ del obj, point, pointProperty
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(cacheSize(), cache_size)
+
+ def testProtectedValueTypePointerProperty(self):
+ '''Writes and reads a protected value type pointer property.'''
+ pt1 = Point(12, 34)
+ pt2 = Point(12, 34)
+ self.obj.protectedValueTypePointerProperty = pt1
+ self.assertEqual(self.obj.protectedValueTypePointerProperty, pt1)
+ self.assertEqual(self.obj.protectedValueTypePointerProperty, pt2)
+ self.assertTrue(self.obj.protectedValueTypePointerProperty is pt1)
+ self.assertFalse(self.obj.protectedValueTypePointerProperty is pt2)
+ # PYSIDE-535: Need to assign None to break the cycle
+ self.obj.protectedValueTypePointerProperty = None
+
+ def testProtectedObjectTypeProperty(self):
+ '''Writes and reads a protected object type property.'''
+ obj = ObjectType()
+ self.obj.protectedObjectTypeProperty = obj
+ self.assertEqual(self.obj.protectedObjectTypeProperty, obj)
+ # PYSIDE-535: Need to assign None to break the cycle
+ self.obj.protectedObjectTypeProperty = None
+
+
+class PrivateDtorProtectedMethodTest(unittest.TestCase):
+ '''Test cases for classes with private destructors and protected methods.'''
+
+ def tearDown(self):
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(cacheSize(), 0)
+
+ def testProtectedMethod(self):
+ '''Calls protected method of a class with a private destructor.'''
+ obj = PrivateDtor.instance()
+
+ self.assertEqual(type(obj), PrivateDtor)
+ self.assertEqual(obj.instanceCalls(), 1)
+ self.assertEqual(obj.instanceCalls(), obj.protectedInstanceCalls())
+ obj = PrivateDtor.instance()
+ self.assertEqual(obj.instanceCalls(), 2)
+ self.assertEqual(obj.instanceCalls(), obj.protectedInstanceCalls())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/pstrlist_test.py b/sources/shiboken6/tests/samplebinding/pstrlist_test.py
new file mode 100644
index 000000000..d60f9cf35
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/pstrlist_test.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+import sample
+
+
+class PStrListTest(unittest.TestCase):
+
+ def testPStrList(self):
+ a = 'str0'
+ b = 'str1'
+ lst = sample.createPStrList(a, b)
+ self.assertEqual(lst, [a, b])
+
+ def testListOfPStr(self):
+ a = 'str0'
+ b = 'str1'
+ lst = sample.createListOfPStr(a, b)
+ self.assertEqual(lst, [a, b])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/pystr_test.py b/sources/shiboken6/tests/samplebinding/pystr_test.py
new file mode 100644
index 000000000..ec64c1e31
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/pystr_test.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for definition of __str__ method.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point
+
+
+class PyStrTest(unittest.TestCase):
+ '''Test case for definition of __str__ method.'''
+
+ def testPyStr(self):
+ '''Test case for defined __str__ method.'''
+ pt = Point(5, 2)
+ self.assertEqual(str(pt), 'Point(5.0, 2.0)')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/python_thread_test.py b/sources/shiboken6/tests/samplebinding/python_thread_test.py
new file mode 100644
index 000000000..65398b5c6
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/python_thread_test.py
@@ -0,0 +1,96 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#!/usr/bin/env python
+
+'''Tests for using Shiboken-based bindings with python threads'''
+
+import logging
+import os
+from random import random
+import sys
+import threading
+import time
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+import sample
+
+#logging.basicConfig(level=logging.DEBUG)
+
+
+class Producer(threading.Thread):
+ '''Producer thread'''
+
+ def __init__(self, bucket, max_runs, *args):
+ #Constructor. Receives the bucket
+ super(Producer, self).__init__(*args)
+ self.runs = 0
+ self.bucket = bucket
+ self.max_runs = max_runs
+ self.production_list = []
+
+ def run(self):
+ while self.runs < self.max_runs:
+ value = int(random() * 10) % 10
+ self.bucket.push(value)
+ self.production_list.append(value)
+ logging.debug(f'PRODUCER - pushed {value}')
+ self.runs += 1
+ #self.msleep(5)
+ time.sleep(0.01)
+
+
+class Consumer(threading.Thread):
+ '''Consumer thread'''
+ def __init__(self, bucket, max_runs, *args):
+ #Constructor. Receives the bucket
+ super(Consumer, self).__init__(*args)
+ self.runs = 0
+ self.bucket = bucket
+ self.max_runs = max_runs
+ self.consumption_list = []
+
+ def run(self):
+ while self.runs < self.max_runs:
+ if not self.bucket.empty():
+ value = self.bucket.pop()
+ self.consumption_list.append(value)
+ logging.debug(f'CONSUMER - got {value}')
+ self.runs += 1
+ else:
+ logging.debug('CONSUMER - empty bucket')
+ time.sleep(0.01)
+
+
+class ProducerConsumer(unittest.TestCase):
+ '''Basic test case for producer-consumer QThread'''
+
+ def finishCb(self):
+ #Quits the application
+ self.app.exit(0)
+
+ def testProdCon(self):
+ #QThread producer-consumer example
+ bucket = sample.Bucket()
+ prod = Producer(bucket, 10)
+ cons = Consumer(bucket, 10)
+
+ prod.start()
+ cons.start()
+
+ #QObject.connect(prod, SIGNAL('finished()'), self.finishCb)
+ #QObject.connect(cons, SIGNAL('finished()'), self.finishCb)
+
+ prod.join()
+ cons.join()
+
+ self.assertEqual(prod.production_list, cons.consumption_list)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/receive_null_cstring_test.py b/sources/shiboken6/tests/samplebinding/receive_null_cstring_test.py
new file mode 100644
index 000000000..1d19de941
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/receive_null_cstring_test.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for a function that could receive a NULL pointer in a '[const] char*' parameter.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import countCharacters
+
+
+class ReceiveNullCStringTest(unittest.TestCase):
+ '''Test case for a function that could receive a NULL pointer in a '[const] char*'
+ parameter.'''
+
+ def testBasic(self):
+ '''The test function should be working for the basic cases.'''
+ a = ''
+ b = 'abc'
+ self.assertEqual(countCharacters(a), len(a))
+ self.assertEqual(countCharacters(b), len(b))
+
+ def testReceiveNull(self):
+ '''The test function returns '-1' when receives a None value instead of a string.'''
+ self.assertEqual(countCharacters(None), -1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/reference_test.py b/sources/shiboken6/tests/samplebinding/reference_test.py
new file mode 100644
index 000000000..1b6dd3a7a
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/reference_test.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for methods that receive references to objects.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Reference, Str
+
+
+class ExtendedReference(Reference):
+ def __init__(self):
+ Reference.__init__(self)
+ self.uses_reference_virtual_called = False
+ self.uses_const_reference_virtual_called = False
+ self.reference_inc = 1
+ self.const_reference_inc = 2
+ self.multiplier = 333
+
+ def usesReferenceVirtual(self, ref, inc):
+ self.uses_reference_virtual_called = True
+ return ref.objId() + inc + self.reference_inc
+
+ def usesConstReferenceVirtual(self, ref, inc):
+ self.uses_const_reference_virtual_called = True
+ return ref.objId() + inc + self.const_reference_inc
+
+ def alterReferenceIdVirtual(self, ref):
+ ref.setObjId(ref.objId() * self.multiplier)
+
+
+class ReferenceTest(unittest.TestCase):
+ '''Test case for methods that receive references to objects.'''
+
+ def testMethodThatReceivesReference(self):
+ '''Test a method that receives a reference to an object as argument.'''
+ objId = 123
+ r = Reference(objId)
+ self.assertEqual(Reference.usesReference(r), objId)
+
+ def testCantSegFaultWhenReceiveNone(self):
+ '''do not segfault when receiving None as argument.'''
+ s = Str()
+ self.assertFalse(bool(s))
+
+ def testMethodThatReceivesConstReference(self):
+ '''Test a method that receives a const reference to an object as argument.'''
+ objId = 123
+ r = Reference(objId)
+ self.assertEqual(Reference.usesConstReference(r), objId)
+
+ def testModificationOfReference(self):
+ '''Tests if the identity of a reference argument is preserved when passing
+ it to be altered in C++.'''
+ objId = 123
+ r1 = Reference(objId)
+ r1.alterReferenceIdVirtual(r1)
+ self.assertEqual(r1.objId(), objId * Reference.multiplier())
+
+ def testModificationOfReferenceCallingAVirtualIndirectly(self):
+ '''Tests if the identity of a reference argument is preserved when passing it
+ to be altered in C++ through a method that calls a virtual method.'''
+ objId = 123
+ r1 = Reference(objId)
+ r1.callAlterReferenceIdVirtual(r1)
+ self.assertEqual(r1.objId(), objId * Reference.multiplier())
+
+ def testModificationOfReferenceCallingAReimplementedVirtualIndirectly(self):
+ '''Test if a Python override of a virtual method with a reference parameter
+ called from C++ alters the argument properly.'''
+ objId = 123
+ r = Reference(objId)
+ er = ExtendedReference()
+ result = er.callAlterReferenceIdVirtual(r) # noqa: F841
+ self.assertEqual(r.objId(), objId * er.multiplier)
+
+ def testReimplementedVirtualMethodCallWithReferenceParameter(self):
+ '''Test if a Python override of a virtual method with a reference parameter
+ is correctly called from C++.'''
+ inc = 9
+ objId = 123
+ r = Reference(objId)
+ er = ExtendedReference()
+ result = er.callUsesReferenceVirtual(r, inc)
+ self.assertEqual(result, objId + inc + er.reference_inc)
+
+ def testReimplementedVirtualMethodCallWithConstReferenceParameter(self):
+ '''Test if a Python override of a virtual method with a const reference
+ parameter is correctly called from C++.'''
+ inc = 9
+ objId = 123
+ r = Reference(objId)
+ er = ExtendedReference()
+ result = er.callUsesConstReferenceVirtual(r, inc)
+ self.assertEqual(result, objId + inc + er.const_reference_inc)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/referencetopointer_test.py b/sources/shiboken6/tests/samplebinding/referencetopointer_test.py
new file mode 100644
index 000000000..942c7ea29
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/referencetopointer_test.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for a reference to pointer argument type.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import VirtualMethods, Str
+
+
+class ExtendedVirtualMethods(VirtualMethods):
+ def __init__(self):
+ VirtualMethods.__init__(self)
+ self.prefix = 'Ext'
+
+ def createStr(self, text):
+ ext_text = text
+ if text is not None:
+ ext_text = self.prefix + text
+ return VirtualMethods.createStr(self, ext_text)
+
+
+class ReferenceToPointerTest(unittest.TestCase):
+ '''Test cases for a reference to pointer argument type.'''
+
+ def testSimpleCallWithNone(self):
+ '''Simple call to createStr method with a None argument.'''
+ obj = VirtualMethods()
+ ok, string = obj.createStr(None)
+ self.assertFalse(ok)
+ self.assertEqual(string, None)
+
+ def testSimpleCallWithString(self):
+ '''Simple call to createStr method with a Python string argument.'''
+ obj = VirtualMethods()
+ ok, string = obj.createStr('foo')
+ self.assertTrue(ok)
+ self.assertEqual(string, Str('foo'))
+
+ def testCallNonReimplementedMethodWithNone(self):
+ '''Calls createStr method from C++ with a None argument.'''
+ obj = VirtualMethods()
+ ok, string = obj.callCreateStr(None)
+ self.assertFalse(ok)
+ self.assertEqual(string, None)
+
+ def testCallNonReimplementedMethodWithString(self):
+ '''Calls createStr method from C++ with a Python string argument.'''
+ obj = VirtualMethods()
+ ok, string = obj.callCreateStr('foo')
+ self.assertTrue(ok)
+ self.assertEqual(string, Str('foo'))
+
+ def testCallReimplementedMethodWithNone(self):
+ '''Calls reimplemented createStr method from C++ with a None argument.'''
+ obj = ExtendedVirtualMethods()
+ ok, string = obj.callCreateStr(None)
+ self.assertFalse(ok)
+ self.assertEqual(string, None)
+
+ def testCallReimplementedMethodWithString(self):
+ '''Calls reimplemented createStr method from C++ with a Python string argument.'''
+ obj = ExtendedVirtualMethods()
+ ok, string = obj.callCreateStr('foo')
+ self.assertTrue(ok)
+ self.assertEqual(string, Str(obj.prefix + 'foo'))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/renaming_test.py b/sources/shiboken6/tests/samplebinding/renaming_test.py
new file mode 100644
index 000000000..b08438ef3
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/renaming_test.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for renaming using target-lang-name attribute.'''
+
+import os
+import re
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import RenamedValue, RenamedUser
+
+from shibokensupport.signature import get_signature
+
+
+class RenamingTest(unittest.TestCase):
+ def test(self):
+ '''Tests whether the C++ class ToBeRenamedValue renamed via attribute
+ target-lang-name to RenamedValue shows up in consuming function
+ signature strings correctly.
+ '''
+ renamed_value = RenamedValue()
+ self.assertEqual(str(type(renamed_value)),
+ "<class 'sample.RenamedValue'>")
+ rename_user = RenamedUser()
+ rename_user.useRenamedValue(renamed_value)
+ actual_signature = str(get_signature(rename_user.useRenamedValue))
+ self.assertTrue(re.match(r"^\(self,\s*?v:\s*?sample.RenamedValue\)\s*?->\s*?None$",
+ actual_signature))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/return_null_test.py b/sources/shiboken6/tests/samplebinding/return_null_test.py
new file mode 100644
index 000000000..2c4f07c65
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/return_null_test.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for functions that could return a NULL pointer.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import (returnNullPrimitivePointer, returnNullValueTypePointer,
+ returnNullObjectTypePointer)
+
+
+class ReturnNullTest(unittest.TestCase):
+ '''Test case for functions that could return a NULL pointer.'''
+
+ def testReturnNull(self):
+ '''Function returns a NULL pointer to a primitive type.'''
+ o = returnNullPrimitivePointer()
+ self.assertEqual(o, None)
+
+ def testReturnNullObjectType(self):
+ '''Function returns a NULL pointer to an object-type.'''
+ o = returnNullObjectTypePointer()
+ self.assertEqual(o, None)
+
+ def testReturnNullValueType(self):
+ '''Function returns a NULL pointer to a value-type.'''
+ o = returnNullValueTypePointer()
+ self.assertEqual(o, None)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/richcompare_test.py b/sources/shiboken6/tests/samplebinding/richcompare_test.py
new file mode 100644
index 000000000..3146d0faf
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/richcompare_test.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Expression
+
+
+class TestRichCompare(unittest.TestCase):
+
+ def testIt(self):
+ a = Expression(2)
+ b = Expression(3)
+ c = a + b
+ d = a + c < b + a
+ self.assertEqual(d.toString(), "((2+(2+3))<(3+2))")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/sample-binding.txt.in b/sources/shiboken6/tests/samplebinding/sample-binding.txt.in
new file mode 100644
index 000000000..bcf9de90f
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/sample-binding.txt.in
@@ -0,0 +1,16 @@
+[generator-project]
+
+generator-set = shiboken
+
+header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h
+typesystem-file = @sample_TYPESYSTEM@
+
+output-directory = @CMAKE_CURRENT_BINARY_DIR@
+
+include-path = @libsample_SOURCE_DIR@
+
+typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@
+
+enable-parent-ctor-heuristic
+use-isnull-as-nb_nonzero
+lean-headers
diff --git a/sources/shiboken6/tests/samplebinding/sample_test.py b/sources/shiboken6/tests/samplebinding/sample_test.py
new file mode 100644
index 000000000..19b2f708d
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/sample_test.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for libsample bindings module'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+import sample
+
+
+class ModuleTest(unittest.TestCase):
+ '''Test case for module and global functions'''
+
+ def testAddedFunctionAtModuleLevel(self):
+ '''Calls function added to module from type system description.'''
+ str1 = 'Foo'
+ self.assertEqual(sample.multiplyString(str1, 3), str1 * 3)
+ self.assertEqual(sample.multiplyString(str1, 0), str1 * 0)
+
+ def testAddedFunctionWithVarargs(self):
+ '''Calls function that receives varargs added to module from type system description.'''
+ self.assertEqual(sample.countVarargs(1), 0)
+ self.assertEqual(sample.countVarargs(1, 2), 1)
+ self.assertEqual(sample.countVarargs(1, 2, 3, 'a', 'b', 4, (5, 6)), 6)
+
+ def testSampleComparisonOpInNamespace(self):
+ s1 = sample.sample.sample(10)
+ s2 = sample.sample.sample(10)
+ self.assertEqual(s1, s2)
+
+ def testConstant(self):
+ self.assertEqual(sample.sample.INT_CONSTANT, 42)
+
+ def testStringFunctions(self):
+ # Test plain ASCII, UCS1 and UCS4 encoding which have different
+ # representations in the PyUnicode objects.
+ for t1 in ["ascii", "Ümläut", "😀"]:
+ expected = t1 + t1
+ self.assertEqual(sample.addStdStrings(t1, t1), expected)
+ self.assertEqual(sample.addStdWStrings(t1, t1), expected)
+
+ def testNullPtrT(self):
+ sample.testNullPtrT(None)
+ self.assertRaises(TypeError, sample.testNullPtrT, 42)
+
+ def testRValueRefsWithValueTypes(self):
+ """Passing value types by rvalue refs: For value types, nothing should
+ happen since the argument is copied in the call and the copy is
+ moved from."""
+ polygon = sample.Polygon()
+ polygon.addPoint(sample.Point(1, 2))
+ polygon.addPoint(sample.Point(3, 4))
+ point_count = len(polygon.points())
+ self.assertEqual(point_count, sample.takePolygon(polygon))
+
+ def testRValueRefsWithObjectTypes(self):
+ """Passing object types by rvalue refs: The underlying object should
+ be moved from."""
+ o = sample.ObjectType()
+ object_name = "Name"
+ o.setObjectName(object_name)
+ self.assertEqual(len(object_name), sample.takeObjectType(o))
+ # o should be moved from, name is now empty
+ self.assertEqual(len(o.objectName()), 0)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/samplebinding.pyproject b/sources/shiboken6/tests/samplebinding/samplebinding.pyproject
new file mode 100644
index 000000000..ba6ba6f8f
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/samplebinding.pyproject
@@ -0,0 +1,131 @@
+{
+ "files": ["__del___test.py",
+ "abstract_test.py",
+ "addedfunction_test.py",
+ "addedfunction_with_container_args_test.py",
+ "argumentmodifications_test.py",
+ "array_numpy_test.py",
+ "array_sequence_test.py",
+ "bug_554_test.py",
+ "bug_704_test.py",
+ "bytearray_test.py",
+ "child_return_test.py",
+ "class_fields_test.py",
+ "collector_test.py",
+ "complex_test.py",
+ "conversion_operator_test.py",
+ "copy_test.py",
+ "ctorconvrule_test.py",
+ "cyclic_test.py",
+ "date_test.py",
+ "decisor_test.py",
+ "delete_test.py",
+ "deprecated_test.py",
+ "derived_test.py",
+ "duck_punching_test.py",
+ "echo_test.py",
+ "enum_test.py",
+ "enumfromremovednamespace_test.py",
+ "event_loop_call_virtual_test.py",
+ "event_loop_thread_test.py",
+ "exception_test.py",
+ "filter_test.py",
+ "handleholder_test.py",
+ "hashabletype_test.py",
+ "ignorederefop_test.py",
+ "implicitconv_numerical_test.py",
+ "implicitconv_test.py",
+ "inheritanceandscope_test.py",
+ "injectcode_test.py",
+ "innerclass_test.py",
+ "intlist_test.py",
+ "intwrapper_test.py",
+ "invalid_virtual_return_test.py",
+ "keep_reference_test.py",
+ "list_test.py",
+ "lock_test.py",
+ "map_test.py",
+ "metaclass_test.py",
+ "mi_virtual_methods_test.py",
+ "mixed_mi_test.py",
+ "modelindex_test.py",
+ "modelview_test.py",
+ "modifications_test.py",
+ "modified_constructor_test.py",
+ "modifiedvirtualmethods_test.py",
+ "multi_cpp_inheritance_test.py",
+ "multiple_derived_test.py",
+ "namespace_test.py",
+ "newdivision_test.py",
+ "nondefaultctor_test.py",
+ "nontypetemplate_test.py",
+ "nonzero_test.py",
+ "numericaltypedef_test.py",
+ "numpy_test.py",
+ "objecttype_test.py",
+ "objecttype_with_named_args_test.py",
+ "objecttypebyvalue_test.py",
+ "objecttypelayout_test.py",
+ "objecttypeoperators_test.py",
+ "objecttypereferenceasvirtualmethodargument_test.py",
+ "oddbool_test.py",
+ "onlycopyclass_test.py",
+ "overflow_test.py",
+ "overload_sorting_test.py",
+ "overload_test.py",
+ "overloadwithdefault_test.py",
+ "ownership_argument_invalidation_test.py",
+ "ownership_delete_child_in_cpp_test.py",
+ "ownership_delete_child_in_python_test.py",
+ "ownership_delete_parent_test.py",
+ "ownership_invalidate_after_use_test.py",
+ "ownership_invalidate_child_test.py",
+ "ownership_invalidate_nonpolymorphic_test.py",
+ "ownership_invalidate_parent_test.py",
+ "ownership_reparenting_test.py",
+ "ownership_transference_test.py",
+ "pair_test.py",
+ "pen_test.py",
+ "point_test.py",
+ "pointerholder_test.py",
+ "pointerprimitivetype_test.py",
+ "pointf_test.py",
+ "primitivereferenceargument_test.py",
+ "privatector_test.py",
+ "privatedtor_test.py",
+ "protected_test.py",
+ "pstrlist_test.py",
+ "pystr_test.py",
+ "python_thread_test.py",
+ "receive_null_cstring_test.py",
+ "reference_test.py",
+ "referencetopointer_test.py",
+ "renaming_test.py",
+ "return_null_test.py",
+ "richcompare_test.py",
+ "sample_test.py",
+ "samplesnippets.cpp",
+ "simplefile_glue.cpp",
+ "simplefile_test.py",
+ "size_test.py",
+ "snakecase_test.py",
+ "static_nonstatic_methods_test.py",
+ "str_test.py",
+ "strlist_test.py",
+ "templateinheritingclass_test.py",
+ "time_test.py",
+ "transform_test.py",
+ "typeconverters_test.py",
+ "typedealloc_test.py",
+ "typedtordoublefree_test.py",
+ "typesystypedef_test.py",
+ "unsafe_parent_test.py",
+ "useraddedctor_test.py",
+ "virtualdtor_test.py",
+ "virtualmethods_test.py",
+ "visibilitychange_test.py",
+ "voidholder_test.py",
+ "weakref_test.py",
+ "writableclassdict_test.py",
+ "typesystem_sample.xml"]
+}
diff --git a/sources/shiboken6/tests/samplebinding/samplesnippets.cpp b/sources/shiboken6/tests/samplebinding/samplesnippets.cpp
new file mode 100644
index 000000000..43e6b08de
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/samplesnippets.cpp
@@ -0,0 +1,54 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+// @snippet intwrapper_add_ints
+extern "C" {
+static PyObject *Sbk_IntWrapper_add_ints(PyObject * /* self */, PyObject *args)
+{
+ PyObject *result = nullptr;
+ if (PyTuple_Check(args) != 0 && PyTuple_Size(args) == 2) {
+ PyObject *arg1 = PyTuple_GetItem(args, 0);
+ PyObject *arg2 = PyTuple_GetItem(args, 1);
+ if (PyLong_Check(arg1) != 0 && PyLong_Check(arg2) != 0)
+ result = PyLong_FromLong(PyLong_AsLong(arg1) + PyLong_AsLong(arg2));
+ }
+ if (result == nullptr)
+ PyErr_SetString(PyExc_TypeError, "expecting 2 ints");
+ return result;
+}
+}
+// @snippet intwrapper_add_ints
+
+// @snippet stdcomplex_floor
+%PYARG_0 = PyFloat_FromDouble(std::floor(%CPPSELF.abs_value()));
+// @snippet stdcomplex_floor
+
+// @snippet stdcomplex_ceil
+%PYARG_0 = PyFloat_FromDouble(std::ceil(%CPPSELF.abs_value()));
+// @snippet stdcomplex_ceil
+
+// @snippet stdcomplex_abs
+%PYARG_0 = PyFloat_FromDouble(%CPPSELF.abs_value());
+// @snippet stdcomplex_abs
+
+// @snippet stdcomplex_pow
+%RETURN_TYPE %0 = %CPPSELF.pow(%1);
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+// @snippet stdcomplex_pow
+
+// @snippet size_char_ct
+// Convert a string "{width}x{height}" specification
+{
+ double width = -1;
+ double height = -1;
+ const std::string s = %1;
+ const auto pos = s.find('x');
+ if (pos != std::string::npos) {
+ std::istringstream wstr(s.substr(0, pos));
+ wstr >> width;
+ std::istringstream hstr(s.substr(pos + 1, s.size() - pos - 1));
+ hstr >> height;
+ }
+ %0 = new %TYPE(width, height);
+}
+// @snippet size_char_ct
diff --git a/sources/shiboken6/tests/samplebinding/simplefile_glue.cpp b/sources/shiboken6/tests/samplebinding/simplefile_glue.cpp
new file mode 100644
index 000000000..76c0cfaf2
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/simplefile_glue.cpp
@@ -0,0 +1,9 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+if (!%CPPSELF.%FUNCTION_NAME()) {
+ PyObject* error_msg = PyBytes_FromFormat(
+ "Could not open file: \"%s\"", %CPPSELF->filename());
+ PyErr_SetObject(PyExc_IOError, error_msg);
+ return 0;
+}
diff --git a/sources/shiboken6/tests/samplebinding/simplefile_test.py b/sources/shiboken6/tests/samplebinding/simplefile_test.py
new file mode 100644
index 000000000..55c894a35
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/simplefile_test.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for SimpleFile class'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import SimpleFile
+
+
+class SimpleFileTest(unittest.TestCase):
+ '''Test cases for SimpleFile class.'''
+
+ def setUp(self):
+ filename = f'simplefile{os.getpid()}.txt'
+ self.existing_filename = Path(os.curdir) / filename
+ self.delete_file = False
+ if not self.existing_filename.exists():
+ with self.existing_filename.open('w') as f:
+ for line in range(10):
+ f.write('sbrubbles\n')
+ self.delete_file = True
+
+ self.non_existing_filename = Path(os.curdir) / 'inexistingfile.txt'
+ i = 0
+ while self.non_existing_filename.exists():
+ i += 1
+ filename = f'inexistingfile-{i}.txt'
+ self.non_existing_filename = Path(os.curdir) / filename
+
+ def tearDown(self):
+ if self.delete_file:
+ os.remove(self.existing_filename)
+
+ def testExistingFile(self):
+ '''Test SimpleFile class with existing file.'''
+ f = SimpleFile(os.fspath(self.existing_filename))
+ self.assertEqual(f.filename(), os.fspath(self.existing_filename))
+ f.open()
+ self.assertNotEqual(f.size(), 0)
+ f.close()
+
+ def testNonExistingFile(self):
+ '''Test SimpleFile class with non-existing file.'''
+ f = SimpleFile(os.fspath(self.non_existing_filename))
+ self.assertEqual(f.filename(), os.fspath(self.non_existing_filename))
+ self.assertRaises(IOError, f.open)
+ self.assertEqual(f.size(), 0)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/size_test.py b/sources/shiboken6/tests/samplebinding/size_test.py
new file mode 100644
index 000000000..069ce59b3
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/size_test.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for operator overloads on Size class'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Size
+
+
+class PointTest(unittest.TestCase):
+ '''Test case for Size class, including operator overloads.'''
+
+ def testConstructor(self):
+ '''Test Size class constructor.'''
+ width, height = (5.0, 2.3)
+ size = Size(width, height)
+ self.assertEqual(size.width(), width)
+ self.assertEqual(size.height(), height)
+ self.assertEqual(size.calculateArea(), width * height)
+
+ def testCopyConstructor(self):
+ '''Test Size class copy constructor.'''
+ width, height = (5.0, 2.3)
+ s1 = Size(width, height)
+ s2 = Size(s1)
+ self.assertFalse(s1 is s2)
+ self.assertEqual(s1, s2)
+
+ def testPlusOperator(self):
+ '''Test Size class + operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(0.5, 3.2)
+ self.assertEqual(s1 + s2, Size(5.0 + 0.5, 2.3 + 3.2))
+
+ def testEqualOperator(self):
+ '''Test Size class == operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(5.0, 2.3)
+ s3 = Size(0.5, 3.2)
+ self.assertTrue(s1 == s1)
+ self.assertTrue(s1 == s2)
+ self.assertFalse(s1 == s3)
+
+ def testNotEqualOperator(self):
+ '''Test Size class != operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(5.0, 2.3)
+ s3 = Size(0.5, 3.2)
+ self.assertFalse(s1 != s1)
+ self.assertFalse(s1 != s2)
+ self.assertTrue(s1 != s3)
+
+ def testMinorEqualOperator(self):
+ '''Test Size class <= operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(5.0, 2.3)
+ s3 = Size(0.5, 3.2)
+ self.assertTrue(s1 <= s1)
+ self.assertTrue(s1 <= s2)
+ self.assertTrue(s3 <= s1)
+ self.assertFalse(s1 <= s3)
+
+ def testMinorOperator(self):
+ '''Test Size class < operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(0.5, 3.2)
+ self.assertFalse(s1 < s1)
+ self.assertFalse(s1 < s2)
+ self.assertTrue(s2 < s1)
+
+ def testMajorEqualOperator(self):
+ '''Test Size class >= operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(5.0, 2.3)
+ s3 = Size(0.5, 3.2)
+ self.assertTrue(s1 >= s1)
+ self.assertTrue(s1 >= s2)
+ self.assertTrue(s1 >= s3)
+ self.assertFalse(s3 >= s1)
+
+ def testMajorOperator(self):
+ '''Test Size class > operator.'''
+ s1 = Size(5.0, 2.3)
+ s2 = Size(0.5, 3.2)
+ self.assertFalse(s1 > s1)
+ self.assertTrue(s1 > s2)
+ self.assertFalse(s2 > s1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/snakecase_test.py b/sources/shiboken6/tests/samplebinding/snakecase_test.py
new file mode 100644
index 000000000..a1538796a
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/snakecase_test.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for snake case generation'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import (SnakeCaseTest, SnakeCaseDerivedTest,
+ snake_case_global_function)
+
+
+class OverrideTest(SnakeCaseDerivedTest):
+ def virtual_func(self):
+ return 4711
+
+
+class SnakeCaseTestCase(unittest.TestCase):
+ '''Test for SnakeCaseTest'''
+ def testMemberFunctions(self):
+ s = SnakeCaseTest()
+ self.assertEqual(s.test_function1(), 42)
+
+ self.assertEqual(s.testFunctionDisabled(), 42)
+
+ self.assertEqual(s.testFunctionBoth(), 42)
+ self.assertEqual(s.test_function_both(), 42)
+
+ def virtualFunctions(self):
+ s = OverrideTest()
+ self.assertEqual(s.call_virtual_func(), 4711)
+
+ def testMemberFields(self):
+ s = SnakeCaseTest()
+ old_value = s.test_field
+ s.test_field = old_value + 1
+ self.assertEqual(s.test_field, old_value + 1)
+
+ old_value = s.testFieldDisabled
+ s.testFieldDisabled = old_value + 1
+ self.assertEqual(s.testFieldDisabled, old_value + 1)
+
+ old_value = s.test_field_both
+ s.test_field_both = old_value + 1
+ self.assertEqual(s.test_field_both, old_value + 1)
+ self.assertEqual(s.testFieldBoth, old_value + 1)
+
+ def testGlobalFunction(self):
+ self.assertEqual(snake_case_global_function(), 42)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/static_nonstatic_methods_test.py b/sources/shiboken6/tests/samplebinding/static_nonstatic_methods_test.py
new file mode 100644
index 000000000..cf0889299
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/static_nonstatic_methods_test.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for overloads involving static and non-static versions of a method.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import SimpleFile
+
+
+class SimpleFile2 (SimpleFile):
+ def exists(self):
+ return "Mooo"
+
+
+class SimpleFile3 (SimpleFile):
+ pass
+
+
+class SimpleFile4 (SimpleFile):
+ exists = 5
+
+
+class StaticNonStaticMethodsTest(unittest.TestCase):
+ '''Test cases for overloads involving static and non-static versions of a method.'''
+
+ def setUp(self):
+ filename = f'simplefile{os.getpid()}.txt'
+ self.existing_filename = Path(filename)
+ self.delete_file = False
+ if not self.existing_filename.exists():
+ with self.existing_filename.open('w') as f:
+ for line in range(10):
+ f.write('sbrubbles\n')
+ self.delete_file = True
+
+ self.non_existing_filename = Path('inexistingfile.txt')
+ i = 0
+ while self.non_existing_filename.exists():
+ i += 1
+ filename = 'inexistingfile-{i}.txt'
+ self.non_existing_filename = Path(filename)
+
+ def tearDown(self):
+ if self.delete_file:
+ os.remove(self.existing_filename)
+
+ def testCallingStaticMethodWithClass(self):
+ '''Call static method using class.'''
+ self.assertTrue(SimpleFile.exists(os.fspath(self.existing_filename)))
+ self.assertFalse(SimpleFile.exists(os.fspath(self.non_existing_filename)))
+
+ def testCallingStaticMethodWithInstance(self):
+ '''Call static method using instance of class.'''
+ f = SimpleFile(os.fspath(self.non_existing_filename))
+ self.assertTrue(f.exists(os.fspath(self.existing_filename)))
+ self.assertFalse(f.exists(os.fspath(self.non_existing_filename)))
+
+ def testCallingInstanceMethod(self):
+ '''Call instance method.'''
+ f1 = SimpleFile(os.fspath(self.non_existing_filename))
+ self.assertFalse(f1.exists())
+ f2 = SimpleFile(os.fspath(self.existing_filename))
+ self.assertTrue(f2.exists())
+
+ def testOverridingStaticNonStaticMethod(self):
+ f = SimpleFile2(os.fspath(self.existing_filename))
+ self.assertEqual(f.exists(), "Mooo")
+
+ f = SimpleFile3(os.fspath(self.existing_filename))
+ self.assertTrue(f.exists())
+
+ f = SimpleFile4(os.fspath(self.existing_filename))
+ self.assertEqual(f.exists, 5)
+
+ def testDuckPunchingStaticNonStaticMethod(self):
+ f = SimpleFile(os.fspath(self.existing_filename))
+ f.exists = lambda: "Meee"
+ self.assertEqual(f.exists(), "Meee")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/stdcomplex_test.py b/sources/shiboken6/tests/samplebinding/stdcomplex_test.py
new file mode 100644
index 000000000..0caa9764d
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/stdcomplex_test.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for StdComplex class'''
+
+import os
+import math
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import StdComplex
+
+
+REAL = 5.0
+IMAG = 2.3
+
+
+class StdComplexTest(unittest.TestCase):
+ '''Test case for StdComplex class, exercising esoteric number
+ protocols (Py_nb_). For standard number protocols, see Point.'''
+
+ def testConversion(self):
+ pt = StdComplex(REAL, IMAG)
+ self.assertEqual(int(pt), int(round(pt.abs_value())))
+ self.assertEqual(float(pt), pt.abs_value())
+
+ def testAbs(self):
+ pt = StdComplex(REAL, IMAG)
+ self.assertEqual(abs(pt), pt.abs_value())
+
+ def testPow(self):
+ '''Compare pow() function to builtin Python type.'''
+ pt = StdComplex(REAL, IMAG)
+ result = pow(pt, StdComplex(2.0, 0))
+ py_pt = complex(REAL, IMAG)
+ py_result = pow(py_pt, complex(2.0, 0))
+ self.assertAlmostEqual(result.real(), py_result.real)
+ self.assertAlmostEqual(result.imag(), py_result.imag)
+
+ def testFloor(self):
+ pt = StdComplex(REAL, IMAG)
+ self.assertEqual(math.floor(pt), math.floor(pt.abs_value()))
+
+ def testCeil(self):
+ pt = StdComplex(REAL, IMAG)
+ self.assertEqual(math.ceil(pt), math.ceil(pt.abs_value()))
+
+ def testPlusOperator(self):
+ '''Test StdComplex class + operator.'''
+ pt1 = StdComplex(REAL, IMAG)
+ pt2 = StdComplex(0.5, 3.2)
+ self.assertEqual(pt1 + pt2, StdComplex(REAL + 0.5, IMAG + 3.2))
+
+ def testEqualOperator(self):
+ '''Test StdComplex class == operator.'''
+ pt1 = StdComplex(REAL, IMAG)
+ pt2 = StdComplex(REAL, IMAG)
+ pt3 = StdComplex(0.5, 3.2)
+ self.assertTrue(pt1 == pt1)
+ self.assertTrue(pt1 == pt2)
+ self.assertFalse(pt1 == pt3)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/str_test.py b/sources/shiboken6/tests/samplebinding/str_test.py
new file mode 100644
index 000000000..c06fd6428
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/str_test.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for a method that receives a reference to class that is implicitly
+ convertible from a Python native type.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Str
+
+
+class StrTest(unittest.TestCase):
+ '''Test cases for thr Str class.'''
+
+ def test__str__Method(self):
+ '''Test if the binding correcly implements the Python __str__ method.'''
+ s1 = 'original string'
+ s2 = Str(s1)
+ self.assertEqual(s1, s2)
+ self.assertEqual(s1, str(s2))
+
+ def testPassExactClassAsReferenceToArgument(self):
+ '''Test passing the expected class as an argument to a method that expects a reference.'''
+ s1 = Str('This is %VAR!').arg(Str('Sparta'))
+ self.assertEqual(str(s1), 'This is Sparta!')
+
+ def testPassPythonTypeImplictlyConvertibleToAClassUsedAsReference(self):
+ '''Test passing a Python class implicitly convertible to a wrapped class
+ that is expected to be passed as reference.'''
+ s1 = Str('This is %VAR!').arg('Athens')
+ self.assertEqual(str(s1), 'This is Athens!')
+
+ def testSequenceOperators(self):
+ s1 = Str("abcdef")
+ self.assertEqual(len(s1), 6)
+ self.assertEqual(len(Str()), 0)
+
+ # getitem
+ self.assertEqual(s1[0], "a")
+ self.assertEqual(s1[1], "b")
+ self.assertEqual(s1[2], "c")
+ self.assertEqual(s1[3], "d")
+ self.assertEqual(s1[4], "e")
+ self.assertEqual(s1[5], "f")
+ self.assertEqual(s1[-1], "f")
+ self.assertEqual(s1[-2], "e")
+
+ self.assertRaises(TypeError, s1.__getitem__, 6)
+
+ # setitem
+ s1[0] = 'A'
+ s1[1] = 'B'
+ self.assertEqual(s1[0], 'A')
+ self.assertEqual(s1[1], 'B')
+ self.assertRaises(TypeError, s1.__setitem__(6, 67))
+
+ def testReverseOperator(self):
+ s1 = Str("hello")
+ self.assertEqual(s1 + 2, "hello2")
+ self.assertEqual(2 + s1, "2hello")
+
+ def testToIntError(self):
+ self.assertEqual(Str('Z').toInt(), (0, False))
+
+ def testToIntWithDecimal(self):
+ decimal = Str('37')
+ val, ok = decimal.toInt()
+ self.assertEqual(type(val), int)
+ self.assertEqual(type(ok), bool)
+ self.assertEqual(val, int(str(decimal)))
+
+ def testToIntWithOctal(self):
+ octal = Str('52')
+ val, ok = octal.toInt(8)
+ self.assertEqual(type(val), int)
+ self.assertEqual(type(ok), bool)
+ self.assertEqual(val, int(str(octal), 8))
+
+ def testToIntWithHexadecimal(self):
+ hexa = Str('2A')
+ val, ok = hexa.toInt(16)
+ self.assertEqual(type(val), int)
+ self.assertEqual(type(ok), bool)
+ self.assertEqual(val, int(str(hexa), 16))
+ self.assertEqual(hexa.toInt(), (0, False))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/strlist_test.py b/sources/shiboken6/tests/samplebinding/strlist_test.py
new file mode 100644
index 000000000..2bfb80b67
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/strlist_test.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for StrList class that inherits from std::list<Str>.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Str, StrList
+
+
+class StrListTest(unittest.TestCase):
+ '''Test cases for StrList class that inherits from std::list<Str>.'''
+
+ def testStrListCtor_NoParams(self):
+ '''StrList constructor receives no parameter.'''
+ sl = StrList()
+ self.assertEqual(len(sl), 0)
+ self.assertEqual(sl.constructorUsed(), StrList.NoParamsCtor)
+
+ def testStrListCtor_Str(self):
+ '''StrList constructor receives a Str object.'''
+ s = Str('Foo')
+ sl = StrList(s)
+ self.assertEqual(len(sl), 1)
+ self.assertEqual(sl[0], s)
+ self.assertEqual(sl.constructorUsed(), StrList.StrCtor)
+
+ def testStrListCtor_PythonString(self):
+ '''StrList constructor receives a Python string.'''
+ s = 'Foo'
+ sl = StrList(s)
+ self.assertEqual(len(sl), 1)
+ self.assertEqual(sl[0], s)
+ self.assertEqual(sl.constructorUsed(), StrList.StrCtor)
+
+ def testStrListCtor_StrList(self):
+ '''StrList constructor receives a StrList object.'''
+ sl1 = StrList(Str('Foo'))
+ sl2 = StrList(sl1)
+ #self.assertEqual(len(sl1), len(sl2))
+ #self.assertEqual(sl1, sl2)
+ self.assertEqual(sl2.constructorUsed(), StrList.CopyCtor)
+
+ def testStrListCtor_ListOfStrs(self):
+ '''StrList constructor receives a Python list of Str objects.'''
+ strs = [Str('Foo'), Str('Bar')]
+ sl = StrList(strs)
+ self.assertEqual(len(sl), len(strs))
+ self.assertEqual(sl, strs)
+ self.assertEqual(sl.constructorUsed(), StrList.ListOfStrCtor)
+
+ def testStrListCtor_MixedListOfStrsAndPythonStrings(self):
+ '''StrList constructor receives a Python list of mixed Str objects and Python strings.'''
+ strs = [Str('Foo'), 'Bar']
+ sl = StrList(strs)
+ self.assertEqual(len(sl), len(strs))
+ self.assertEqual(sl, strs)
+ self.assertEqual(sl.constructorUsed(), StrList.ListOfStrCtor)
+
+ def testCompareStrListWithTupleOfStrs(self):
+ '''Compares StrList with a Python tuple of Str objects.'''
+ sl = StrList()
+ sl.append(Str('Foo'))
+ sl.append(Str('Bar'))
+ self.assertEqual(len(sl), 2)
+ self.assertEqual(sl, (Str('Foo'), Str('Bar')))
+
+ def testCompareStrListWithTupleOfPythonStrings(self):
+ '''Compares StrList with a Python tuple of Python strings.'''
+ sl = StrList()
+ sl.append(Str('Foo'))
+ sl.append(Str('Bar'))
+ self.assertEqual(len(sl), 2)
+ self.assertEqual(sl, ('Foo', 'Bar'))
+
+ def testCompareStrListWithTupleOfStrAndPythonString(self):
+ '''Compares StrList with a Python tuple of mixed Str objects and Python strings.'''
+ sl = StrList()
+ sl.append(Str('Foo'))
+ sl.append(Str('Bar'))
+ self.assertEqual(len(sl), 2)
+ self.assertEqual(sl, (Str('Foo'), 'Bar'))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/templateinheritingclass_test.py b/sources/shiboken6/tests/samplebinding/templateinheritingclass_test.py
new file mode 100644
index 000000000..11279c7ec
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/templateinheritingclass_test.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Photon
+
+'''This tests classes that inherit from template classes,
+ simulating a situation found in Qt's phonon module.'''
+
+
+class TemplateInheritingClassTest(unittest.TestCase):
+ def testClassBasics(self):
+ self.assertEqual(Photon.ValueIdentity.classType(), Photon.IdentityType)
+ self.assertEqual(Photon.ValueDuplicator.classType(), Photon.DuplicatorType)
+
+ def testInstanceBasics(self):
+ value = 123
+ samer = Photon.ValueIdentity(value)
+ self.assertEqual(samer.multiplicator(), 1)
+ doubler = Photon.ValueDuplicator(value)
+ self.assertEqual(doubler.multiplicator(), 2)
+ self.assertEqual(samer.value(), doubler.value())
+ self.assertEqual(samer.calculate() * 2, doubler.calculate())
+
+ def testPassToFunctionAsPointer(self):
+ obj = Photon.ValueDuplicator(123)
+ self.assertEqual(Photon.callCalculateForValueDuplicatorPointer(obj), obj.calculate())
+
+ def testPassToFunctionAsReference(self):
+ obj = Photon.ValueDuplicator(321)
+ self.assertEqual(Photon.callCalculateForValueDuplicatorReference(obj), obj.calculate())
+
+ def testPassToMethodAsValue(self):
+ value1, value2 = 123, 321
+ one = Photon.ValueIdentity(value1)
+ other = Photon.ValueIdentity(value2)
+ self.assertEqual(one.sumValueUsingPointer(other), value1 + value2)
+
+ def testPassToMethodAsReference(self):
+ value1, value2 = 123, 321
+ one = Photon.ValueDuplicator(value1)
+ other = Photon.ValueDuplicator(value2)
+ self.assertEqual(one.sumValueUsingReference(other), value1 + value2)
+
+ def testPassPointerThrough(self):
+ obj1 = Photon.ValueIdentity(123)
+ self.assertEqual(obj1, obj1.passPointerThrough(obj1))
+ obj2 = Photon.ValueDuplicator(321)
+ self.assertEqual(obj2, obj2.passPointerThrough(obj2))
+ self.assertRaises(TypeError, obj1.passPointerThrough, obj2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/time_test.py b/sources/shiboken6/tests/samplebinding/time_test.py
new file mode 100644
index 000000000..6283a6744
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/time_test.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for constructor and method signature decisor on Time class.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+import datetime
+
+from sample import Time, ImplicitConv, ObjectType
+
+
+class TimeTest(unittest.TestCase):
+ '''Test cases for constructor and method signature decisor on Time class.
+ The constructor and one method have these signatures: CTORMETHOD() and
+ CTORMETHOD(int h, int m, int s = 0, int ms = 0); there another method
+ with a more complex signature METH(int, int, ImplicitConv=DEFVALUE, ObjectType=0),
+ to produce an even worse scenario.
+ '''
+
+ def testConstructorWithoutParamers(self):
+ '''Constructor without parameters: Time()'''
+ time = Time()
+ self.assertTrue(time.isNull())
+
+ def testConstructorWithAllParamers(self):
+ '''Constructor with all parameters: Time(int h, int m, int s = 0, int ms = 0)'''
+ time = Time(1, 2, 3, 4)
+ self.assertTrue(time.toString(), '01:02:03.004')
+
+ def testConstructorWithThreeParamers(self):
+ '''Constructor with 3 parameters: Time(int h, int m, int s = 0, int ms = 0)'''
+ time = Time(1, 2, 3)
+ self.assertTrue(time.toString(), '01:02:03.000')
+
+ def testConstructorWithTwoParamers(self):
+ '''Constructor with 2 parameters: Time(int h, int m, int s = 0, int ms = 0)'''
+ time = Time(1, 2)
+ self.assertTrue(time.toString(), '01:02:00.000')
+
+ def testSimpleMethodWithoutParamers(self):
+ '''Constructor without parameters: Time.setTime()'''
+ time = Time(1, 2, 3, 4)
+ time.setTime()
+ self.assertTrue(time.isNull())
+
+ def testSimpleMethodWithAllParamers(self):
+ '''Simple method with all parameters: Time.setTime(int h, int m, int s = 0, int ms = 0)'''
+ time = Time()
+ time.setTime(1, 2, 3, 4)
+ self.assertTrue(time.toString(), '01:02:03.004')
+
+ def testSimpleMethodWithThreeParamers(self):
+ '''Simple method with 3 parameters: Time.setTime(int h, int m, int s = 0, int ms = 0)'''
+ time = Time()
+ time.setTime(1, 2, 3)
+ self.assertTrue(time.toString(), '01:02:03.000')
+
+ def testSimpleMethodWithTwoParamers(self):
+ '''Simple method with 2 parameters: Time.setTime(int h, int m, int s = 0, int ms = 0)'''
+ time = Time()
+ time.setTime(1, 2)
+ self.assertTrue(time.toString(), '01:02:00.000')
+
+ def testMethodWithoutParamers(self):
+ '''Method without parameters: Time.somethingCompletelyDifferent()'''
+ time = Time()
+ result = time.somethingCompletelyDifferent()
+ self.assertEqual(result, Time.ZeroArgs)
+
+ def testMethodWithAllParamers(self):
+ '''Method with all parameters:
+ Time.somethingCompletelyDifferent(
+ int h, int m, ImplicitConv ic = ImplicitConv::CtorThree, ObjectType* type = 0
+ );
+ '''
+ time = Time()
+ obj = ObjectType()
+ result = time.somethingCompletelyDifferent(1, 2, ImplicitConv(2), obj)
+ self.assertEqual(result, Time.FourArgs)
+
+ def testMethodWithThreeParamers(self):
+ '''Method with 3 parameters: Time.somethingCompletelyDifferent(...)'''
+ time = Time()
+ result = time.somethingCompletelyDifferent(1, 2, ImplicitConv(ImplicitConv.CtorOne))
+ self.assertEqual(result, Time.ThreeArgs)
+
+ def testMethodWithTwoParamers(self):
+ '''Method with 2 parameters: Time.somethingCompletelyDifferent(...)'''
+ time = Time()
+ result = time.somethingCompletelyDifferent(1, 2)
+ self.assertEqual(result, Time.TwoArgs)
+
+ def testMethodWithThreeParamersAndImplicitConversion(self):
+ '''Method with 3 parameters, the last one triggers an implicit conversion.'''
+ time = Time()
+ result = time.somethingCompletelyDifferent(1, 2, ImplicitConv.CtorOne)
+ self.assertEqual(result, Time.ThreeArgs)
+
+ # PYSIDE-1436: These tests crash at shutdown due to `assert(Not)?Equal`.
+ def testCompareWithPythonTime(self):
+ time = Time(12, 32, 5)
+ py = datetime.time(12, 32, 5)
+ self.assertEqual(time, py)
+
+ def testNotEqual(self):
+ time = Time(12, 32, 6)
+ py = datetime.time(12, 32, 5)
+ self.assertNotEqual(time, py)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/transform_test.py b/sources/shiboken6/tests/samplebinding/transform_test.py
new file mode 100644
index 000000000..7dfd18a4a
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/transform_test.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for argument modification with more than nine arguments.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point, applyHomogeneousTransform
+
+
+class TransformTest(unittest.TestCase):
+ '''Test cases for modifying a function with > 9 arguments.'''
+
+ def testTransform_ValidMatrix(self):
+ '''Transform applies successfully.'''
+ p = Point(3, 4)
+ r = applyHomogeneousTransform(p, 0, 1, 0, -1, 0, 0, 0, 0, 1)
+ self.assertTrue(type(r) is Point)
+ self.assertEqual(r.x(), 4)
+ self.assertEqual(r.y(), -3)
+
+ def testTransform_InvalidMatrix(self):
+ '''Transform does not apply successfully.'''
+ p = Point(3, 4)
+ r = applyHomogeneousTransform(p, 1, 0, 0, 0, 1, 0, 0, 0, 0)
+ self.assertTrue(r is None)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/typeconverters_test.py b/sources/shiboken6/tests/samplebinding/typeconverters_test.py
new file mode 100644
index 000000000..987ba6dfd
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/typeconverters_test.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Tests various usages of the type converters.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+import sample
+
+
+class GetPythonTypeByNameTest(unittest.TestCase):
+
+ '''Uses an added function with inject code that uses the libshiboken
+ function "Shiboken::Conversions::getPythonTypeObject(typeName)".'''
+
+ def testGetObjectType(self):
+ pyType1 = sample.getPythonType('ObjectType')
+ self.assertEqual(pyType1, sample.ObjectType)
+ pyType2 = sample.getPythonType('ObjectType*')
+ self.assertEqual(pyType2, sample.ObjectType)
+ self.assertEqual(pyType1, pyType2)
+
+ def testGetValueType(self):
+ pyType1 = sample.getPythonType('Point')
+ self.assertEqual(pyType1, sample.Point)
+ pyType2 = sample.getPythonType('Point*')
+ self.assertEqual(pyType2, sample.Point)
+ self.assertEqual(pyType1, pyType2)
+
+ def testGetUsersPrimitiveType(self):
+ pyType = sample.getPythonType('OddBool')
+ self.assertEqual(pyType, bool)
+
+ def testGetUsersPrimitiveTypeWithoutTargetLangApiName(self):
+ '''If the primitive type attribute "target-lang-api-name" is not set
+ there'll be no Python type associated with the C++ type.'''
+ pyType = sample.getPythonType('PStr')
+ self.assertEqual(pyType, None)
+
+ def testPrimitiveTypeAndTypedef(self):
+ pyType = sample.getPythonType('double')
+ self.assertEqual(pyType, float)
+ pyTypedef = sample.getPythonType('real')
+ self.assertEqual(pyType, pyTypedef)
+
+ def testPairContainerType(self):
+ pyType = sample.getPythonType('std::pair<Complex,int>')
+ self.assertEqual(pyType, list)
+
+ def testListContainerType(self):
+ pyType = sample.getPythonType('std::list<int>')
+ self.assertEqual(pyType, list)
+
+ def testMapContainerType(self):
+ pyType = sample.getPythonType('std::map<std::string,int>')
+ self.assertEqual(pyType, dict)
+
+ def testGlobalEnumType(self):
+ pyType = sample.getPythonType('GlobalEnum')
+ self.assertEqual(pyType, sample.GlobalEnum)
+
+ def testScopedEnumType(self):
+ pyType = sample.getPythonType('Abstract::Type')
+ self.assertEqual(pyType, sample.Abstract.Type)
+
+
+class CheckValueAndObjectTypeByNameTest(unittest.TestCase):
+
+ '''Uses an added function with inject code that uses the libshiboken
+ functions that check if a type is Object or Value, based on its converter.'''
+
+ def testErrors(self):
+ '''not existent type'''
+ self.assertRaises(ValueError, sample.cppTypeIsValueType, 'NotExistentType')
+ self.assertRaises(ValueError, sample.cppTypeIsObjectType, 'NotExistentType')
+
+ def testObjectType1(self):
+ self.assertTrue(sample.cppTypeIsObjectType('ObjectType'))
+ self.assertFalse(sample.cppTypeIsValueType('ObjectType'))
+
+ def testObjectType2(self):
+ self.assertTrue(sample.cppTypeIsObjectType('ObjectType*'))
+ self.assertFalse(sample.cppTypeIsValueType('ObjectType*'))
+
+ def testValueType1(self):
+ self.assertTrue(sample.cppTypeIsValueType('Point'))
+ self.assertFalse(sample.cppTypeIsObjectType('Point'))
+
+ def testValueType2(self):
+ self.assertTrue(sample.cppTypeIsValueType('Point*'))
+ self.assertFalse(sample.cppTypeIsObjectType('Point*'))
+
+ def testUsersPrimitiveType(self):
+ self.assertFalse(sample.cppTypeIsValueType('Complex'))
+ self.assertFalse(sample.cppTypeIsObjectType('Complex'))
+
+ def testContainerType(self):
+ self.assertFalse(sample.cppTypeIsValueType('std::list<int>'))
+ self.assertFalse(sample.cppTypeIsObjectType('std::list<int>'))
+
+
+class SpecificConverterTest(unittest.TestCase):
+
+ '''Uses an added function with inject code that uses the libshiboken
+ adapter class "Shiboken::Conversions::SpecificConverter".'''
+
+ def testNotExistentType(self):
+ conversion = sample.getConversionTypeString('NotExistentType')
+ self.assertEqual(conversion, 'Invalid conversion')
+
+ def testObjectType(self):
+ conversion = sample.getConversionTypeString('ObjectType')
+ self.assertEqual(conversion, 'Pointer conversion')
+ conversion = sample.getConversionTypeString('ObjectType*')
+ self.assertEqual(conversion, 'Pointer conversion')
+ conversion = sample.getConversionTypeString('ObjectType&')
+ self.assertEqual(conversion, 'Reference conversion')
+
+ def testValueType(self):
+ conversion = sample.getConversionTypeString('Point')
+ self.assertEqual(conversion, 'Copy conversion')
+ conversion = sample.getConversionTypeString('Point*')
+ self.assertEqual(conversion, 'Pointer conversion')
+ conversion = sample.getConversionTypeString('Point&')
+ self.assertEqual(conversion, 'Reference conversion')
+
+
+class StringBasedConversionTest(unittest.TestCase):
+
+ def testValueType(self):
+ pts = (sample.Point(1, 1), sample.Point(2, 2), sample.Point(3, 3))
+ result = sample.convertValueTypeToCppAndThenToPython(pts[0], pts[1], pts[2])
+ for orig, new in zip(pts, result):
+ self.assertEqual(orig, new)
+ self.assertFalse(pts[0] is result[0])
+ self.assertTrue(pts[1] is result[1])
+ self.assertTrue(pts[2] is result[2])
+
+ def testObjectType(self):
+ objs = (sample.ObjectType(), sample.ObjectType())
+ objs[0].setObjectName('obj0')
+ objs[1].setObjectName('obj1')
+ result = sample.convertObjectTypeToCppAndThenToPython(objs[0], objs[1])
+ for orig, new in zip(objs, result):
+ self.assertEqual(orig, new)
+ self.assertEqual(orig.objectName(), new.objectName())
+ self.assertTrue(orig is new)
+
+ def testContainerType(self):
+ lst = range(4)
+ result = sample.convertListOfIntegersToCppAndThenToPython(lst)
+ self.assertTrue(len(result), 1)
+ self.assertTrue(lst, result[0])
+
+
+class PrimitiveConversionTest(unittest.TestCase):
+
+ def testCppPrimitiveType(self):
+ integers = (12, 34)
+ result = sample.convertIntegersToCppAndThenToPython(integers[0], integers[1])
+ for orig, new in zip(integers, result):
+ self.assertEqual(orig, new)
+
+ def testLargeIntAsFloat(self):
+ """PYSIDE-2417: When passing an int to a function taking float,
+ a 64bit conversion should be done."""
+ point = sample.PointF(1, 2)
+ large_int = 2**31 + 2
+ point.setX(large_int)
+ self.assertEqual(round(point.x()), large_int)
+
+ def testUnsignedLongLongAsFloat(self):
+ """PYSIDE-2652: When passing an unsigned long long to a function taking float,
+ an unsigned 64bit conversion should be done."""
+ point = sample.PointF(1, 2)
+ large_int = 2**63
+ point.setX(large_int)
+ self.assertEqual(round(point.x()), large_int)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/typedealloc_test.py b/sources/shiboken6/tests/samplebinding/typedealloc_test.py
new file mode 100644
index 000000000..ce881e802
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/typedealloc_test.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test deallocation of type extended in Python.'''
+
+import gc
+import os
+import sys
+import unittest
+import weakref
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point
+
+
+class TypeDeallocTest(unittest.TestCase):
+
+ def setUp(self):
+ self.called = False
+
+ def tearDown(self):
+ del self.called
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ def callback(self, *args):
+ self.called = True
+
+ def testScopeEnd(self):
+ ref = None
+
+ def scope():
+
+ class Ext(Point):
+ pass
+
+ o = Ext() # noqa: F841
+ global ref
+ ref = weakref.ref(Ext, self.callback)
+
+ scope()
+ gc.collect()
+ self.assertTrue(self.called)
+
+ def testDeleteType(self):
+ class Ext(Point):
+ pass
+ ref = weakref.ref(Ext, self.callback) # noqa: F841
+ del Ext
+ gc.collect()
+ self.assertTrue(self.called)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/typedtordoublefree_test.py b/sources/shiboken6/tests/samplebinding/typedtordoublefree_test.py
new file mode 100644
index 000000000..ab8e535b5
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/typedtordoublefree_test.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import ObjectType
+
+
+class TestTypeDestructorDoubleFree(unittest.TestCase):
+ def testTypeDestructorDoubleFree(self):
+ '''Causes the type destructors of two derived classes to be called.'''
+ def scope():
+ class ExtObj1(ObjectType):
+ def __init__(self):
+ ObjectType.__init__(self)
+ obj = ExtObj1()
+ child = ObjectType(parent=obj)
+ self.assertEqual(obj.takeChild(child), child)
+
+ class ExtObj2(ObjectType):
+ def __init__(self):
+ ObjectType.__init__(self)
+
+ obj = ExtObj2()
+ child = ObjectType(parent=obj)
+ self.assertEqual(obj.takeChild(child), child)
+ scope()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
new file mode 100644
index 000000000..e315e599e
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
@@ -0,0 +1,2457 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<typesystem package="sample">
+ <primitive-type name="ObjectType::Identifier"/>
+ <primitive-type name="std::nullptr_t"/>
+
+ <primitive-type name="Foo::SAMPLE_HANDLE" target-lang-api-name="PyLong"/>
+
+ <primitive-type name="std::size_t" target-lang-api-name="PyLong">
+ <conversion-rule>
+ <native-to-target>
+ return PyLong_FromSize_t(%in);
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyLong">
+ %out = %OUTTYPE(PyLong_AsSsize_t(%in));
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
+ <inject-code class="native" position="beginning">
+ static bool Check2TupleOfNumbers(PyObject* pyIn) {
+ if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2))
+ return false;
+ Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0));
+ if (!PyNumber_Check(pyReal))
+ return false;
+ Shiboken::AutoDecRef pyImag(PySequence_GetItem(pyIn, 1));
+ if (!PyNumber_Check(pyImag))
+ return false;
+ return true;
+ }
+ </inject-code>
+ <primitive-type name="Complex" target-lang-api-name="PyComplex">
+ <include file-name="complex.h" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ return PyComplex_FromDoubles(%in.real(), %in.imag());
+ </native-to-target>
+ <target-to-native>
+ <!-- The 'check' attribute can be derived from the 'type' attribute,
+ it is defined here to test the CHECKTYPE type system variable. -->
+ <add-conversion type="PyComplex" check="%CHECKTYPE[Complex](%in)">
+ double real = PyComplex_RealAsDouble(%in);
+ double imag = PyComplex_ImagAsDouble(%in);
+ %out = %OUTTYPE(real, imag);
+ </add-conversion>
+ <add-conversion type="PySequence" check="Check2TupleOfNumbers(%in)">
+ Shiboken::AutoDecRef pyReal(PySequence_GetItem(%in, 0));
+ Shiboken::AutoDecRef pyImag(PySequence_GetItem(%in, 1));
+ double real = %CONVERTTOCPP[double](pyReal);
+ double imag = %CONVERTTOCPP[double](pyImag);
+ %out = %OUTTYPE(real, imag);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
+ <primitive-type name="Null">
+ <include file-name="null.h" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ SBK_UNUSED(%in);
+ Py_RETURN_NONE;
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyObject" check="%in == 0 || %in == Py_None">
+ %out = %OUTTYPE(%in == 0);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
+ <primitive-type name="SAMPLE_HANDLE" target-lang-api-name="PyComplex">
+ <include file-name="handle.h" location="local"/>
+ <conversion-rule>
+ <native-to-target>
+ if (!%in)
+ Py_RETURN_NONE;
+ return PyCapsule_New(%in, nullptr, nullptr);
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyNone">
+ SBK_UNUSED(%in)
+ %out = 0;
+ </add-conversion>
+ <add-conversion check="checkPyCapsuleOrPyCObject(%in)" type="PyObject">
+ void *ptr = PyCapsule_GetPointer(%in, nullptr);
+ %out = (%OUTTYPE)ptr;
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
+ <inject-code class="native" position="beginning">
+ static bool checkPyCapsuleOrPyCObject(PyObject* pyObj)
+ {
+ return PyCapsule_CheckExact(pyObj);
+ }
+ </inject-code>
+
+ <primitive-type name="PrimitiveStructPtr">
+ <include file-name="handle.h" location="local"/>
+ <conversion-rule>
+ <native-to-target>
+ return PyCapsule_New(&amp;%in, nullptr, nullptr);
+ </native-to-target>
+ <target-to-native>
+ <add-conversion check="checkPyCapsuleOrPyCObject(%in)" type="PyObject">
+ void *ptr = PyCapsule_GetPointer(%in, nullptr);
+ %out = *reinterpret_cast&lt;%OUTTYPE*&gt;(ptr);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
+ <primitive-type name="OddBool" target-lang-api-name="PyBool" default-constructor="OddBool(false)">
+ <include file-name="oddbool.h" location="global"/>
+ <include file-name="complex.h" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ return PyBool_FromLong(%in.value());
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyBool">
+ // Tests CONVERTTOCPP macro with C++ primitive type.
+ bool b = %CONVERTTOCPP[bool](%in);
+ %out = %OUTTYPE(b);
+ </add-conversion>
+ <add-conversion type="PyComplex">
+ // Tests CONVERTTOCPP macro with user's primitive type.
+ Complex cpx = %CONVERTTOCPP[Complex](%in);
+ %out = %OUTTYPE(cpx.real() != 0.0 || cpx.imag() != 0.0);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
+ <!-- As of Qt 6, there is a trend of hiding bool returns of comparison
+ operators of container classes behind some template expression using
+ SFINAE depending on their value's traits, like:
+ template <typename U = T>
+ friend QTypeTraits::compare_eq_result<U> operator==(const QList &l, const QList &r)
+ which the clang parser cannot identify. Rich comparison of classes
+ inheriting QList (QPolygon, QItemSelection) will then not be generated.
+ To work around, the operators should be added manually without
+ injecting code. The code should just use the standard implementation. -->
+ <value-type name="ComparisonTester">
+ <include file-name="oddbool.h" location="global"/>
+ <add-function signature="operator==(const ComparisonTester&amp;)" return-type="bool"/>
+ <add-function signature="operator!=(const ComparisonTester&amp;)" return-type="bool"/>
+ </value-type>
+ <value-type name="SpaceshipComparisonTester">
+ <enum-type name="Enabled"/>
+ </value-type>
+
+ <primitive-type name="PStr">
+ <include file-name="str.h" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ return Shiboken::String::fromCString(%in.cstring(), %in.size());
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyUnicode" check="Shiboken::String::check(%in)">
+ const char* str = %CONVERTTOCPP[const char*](%in);
+ %out = %OUTTYPE(str);
+ </add-conversion>
+ <add-conversion type="Py_None">
+ SBK_UNUSED(%in)
+ %out = %OUTTYPE();
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
+ <function signature="changePStr(PStr*, const char*)">
+ <!--
+ Comment out these modifications and the Shiboken generator
+ will issue a fatal error, because it can't handle a pointer
+ to a primitive type (PStr*) without help from the binding
+ developer.
+ -->
+ <modify-function>
+ <modify-argument index="1">
+ <replace-type modified-type="PStr"/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ %FUNCTION_NAME(&amp;%1, %2);
+ %PYARG_0 = %CONVERTTOPYTHON[PStr](%1);
+ </inject-code>
+ </modify-function>
+ </function>
+
+ <function signature="duplicatePStr(PStr*)">
+ <modify-function>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject"/>
+ </modify-argument>
+ <modify-argument index="1">
+ <replace-type modified-type="PStr"/>
+ <replace-default-expression with="PStr()"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ %FUNCTION_NAME(&amp;%1);
+ %PYARG_0 = %CONVERTTOPYTHON[PStr](%1);
+ </inject-code>
+ </modify-function>
+ </function>
+
+ <primitive-type name="PStrList">
+ <include file-name="strlist.h" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ PyObject *%out = PyList_New(Py_ssize_t(%in.size()));
+ Py_ssize_t idx = 0;
+ for (const auto &amp;s : %in) {
+ PStr cppItem(s);
+ PyList_SET_ITEM(%out, idx++, %CONVERTTOPYTHON[PStr](cppItem));
+ }
+ return %out;
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ %OUTTYPE&amp; list = %out;
+ Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0));
+ for (int i = 0; i &lt; PySequence_Fast_GET_SIZE(seq.object()); i++) {
+ PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), i);
+ PStr cppItem = %CONVERTTOCPP[PStr](pyItem);
+ list.push_back(cppItem);
+ }
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </primitive-type>
+
+ <add-function signature="createPStrList(PStr, PStr)" return-type="PyObject">
+ <inject-code class="target">
+ PStrList %0;
+ %0.push_back(%1);
+ %0.push_back(%2);
+ %PYARG_0 = %CONVERTTOPYTHON[PStrList](%0);
+ </inject-code>
+ </add-function>
+ <add-function signature="createListOfPStr(PStr, PStr)" return-type="PyObject">
+ <inject-code class="target">
+ std::list&lt;PStr&gt; %0;
+ %0.push_back(%1);
+ %0.push_back(%2);
+ %PYARG_0 = %CONVERTTOPYTHON[std::list&lt;PStr&gt;](%0);
+ </inject-code>
+ </add-function>
+
+ <add-function signature="getPythonType(const char*)" return-type="PyObject">
+ <inject-code class="target" position="beginning">
+ SBK_UNUSED(self)
+ %PYARG_0 = (PyObject*) Shiboken::Conversions::getPythonTypeObject(%1);
+ if (!%PYARG_0)
+ %PYARG_0 = Py_None;
+ Py_INCREF(%PYARG_0);
+ </inject-code>
+ </add-function>
+
+ <template name="cpp_type_is_object_or_value_type">
+ SbkConverter* converter = Shiboken::Conversions::getConverter(%1);
+ if (converter) {
+ if (Shiboken::Conversions::pythonTypeIs$TYPEType(converter))
+ %PYARG_0 = Py_True;
+ else
+ %PYARG_0 = Py_False;
+ Py_INCREF(%PYARG_0);
+ } else {
+ PyErr_Format(PyExc_ValueError, "Type '%s' has no converter associated to it", %1);
+ }
+ </template>
+ <add-function signature="cppTypeIsObjectType(const char*)" return-type="bool">
+ <inject-code class="target" position="beginning">
+ <insert-template name="cpp_type_is_object_or_value_type">
+ <replace from="$TYPE" to="Object" />
+ </insert-template>
+ </inject-code>
+ </add-function>
+ <add-function signature="cppTypeIsValueType(const char*)" return-type="bool">
+ <inject-code class="target" position="beginning">
+ <insert-template name="cpp_type_is_object_or_value_type">
+ <replace from="$TYPE" to="Value" />
+ </insert-template>
+ </inject-code>
+ </add-function>
+
+ <add-function signature="getConversionTypeString(const char*)" return-type="PyObject">
+ <inject-code class="target" position="beginning">
+ Shiboken::Conversions::SpecificConverter converter(%1);
+ const char* %0 = 0;
+ switch (converter.conversionType()) {
+ case Shiboken::Conversions::SpecificConverter::CopyConversion:
+ %0 = "Copy conversion";
+ break;
+ case Shiboken::Conversions::SpecificConverter::PointerConversion:
+ %0 = "Pointer conversion";
+ break;
+ case Shiboken::Conversions::SpecificConverter::ReferenceConversion:
+ %0 = "Reference conversion";
+ break;
+ default:
+ %0 = "Invalid conversion";
+ }
+ %PYARG_0 = %CONVERTTOPYTHON[const char*](%0);
+ </inject-code>
+ </add-function>
+
+ <inject-code class="native" position="beginning">
+ static PyObject* __convertCppValuesToPython(const char** typeName, void** values, int size)
+ {
+ PyObject* result = PyTuple_New(size);
+ for (int i = 0; i &lt; size; ++i) {
+ Shiboken::Conversions::SpecificConverter converter(typeName[i]);
+ PyTuple_SET_ITEM(result, i, converter.toPython(values[i]));
+ }
+ return result;
+ }
+ </inject-code>
+ <add-function signature="convertValueTypeToCppAndThenToPython(Point,Point*,Point&amp;)" return-type="PyObject">
+ <inject-code class="target" position="beginning">
+ const char* typeNames[] = { "Point", "Point*", "Point&amp;" };
+ void* values[] = { &amp;%1, &amp;%2, &amp;(%3) };
+ %PYARG_0 = __convertCppValuesToPython(typeNames, values, 3);
+ </inject-code>
+ </add-function>
+ <add-function signature="convertObjectTypeToCppAndThenToPython(ObjectType*,ObjectType&amp;)" return-type="PyObject">
+ <inject-code class="target" position="beginning">
+ const char* typeNames[] = { "ObjectType*", "ObjectType&amp;" };
+ void* values[] = { &amp;%1, &amp;(%2) };
+ %PYARG_0 = __convertCppValuesToPython(typeNames, values, 2);
+ </inject-code>
+ </add-function>
+ <add-function signature="convertListOfIntegersToCppAndThenToPython(std::list&lt;int&gt;)" return-type="PyObject">
+ <inject-code class="target" position="beginning">
+ const char* typeNames[] = { "std::list&lt;int&gt;" };
+ void* values[] = { &amp;%1 };
+ %PYARG_0 = __convertCppValuesToPython(typeNames, values, 1);
+ </inject-code>
+ </add-function>
+ <add-function signature="convertIntegersToCppAndThenToPython(int,int)" return-type="PyObject">
+ <inject-code class="target" position="beginning">
+ const char* typeNames[] = { "int", "int" };
+ void* values[] = { &amp;%1, &amp;%2 };
+ %PYARG_0 = __convertCppValuesToPython(typeNames, values, 2);
+ </inject-code>
+ </add-function>
+
+ <template name="cpp_indexed_list_to_pylist_conversion">
+ PyObject *%out = PyList_New(Py_ssize_t(%in.size()));
+ Py_ssize_t idx = 0;
+ for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it, ++idx) {
+ %INTYPE_0 cppItem(*it);
+ PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
+ }
+ return %out;
+ </template>
+ <container-type name="List" type="list">
+ <include file-name="list" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ <insert-template name="cpp_indexed_list_to_pylist_conversion"/>
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer"/>
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </container-type>
+ <add-function signature="cacheSize()" return-type="int">
+ <inject-code class="target">
+ %RETURN_TYPE %0 = Shiboken::BindingManager::instance().getAllPyObjects().size();
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+
+ <namespace-type name="sample">
+ <value-type name="sample" />
+ </namespace-type>
+
+ <function signature="sumComplexPair(std::pair&lt;Complex, Complex>)" />
+ <function signature="gimmeComplexList()" />
+ <function signature="transmuteComplexIntoPoint(const Complex&amp;)" />
+ <function signature="transmutePointIntoComplex(const Point&amp;)" />
+ <function signature="sumComplexPair(std::pair&lt;Complex, Complex>)" />
+ <function signature="doubleUnsignedInt(unsigned int)" />
+ <function signature="doubleLongLong(long long)" />
+ <function signature="doubleUnsignedLongLong(unsigned long long)" />
+ <function signature="doubleShort(short)" />
+ <function signature="returnNullPrimitivePointer()" />
+ <function signature="returnNullValueTypePointer()" />
+ <function signature="returnNullObjectTypePointer()" />
+ <function signature="acceptInt(int)" />
+ <function signature="acceptIntReturnPtr(int)"/>
+ <function signature="acceptUInt(unsigned int)" />
+ <function signature="acceptLong(long)" />
+ <function signature="acceptULong(unsigned long)" />
+ <function signature="acceptDouble(double)" />
+ <function signature="acceptIntReference(int&amp;)" />
+ <function signature="acceptOddBoolReference(OddBool&amp;)" />
+ <function signature="countCharacters(const char*)" />
+ <function signature="gimmeInt()" />
+ <function signature="gimmeDouble()" />
+ <function signature="makeCString()" />
+ <function signature="sumIntArray(int[4])"/>
+ <function signature="sumDoubleArray(double[4])"/>
+ <function signature="sumIntMatrix(int[2][3])"/>
+ <function signature="sumDoubleMatrix(double[2][3])"/>
+ <function signature="multiplyPair(std::pair&lt;double, double>)" />
+ <function signature="returnCString()" />
+ <function signature="overloadedFunc(double)" />
+ <function signature="overloadedFunc(int)" />
+ <function signature="addStdStrings(const std::string&amp;, const std::string&amp;)"/>
+ <function signature="addStdWStrings(const std::wstring&amp;, const std::wstring&amp;)"/>
+ <function signature="testNullPtrT(std::nullptr_t)"/>
+ <function signature="takePolygon(Polygon&amp;&amp;)"/>
+ <function signature="takeObjectType(ObjectType&amp;&amp;)"/>
+
+ <value-type name="ArrayModifyTest">
+ <modify-function signature="sumIntArray(int, int*)">
+ <modify-argument index="2"><array/></modify-argument>
+ </modify-function>
+ </value-type>
+
+ <value-type name="ClassWithFunctionPointer">
+ <suppress-warning text="^skipping public function 'void ClassWithFunctionPointer::callFunctionPointer.*$" />
+ </value-type>
+
+ <value-type name="IntArray" generate="no"/>
+ <value-type name="IntArray2">
+ <modify-function signature="IntArray2(const int*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
+ </value-type>
+
+ <value-type name="IntArray3">
+ <modify-function signature="IntArray3(const int*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
+ </value-type>
+
+ <enum-type name="OverloadedFuncEnum"/>
+ <!-- BUG:
+ renaming the ICOverloadedFuncEnum to the same name
+ of a global enum causes the generator to confuse the
+ two types.
+ -->
+ <enum-type name="GlobalEnum"/>
+ <enum-type name="GlobalOverloadFuncEnum"/>
+
+ <enum-type identified-by-value="AnonymousGlobalEnum_Value0"/>
+
+ <namespace-type name="SampleNamespace">
+ <namespace-type name="InlineNamespace">
+ <value-type name="ClassWithinInlineNamespace"/>
+ <enum-type name="EnumWithinInlineNamespace"/>
+ </namespace-type>
+ <enum-type name="Option"/>
+ <enum-type name="InValue"/>
+ <enum-type name="OutValue"/>
+ <enum-type identified-by-value="AnonymousClassEnum_Value1"/>
+
+ <object-type name="DerivedFromNamespace">
+ <enum-type name="SampleNamespace"/>
+ </object-type>
+ <value-type name="SomeClass">
+ <enum-type name="PublicScopedEnum"/>
+ <value-type name="SomeInnerClass">
+ <object-type name="OkThisIsRecursiveEnough">
+ <enum-type name="NiceEnum" />
+ <enum-type name="NiceEnumClass" />
+ </object-type>
+ <enum-type name="ProtectedEnum"/>
+ </value-type>
+ <value-type name="SomeOtherInnerClass"/>
+ <enum-type name="ProtectedEnum"/>
+ </value-type>
+
+ <modify-function signature="doSomethingWithArray(const unsigned char*, unsigned int, const char*)">
+ <modify-argument index="1">
+ <replace-type modified-type="const char*"/>
+ <conversion-rule>
+ <target-to-native>
+ <add-conversion>
+ const unsigned char* %out = reinterpret_cast&lt;const unsigned char*>(Shiboken::String::toCString(%PYARG_1));
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="2">
+ <remove-argument/>
+ <conversion-rule class="native">
+ unsigned int %out = static_cast&lt;unsigned int>(Shiboken::String::len(%PYARG_1));
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+ <add-function signature="ImInsideANamespace(int, int)" return-type="int">
+ <inject-code class="target">
+ %RETURN_TYPE %0 = %1 + %2;
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+ <add-function signature="passReferenceToValueType(Point&amp;)" return-type="double">
+ <inject-code>
+ %RETURN_TYPE %0 = %1.x() + %1.y();
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+
+ <!-- Do change the argument from pointer to reference to comply with the C++ overload
+ of this function. The generator must be able to deal with this for Object Types. -->
+ <add-function signature="passReferenceToObjectType(ObjectType*)" return-type="int">
+ <inject-code>
+ // The dot in "%1." must be replaced with a "->" by the generator.
+ %RETURN_TYPE %0 = %1.objectName().size();
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+
+ <object-type name="CtParam"/>
+ </namespace-type>
+
+ <namespace-type name="RemovedNamespace1" visible='false'>
+ <enum-type name="RemovedNamespace1_Enum" />
+ <function signature="mathSum(int,int)"/>
+ <value-type name="ObjectOnInvisibleNamespace" />
+ <namespace-type name="RemovedNamespace2" visible='false'>
+ <enum-type name="RemovedNamespace2_Enum" />
+ </namespace-type>
+ <enum-type identified-by-value="RemovedNamespace1_AnonymousEnum_Value0" />
+ </namespace-type>
+
+ <namespace-type name="UnremovedNamespace">
+ <namespace-type name="RemovedNamespace3" visible='false'>
+ <enum-type name="RemovedNamespace3_Enum" />
+ <enum-type identified-by-value="RemovedNamespace3_AnonymousEnum_Value0" />
+ </namespace-type>
+ </namespace-type>
+
+ <namespace-type name="Photon">
+ <enum-type name="ClassType"/>
+ <value-type name="Base"/>
+ <value-type name="TemplateBase" generate="no"/>
+ <value-type name="ValueIdentity"/>
+ <value-type name="ValueDuplicator"/>
+ </namespace-type>
+
+ <value-type name="CVValueType"/>
+ <value-type name="CVListUser"/>
+
+ <value-type name="IntList">
+ <enum-type name="CtorEnum"/>
+ </value-type>
+ <value-type name="PointValueList">
+ <enum-type name="CtorEnum"/>
+ </value-type>
+ <value-type name="ObjectTypePtrList">
+ <enum-type name="CtorEnum"/>
+ </value-type>
+
+ <object-type name="Abstract">
+ <enum-type name="Type"/>
+ <enum-type name="PrintFormat"/>
+ <modify-function signature="id()" rename="id_"/>
+ <modify-function signature="hideFunction(HideType*)" remove="all"/>
+ <modify-field name="toBeRenamedField" rename="renamedField"/>
+ <modify-field name="readOnlyField" write="false"/>
+ <modify-function signature="virtualWithOutParameter(int&amp;)const">
+ <inject-code class="shell" position="override">
+ x = virtualWithOutParameterPyOverride(gil, pyOverride.object());
+ return;
+ </inject-code>
+ </modify-function>
+ <add-function signature="virtualWithOutParameterPyOverride()"
+ return-type="int" python-override="true"/>
+ </object-type>
+
+ <object-type name="Derived" polymorphic-id-expression="%1->type() == Derived::TpDerived">
+ <enum-type name="OtherOverloadedFuncEnum"/>
+ <value-type name="SomeInnerClass" />
+ </object-type>
+
+ <object-type name="DerivedUsingCt"/>
+
+ <object-type name="ModifiedConstructor">
+ <modify-function signature="ModifiedConstructor(int)">
+ <modify-argument index="1">
+ <replace-type modified-type="str"/>
+ </modify-argument>
+ <inject-code class='target' position='beginning'>
+ const char* tmpArg = %CONVERTTOCPP[const char*](%PYARG_1);
+ %0 = new %FUNCTION_NAME(atoi(tmpArg));
+ </inject-code>
+ </modify-function>
+ </object-type>
+
+ <object-type name="ObjectType" hash-function="objectTypeHash" parent-management="yes">
+ <modify-function signature="deprecatedFunction()" deprecated="yes" />
+ <!-- rename function to avoid Python signature conflit -->
+ <modify-function signature="setObject(const Null&amp;)" rename="setNullObject" />
+
+ <modify-function signature="getCppParent()">
+ <modify-argument index="this">
+ <parent index="return" action="add" />
+ </modify-argument>
+ <modify-argument index="return">
+ <define-ownership class="target" owner="default"/>
+ </modify-argument>
+ </modify-function>
+
+ <modify-function signature="event(Event*)">
+ <modify-argument index="1" invalidate-after-use="yes"/>
+ </modify-function>
+ <modify-function signature="invalidateEvent(Event*)">
+ <modify-argument index="1" invalidate-after-use="yes"/>
+ </modify-function>
+ <modify-function signature="create()">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="createWithChild()">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="setParent(ObjectType*)">
+ <modify-argument index="this">
+ <parent index="1" action="add"/>
+ </modify-argument>
+ </modify-function>
+ <inject-code class="native" position="beginning">
+ static void reparent_layout_items(PyObject* parent, PyObject* layout)
+ {
+ // CHECKTYPE and ISCONVERTIBLE are used here for test purposes, don't change them.
+ if (!%CHECKTYPE[ObjectTypeLayout*](layout) &amp;&amp; !%ISCONVERTIBLE[ObjectTypeLayout*](layout))
+ return;
+ /* %CHECKTYPE[ObjectTypeLayout*](layout) */
+ /* %ISCONVERTIBLE[ObjectTypeLayout*](layout) */
+ ObjectTypeLayout* var;
+ var = %CONVERTTOCPP[ObjectTypeLayout*](layout);
+ // TODO-CONVERTER: erase this
+ /*
+ ObjectTypeLayout* var2 = %CONVERTTOCPP[ObjectTypeLayout*](layout);
+ */
+ const ObjectTypeList&amp; objChildren = var->objects();
+ ObjectTypeList::const_iterator it = objChildren.begin();
+ for (; it != objChildren.end(); ++it) {
+ if ((*it)->isLayoutType()) {
+ ObjectTypeLayout* l = reinterpret_cast&lt;ObjectTypeLayout*>(*it);
+ reparent_layout_items(parent, %CONVERTTOPYTHON[ObjectTypeLayout*](l));
+ Shiboken::Object::setParent(layout, %CONVERTTOPYTHON[ObjectTypeLayout*](l));
+ } else {
+ Shiboken::Object::setParent(parent, %CONVERTTOPYTHON[ObjectType*](*it));
+ }
+ }
+ }
+ </inject-code>
+ <modify-function signature="setLayout(ObjectTypeLayout*)">
+ <modify-argument index="1">
+ <parent index="this" action="add"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ if (%PYARG_1 != Py_None)
+ reparent_layout_items(%PYSELF, %PYARG_1);
+ </inject-code>
+ </modify-function>
+ <modify-function signature="takeChild(ObjectType*)">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ <parent index="this" action="remove"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="takeChild(const Str&amp;)">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ <parent index="this" action="remove"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="findChild(const Str&amp;)">
+ <modify-argument index="return">
+ <parent index="this" action="add"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="children()const">
+ <modify-argument index="return">
+ <parent index="this" action="add"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="createChild(ObjectType*)">
+ <modify-argument index="return">
+ <define-ownership owner="c++" />
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="nextInFocusChain()">
+ <modify-argument index="return">
+ <parent index="this" action="add"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
+
+ <object-type name="OtherBase" />
+ <object-type name="ObjectTypeDerived" />
+
+ <object-type name="ObjectTypeLayout">
+ <modify-function signature="create()">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
+
+ <object-type name="ObjectView">
+ <modify-function signature="ObjectView(ObjectModel*, ObjectType*)">
+ <modify-argument index="1">
+ <reference-count action="set" variable-name="setModel(ObjectModel*)1"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="setModel(ObjectModel*)">
+ <modify-argument index="1">
+ <reference-count action="set"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
+
+ <object-type name="ObjectTypeHolder"/>
+ <value-type name="OnlyCopy"/>
+ <value-type name="FriendOfOnlyCopy"/>
+
+ <object-type name="ObjectModel">
+ <enum-type name="MethodCalled" />
+ <modify-function signature="data() const">
+ <modify-argument index="return">
+ <define-ownership class="native" owner="c++"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
+
+ <value-type name="Event">
+ <enum-type name="EventType"/>
+ <enum-type name="EventTypeClass"/>
+ </value-type>
+
+ <value-type name="BlackBox">
+ <modify-function signature="keepObjectType(ObjectType*)">
+ <modify-argument index="1">
+ <define-ownership owner="c++"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="retrieveObjectType(int)">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="keepPoint(Point*)">
+ <modify-argument index="1">
+ <define-ownership owner="c++"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="retrievePoint(int)">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+ <value-type name="ProtectedNonPolymorphic">
+ <modify-function signature="create()">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="modifiedProtectedSum(int, int)">
+ <inject-code class="target" position="beginning">
+ %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, %2) * 10;
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </modify-function>
+ <modify-function signature="dataTypeName(void*) const" remove="all"/>
+ <modify-function signature="dataTypeName(int) const">
+ <modify-argument index="1">
+ <replace-default-expression with="0"/>
+ </modify-argument>
+ </modify-function>
+ <add-function signature="dataTypeName(PyObject*)const" return-type="const char*">
+ <inject-code class="target" position="beginning">
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%PYARG_1);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+ </value-type>
+
+ <value-type name="ProtectedPolymorphic">
+ <modify-function signature="create()">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+ <value-type name="ProtectedPolymorphicDaughter">
+ <modify-function signature="create()">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+ <value-type name="ProtectedPolymorphicGrandDaughter">
+ <modify-function signature="create()">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+ <object-type name="ProtectedVirtualDestructor">
+ <modify-function signature="create()">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
+
+
+ <object-type name="ProtectedEnumClass">
+ <enum-type name="ProtectedEnum" />
+ <enum-type name="PublicEnum" />
+ </object-type>
+
+ <value-type name="ProtectedProperty" />
+
+ <function signature="createProtectedProperty()" />
+
+ <template name="boolptr_at_end_fix_beginning">
+ bool __ok__;
+ %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%ARGUMENT_NAMES, &amp;__ok__);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </template>
+
+ <template name="boolptr_at_start_fix_beginning">
+ bool __ok__;
+ %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(&amp;__ok__, %ARGUMENT_NAMES);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </template>
+
+ <template name="boolptr_at_start_and_one_arg_fix_beginning">
+ bool __ok__;
+ %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(&amp;__ok__, %2);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </template>
+
+ <template name="boolptr_fix_end">
+ PyObject* _tuple_ = PyTuple_New(2);
+ PyTuple_SET_ITEM(_tuple_, 0, %PYARG_0);
+ PyObject* _item_ = %CONVERTTOPYTHON[bool](__ok__);
+ PyTuple_SET_ITEM(_tuple_, 1, _item_);
+ %PYARG_0 = _tuple_;
+ </template>
+
+ <template name="return_4_arguments_as_tuple">
+ %PYARG_0 = PyTuple_New(4);
+ PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%ARG1_TYPE](%1));
+ PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[%ARG2_TYPE](%2));
+ PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[%ARG3_TYPE](%3));
+ PyTuple_SET_ITEM(%PYARG_0, 3, %CONVERTTOPYTHON[%ARG4_TYPE](%4));
+ </template>
+
+ <template name="return_5_arguments_as_tuple">
+ %PYARG_0 = PyTuple_New(5);
+ PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%ARG1_TYPE](%1));
+ PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[%ARG2_TYPE](%2));
+ PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[%ARG3_TYPE](%3));
+ PyTuple_SET_ITEM(%PYARG_0, 3, %CONVERTTOPYTHON[%ARG4_TYPE](%4));
+ PyTuple_SET_ITEM(%PYARG_0, 4, %CONVERTTOPYTHON[%ARG5_TYPE](%5));
+ </template>
+
+ <template name="return_none">
+ %PYARG_0 = Py_None;
+ Py_INCREF(Py_None);
+ </template>
+
+ <object-type name="Modifications">
+ <enum-type name="OverloadedModFunc"/>
+ <enum-type name="TestEnum"/>
+
+ <modify-function signature="overloaded(int, bool, int, double)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, true, %3, %4);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="overloaded(int, bool, int, int)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <replace-default-expression with="321"/>
+ </modify-argument>
+ <!--
+ <modify-argument index="4">
+ <remove-default-expression/>
+ </modify-argument>
+ -->
+ </modify-function>
+
+ <modify-function signature="argRemoval0(int, bool, int, int)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <replace-default-expression with="321"/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ <insert-template name="return_4_arguments_as_tuple"/>
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="argRemoval1(int, bool, Point, Point, int)">
+ <modify-argument index="3">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="4">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ <insert-template name="return_5_arguments_as_tuple"/>
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="argRemoval1(int, bool, int, bool)">
+ <inject-code class="target" position="end">
+ <insert-template name="return_none"/>
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="argRemoval2(int, bool, Point, Point, int)">
+ <modify-argument index="3">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="4">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ <insert-template name="return_5_arguments_as_tuple"/>
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="argRemoval3(int, Point, bool, Point, int)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="4">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ <insert-template name="return_5_arguments_as_tuple"/>
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="argRemoval4(int, Point, bool, Point, int)">
+ <modify-argument index="2">
+ <remove-argument/>
+ <replace-default-expression with="Point(6, 9)"/>
+ </modify-argument>
+ <modify-argument index="4">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ <insert-template name="return_5_arguments_as_tuple"/>
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="argRemoval5(int, bool, Point, Point, int)">
+ <modify-argument index="1">
+ <remove-argument/>
+ <replace-default-expression with="100"/>
+ </modify-argument>
+ <modify-argument index="3">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="4">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ <insert-template name="return_5_arguments_as_tuple"/>
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="argRemoval5(int, bool, int, bool)">
+ <modify-argument index="1">
+ <remove-argument/>
+ <replace-default-expression with="200"/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ <insert-template name="return_4_arguments_as_tuple"/>
+ </inject-code>
+ </modify-function>
+
+ <!--
+ this alteration will trigger an interesting
+ compile time error on the binding
+ -->
+ <!--
+ <modify-function signature="overloaded(int, bool, Point, Point)">
+ <modify-argument index="3">
+ <remove-argument/>
+ </modify-argument>
+ </modify-function>
+ -->
+
+ <!--
+ renaming this signature should remove it from the other
+ overloaded methods decision tree
+ -->
+ <modify-function signature="overloaded(int, bool, Point, Point)" rename="over"/>
+
+ <!--
+ 'ok' must be removed and the return value will be changed
+ to a tuple (PyObject*) containing the expected result plus
+ the 'ok' value as a Python boolean
+ -->
+ <modify-function signature="pointToPair(Point, bool*)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ <insert-template name="boolptr_at_end_fix_beginning"/>
+ </inject-code>
+ <inject-code class="target" position="end">
+ <insert-template name="boolptr_fix_end"/>
+ </inject-code>
+ </modify-function>
+
+ <!-- same as 'pointToPair' except that this time 'ok' is the first argument -->
+ <modify-function signature="multiplyPointCoordsPlusValue(bool*, Point, double)">
+ <modify-argument index="1">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ <insert-template name="boolptr_at_start_fix_beginning"/>
+ </inject-code>
+ <inject-code class="target" position="end">
+ <insert-template name="boolptr_fix_end"/>
+ </inject-code>
+ </modify-function>
+
+ <!-- completely remove 'plus' from the Python side -->
+ <modify-function signature="doublePlus(int, int)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ </modify-function>
+
+ <!-- the default value for both arguments must be changed in Python -->
+ <modify-function signature="power(int, int)">
+ <modify-argument index="1">
+ <replace-default-expression with="2"/>
+ </modify-argument>
+ <modify-argument index="2">
+ <replace-default-expression with="1"/>
+ </modify-argument>
+ </modify-function>
+
+ <!-- in Python set argument default value to 10 -->
+ <modify-function signature="timesTen(int)">
+ <modify-argument index="1">
+ <replace-default-expression with="10"/>
+ </modify-argument>
+ </modify-function>
+
+ <!-- in Python remove the argument default value -->
+ <modify-function signature="increment(int)">
+ <modify-argument index="1">
+ <remove-default-expression/>
+ </modify-argument>
+ </modify-function>
+
+ <!-- don't export this method to Python -->
+ <modify-function signature="exclusiveCppStuff()" remove="all"/>
+
+ <!-- change the name of this regular method -->
+ <modify-function signature="cppMultiply(int, int)" rename="calculateArea"/>
+
+ <!-- change the name of this virtual method -->
+ <modify-function signature="className()" rename="name"/>
+
+ <modify-function signature="sumPointArray(int, const Point[])">
+ <modify-argument index="1">
+ <remove-argument/>
+ <conversion-rule class="native">
+ const auto %out = PySequence_Size(%PYARG_1);
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="2">
+ <replace-type modified-type="PySequence" />
+ <conversion-rule class="native">
+ Shiboken::AutoArrayPointer&lt;Point&gt; %out(%1);
+ for (Py_ssize_t i = 0; i &lt; %1; ++i)
+ %out[i] = %CONVERTTOCPP[Point](PySequence_Fast_GET_ITEM(%PYARG_1, i));
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="getSize(const void*,int)">
+ <modify-argument index="1">
+ <replace-type modified-type="ByteArray&amp;"/>
+ </modify-argument>
+ <modify-argument index="2">
+ <replace-default-expression with="-1"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ int size = (%2 &lt; 0) ? %1.size() : %2;
+ %BEGIN_ALLOW_THREADS
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME((const void*) %1.data(), size);
+ %END_ALLOW_THREADS
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </modify-function>
+ <modify-function signature="sumPointCoordinates(const Point*)">
+ <modify-argument index="1">
+ <no-null-pointer/>
+ </modify-argument>
+ </modify-function>
+ <template name="differenceOfPointCoordinates_arg2">
+ bool _status;
+ bool* %2 = &amp;_status;
+ </template>
+ <template name="differenceOfPointCoordinates_returnTarget">
+ %PYARG_0 = PyTuple_New(2);
+ PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[bool](*%2));
+ PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[%RETURN_TYPE](%0));
+ </template>
+ <modify-function signature="differenceOfPointCoordinates(const Point*, bool*)">
+ <modify-argument index="2">
+ <remove-argument/>
+ <conversion-rule class="native">
+ <insert-template name="differenceOfPointCoordinates_arg2"/>
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PySequence"/>
+ <conversion-rule>
+ <target-to-native>
+ <add-conversion>
+ Shiboken::AutoDecRef _py_ok_(PySequence_GetItem(%PYARG_0, 0));
+ Shiboken::AutoDecRef _py_ret_(PySequence_GetItem(%PYARG_0, 1));
+ *%2 = %CONVERTTOCPP[bool](_py_ok_);
+ %RETURN_TYPE %out = %CONVERTTOCPP[%RETURN_TYPE](_py_ret_);
+ </add-conversion>
+ </target-to-native>
+ <native-to-target>
+ <insert-template name="differenceOfPointCoordinates_returnTarget"/>
+ </native-to-target>
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="callDifferenceOfPointCoordinates(const Point*, bool*)">
+ <modify-argument index="2">
+ <remove-argument/>
+ <conversion-rule class="native">
+ <insert-template name="differenceOfPointCoordinates_arg2"/>
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PySequence"/>
+ <conversion-rule class="target">
+ <insert-template name="differenceOfPointCoordinates_returnTarget"/>
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="nonConversionRuleForArgumentWithDefaultValue(ObjectType**)">
+ <modify-argument index="1">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="(status, object)"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ ObjectType* tmpObject = 0;
+ %BEGIN_ALLOW_THREADS
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(&amp;tmpObject);
+ %END_ALLOW_THREADS
+ %PYARG_0 = PyTuple_New(2);
+ PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%RETURN_TYPE](%0));
+ PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[ObjectType*](tmpObject));
+ </inject-code>
+ </modify-function>
+ <modify-function signature="passOddBool(OddBool)" rename="invertBoolean">
+ <inject-code class="target" position="beginning">
+ %RETURN_TYPE %0 = !%CPPSELF.%FUNCTION_NAME(%1);
+ %PYARG_0 = %CONVERTTOPYTHON[OddBool](%0);
+ </inject-code>
+ </modify-function>
+ <modify-function signature="setEnumValue(Modifications::TestEnum)">
+ <modify-argument index="1">
+ <replace-default-expression with="cppSelf->defaultEnumValue()"/>
+ </modify-argument>
+ </modify-function>
+ <add-function signature="__getattro__" return-type="PyObject *">
+ <inject-code class="target" position="beginning">
+ cppSelf->notifyGetAttroCalled();
+ </inject-code>
+ </add-function>
+ <add-function signature="__setattro__" return-type="int">
+ <inject-code class="target" position="beginning">
+ cppSelf->notifySetAttroCalled();
+ </inject-code>
+ </add-function>
+ </object-type>
+
+ <object-type name="AbstractModifications">
+ <!--
+ completely removing the pure virtual method from this
+ class will generate an #error directive.
+ -->
+ <!--
+ <modify-function signature="pointlessPureVirtualMethod()" remove="all"/>
+ -->
+ </object-type>
+
+ <value-type name="Reference">
+ <modify-function signature="returnMyFirstArg(Reference&amp;)">
+ <modify-argument index="return">
+ <replace-default-expression with="%1"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="returnMySecondArg(int, Reference&amp;)">
+ <modify-argument index="return">
+ <replace-default-expression with="%2"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+ <object-type name="ObjTypeReference">
+ <modify-function signature="returnMyFirstArg(ObjTypeReference&amp;)">
+ <modify-argument index="return">
+ <replace-default-expression with="%1"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="returnMySecondArg(int, ObjTypeReference&amp;)">
+ <modify-argument index="return">
+ <replace-default-expression with="%2"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="justAPureVirtualFunc(ObjTypeReference&amp;)">
+ <modify-argument index="return">
+ <replace-default-expression with="%1"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
+ <value-type name="ImplicitConv">
+ <enum-type name="CtorEnum"/>
+ <enum-type name="ICOverloadedFuncEnum"/>
+ </value-type>
+
+ <value-type name="VirtualMethods">
+ <modify-function signature="sum0(int, int, int)" rename="sumThree"/>
+ <modify-function signature="sum1(int, int, int)">
+ <modify-argument index="3">
+ <replace-default-expression with="1000"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="sum2(int, int, int)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <replace-default-expression with="2000"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="sum3(int, int, int)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, %1+%3, %3);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </modify-function>
+ <modify-function signature="sum4(int, int, int)">
+ <modify-argument index="2">
+ <remove-argument/>
+ <replace-default-expression with="3000"/>
+ </modify-argument>
+ <inject-code class="native" position="beginning">
+ PyObject* new_arg0 = PyLong_FromLong(PyLong_AS_LONG(%PYARG_1) - %2);
+ Py_DECREF(%PYARG_1);
+ %PYARG_1 = new_arg0;
+ </inject-code>
+ </modify-function>
+ <modify-function signature="name()">
+ <inject-code class="native" position="end">
+ %0.prepend(Str("Pimped"));
+ </inject-code>
+ </modify-function>
+ <modify-function signature="callMe()">
+ <inject-code class="native" position="end">
+ PyObject_Call(%PYTHON_METHOD_OVERRIDE, %PYTHON_ARGUMENTS, NULL);
+ </inject-code>
+ </modify-function>
+ <modify-function signature="createStr(const char*, Str*&amp;)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PySequence"/>
+ <conversion-rule class="native">
+ Shiboken::AutoDecRef _py_ok_(PySequence_GetItem(%PYARG_0, 0));
+ Shiboken::AutoDecRef _py_ret_(PySequence_GetItem(%PYARG_0, 1));
+ %RETURN_TYPE %out = %CONVERTTOCPP[%RETURN_TYPE](_py_ok_);
+ %2 = %CONVERTTOCPP[Str*](_py_ret_);
+ </conversion-rule>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ Str* _str_arg_ = 0;
+ %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, _str_arg_);
+ </inject-code>
+ <inject-code class="target" position="end">
+ %PYARG_0 = PyTuple_New(2);
+ PyObject* _item_ = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ PyTuple_SET_ITEM(%PYARG_0, 0, _item_);
+ _item_ = %CONVERTTOPYTHON[Str*](_str_arg_);
+ PyTuple_SET_ITEM(%PYARG_0, 1, _item_);
+ </inject-code>
+ </modify-function>
+ <modify-function signature="callCreateStr(const char*, Str*&amp;)">
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PySequence"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ Str* _str_arg_ = 0;
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%1, _str_arg_);
+ </inject-code>
+ <inject-code class="target" position="end">
+ %PYARG_0 = PyTuple_New(2);
+ PyObject* _item_ = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ PyTuple_SET_ITEM(%PYARG_0, 0, _item_);
+ _item_ = %CONVERTTOPYTHON[Str*](_str_arg_);
+ PyTuple_SET_ITEM(%PYARG_0, 1, _item_);
+ </inject-code>
+ </modify-function>
+ <template name="fix_int*,int*,int*,int*">
+ int a0, a1, a2, a3;
+ %BEGIN_ALLOW_THREADS
+ %CPPSELF->::%TYPE::%FUNCTION_NAME(&amp;a0, &amp;a1, &amp;a2, &amp;a3);
+ %END_ALLOW_THREADS
+ %PYARG_0 = PyTuple_New(4);
+ PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[int](a0));
+ PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[int](a1));
+ PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[int](a2));
+ PyTuple_SET_ITEM(%PYARG_0, 3, %CONVERTTOPYTHON[int](a3));
+ </template>
+ <template name="fix_native_return_int*,int*,int*,int*">
+ PyObject* _obj = %PYARG_0;
+ if (!PySequence_Check(_obj)
+ || PySequence_Fast_GET_SIZE(_obj) != 4
+ || !PyNumber_Check(PySequence_Fast_GET_ITEM(_obj, 0))
+ || !PyNumber_Check(PySequence_Fast_GET_ITEM(_obj, 1))
+ || !PyNumber_Check(PySequence_Fast_GET_ITEM(_obj, 2))
+ || !PyNumber_Check(PySequence_Fast_GET_ITEM(_obj, 3))) {
+ PyErr_SetString(PyExc_TypeError, "Sequence of 4 numbers expected");
+ } else {
+ *%1 = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(_obj, 0));
+ *%2 = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(_obj, 1));
+ *%3 = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(_obj, 2));
+ *%4 = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(_obj, 3));
+ }
+ </template>
+ <modify-function signature="getMargins(int*,int*,int*,int*)const">
+ <modify-argument index="return" pyi-type="Tuple[int, int, int, int]">
+ <replace-type modified-type="PyObject" />
+ </modify-argument>
+ <modify-argument index="1">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="3">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="4">
+ <remove-argument/>
+ <remove-default-expression/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ <insert-template name="fix_int*,int*,int*,int*"/>
+ </inject-code>
+ <inject-code class="native" position="end">
+ <insert-template name="fix_native_return_int*,int*,int*,int*"/>
+ </inject-code>
+ </modify-function>
+ <modify-function signature="callGetMargins(int*,int*,int*,int*)const">
+ <modify-argument index="0">
+ <replace-type modified-type="PyObject" />
+ </modify-argument>
+ <modify-argument index="1">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="2">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="3">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="4">
+ <remove-argument/>
+ <remove-default-expression/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ <insert-template name="fix_int*,int*,int*,int*"/>
+ </inject-code>
+ </modify-function>
+ <modify-function signature="recursionOnModifiedVirtual(Str)const">
+ <inject-code class="target" position="beginning">
+ %BEGIN_ALLOW_THREADS
+ // It's important for test purposes to use a constructor with parenthesis as argument.
+ %RETURN_TYPE %0 = %RETURN_TYPE(%CPPSELF.%FUNCTION_NAME(Str(%1)));
+ %END_ALLOW_THREADS
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </modify-function>
+ </value-type>
+ <value-type name="VirtualDaughter" />
+ <object-type name="VirtualDaughter2" />
+ <object-type name="VirtualFinalDaughter" />
+
+ <value-type name="VirtualDtor">
+ <modify-function signature="create()">
+ <modify-argument index="return">
+ <define-ownership owner="target"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+ <value-type name="PointerHolder">
+ <modify-function signature="PointerHolder(void*)" remove="all"/>
+ <add-function signature="PointerHolder(PyObject*)">
+ <inject-code class="target" position="beginning">
+ %0 = new %TYPE(%PYARG_1);
+ </inject-code>
+ </add-function>
+ <modify-function signature="pointer() const">
+ <inject-code class="target" position="beginning">
+ %PYARG_0 = reinterpret_cast&lt;PyObject*>(%CPPSELF.%FUNCTION_NAME());
+ if (!%PYARG_0)
+ %PYARG_0 = Py_None;
+ Py_INCREF(%PYARG_0);
+ </inject-code>
+ </modify-function>
+ </value-type>
+
+ <function signature="applyHomogeneousTransform(Point,double,double,double,double,double,double,double,double,double,bool*)">
+ <!--
+ Tests handling of the '%#' substitution for # > 9.
+ -->
+ <modify-function signature="applyHomogeneousTransform(Point,double,double,double,double,double,double,double,double,double,bool*)">
+ <modify-argument index="11">
+ <remove-argument/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ bool ok_;
+ %RETURN_TYPE retval_ =
+ %FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, %8, %9, %10, &amp;ok_);
+ if (!ok_)
+ %PYARG_0 = Py_None;
+ else
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](retval_);
+ </inject-code>
+ </modify-function>
+ </function>
+
+ <!-- Tests add-function for nested template types -->
+ <add-function signature="sum2d(std::list&lt;std::list&lt;int&gt; &gt;)" return-type="int">
+ <inject-code class="target" position="beginning">
+ typedef std::list&lt;int&gt; Inner;
+ typedef std::list&lt;Inner&gt; Outer;
+
+ int result = 0;
+
+ Outer::const_iterator oiter, oend = %1.end();
+ for (oiter = %1.begin(); oiter != oend; ++oiter) {
+ const Inner&amp; inner = *oiter;
+ Inner::const_iterator iiter, iend = inner.end();
+ for (iiter = inner.begin(); iiter != iend; ++iiter)
+ result += *iiter;
+ }
+
+ %PYARG_0 = %CONVERTTOPYTHON[int](result);
+ </inject-code>
+ </add-function>
+
+ <!-- Tests add-function for nested template types -->
+ <add-function signature="sumproduct(std::list&lt;std::pair&lt;int, int&gt; &gt;)" return-type="int">
+ <inject-code class="target" position="beginning">
+ typedef std::pair&lt;int, int&gt; Pair;
+ typedef std::list&lt;Pair&gt; List;
+
+ int result = 0;
+
+ List::const_iterator iter, end = %1.end();
+ for (iter = %1.begin(); iter != end; ++iter)
+ result += iter->first * iter->second;
+
+ %PYARG_0 = %CONVERTTOPYTHON[int](result);
+ </inject-code>
+ </add-function>
+
+
+ <value-type name="InjectCode">
+ <!--
+ Various tests for inject codes.
+ Note: Some uses of inject code here are used just for testing purposes, consider using the add-function tag.
+ -->
+
+ <modify-function signature="sumArrayAndLength(int *) const">
+ <modify-argument index="1">
+ <replace-type modified-type="PyObject"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ int* array = NULL;
+ bool errorOccurred = false;
+
+ if (PySequence_Check(%PYARG_1)) {
+ if((array = Shiboken::sequenceToIntArray(%PYARG_1, true)) == NULL &amp;&amp; PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "Should be a sequence of ints");
+ errorOccurred = true;
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Should be a sequence of ints");
+ errorOccurred = true;
+ }
+
+ if (!errorOccurred) {
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(array);
+ if (array)
+ delete[] array;
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ }
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="arrayMethod(int, int*) const">
+ <modify-argument index="1">
+ <remove-argument/>
+ <conversion-rule class="native">
+ const auto %out = PySequence_Size(%PYARG_1);
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="2">
+ <replace-type modified-type="PySequence"/>
+ <conversion-rule class="native">
+ const auto numItems = PySequence_Size(%PYARG_1);
+ Shiboken::AutoArrayPointer&lt;int&gt; %out(numItems);
+ for (Py_ssize_t i = 0; i &lt; numItems; ++i) {
+ if (%CHECKTYPE[int](PySequence_Fast_GET_ITEM(%PYARG_1, i)))
+ %out[i] = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(%PYARG_1, i));
+ else if (%ISCONVERTIBLE[int](PySequence_Fast_GET_ITEM(%PYARG_1, i)))
+ %out[i] = -1;
+ else
+ %out[i] = -2;
+ }
+ </conversion-rule>
+ <conversion-rule class="target">
+ PyObject* %out = PyList_New(count);
+ for (int i = 0; i &lt; count; ++i)
+ PyList_SET_ITEM(%out, i, %CONVERTTOPYTHON[int](%in[i]));
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+
+ <modify-function signature="callArrayMethod(int, int*) const">
+ <modify-argument index="1">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="2">
+ <replace-type modified-type="PySequence"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ int numItems = PySequence_Size(%PYARG_1);
+ int *cppItems = new int[numItems];
+ for (int i = 0; i &lt; numItems; i++)
+ cppItems[i] = %CONVERTTOCPP[int](PySequence_GetItem(%PYARG_1, i));
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(numItems, cppItems);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ delete[] cppItems;
+ </inject-code>
+ </modify-function>
+
+ <!--
+ Inject the tp_str method using this alternative way
+ Tested in InjectCodeTest.testTypeNativeBeginning_TypeTargetBeginning:
+ -->
+ <inject-code class="native" position="beginning">
+ PyObject* InjectCode_tpstr(PyObject*) { return Shiboken::String::fromCString("Hi! I'm the inject code dummy class."); }
+ </inject-code>
+ <!--
+ Register our tp_str class using another inject code
+ Tested in InjectCodeTest.testTypeNativeBeginning_TypeTargetBeginning:
+ -->
+ <inject-code class="target" position="beginning">
+ %PYTHONTYPEOBJECT.tp_str = InjectCode_tpstr;
+ </inject-code>
+
+ <!-- Tested in InjectCodeTest.testFunctionTargetBeginning_FunctionTargetEnd -->
+ <modify-function signature="simpleMethod1(int, int)">
+ <inject-code class="target" position="beginning">
+ %1 += 1;
+ </inject-code>
+ <inject-code class="target" position="end">
+ PyObject* tmp = Shiboken::String::fromCString("end");
+ Shiboken::String::concat(&amp;%PYARG_0, tmp);
+ Py_DECREF(tmp);
+ </inject-code>
+ </modify-function>
+
+ <!-- Tested in InjectCodeTest.testFunctionTargetBeginning -->
+ <modify-function signature="simpleMethod2()">
+ <inject-code class="target" position="end">
+ PyObject* tmp = Shiboken::String::fromCString("end");
+ Shiboken::String::concat(&amp;%PYARG_0, tmp);
+ Py_DECREF(tmp);
+ </inject-code>
+ </modify-function>
+
+ <!-- Tested in InjectCodeTest.testArgsModification -->
+ <modify-function signature="overloadedMethod(int, char**)">
+ <modify-argument index="1">
+ <replace-type modified-type="PySequence" />
+ </modify-argument>
+ <modify-argument index="2">
+ <remove-argument />
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ int argc;
+ char** argv;
+ if (!Shiboken::listToArgcArgv(%PYARG_1, &amp;argc, &amp;argv)) {
+ PyErr_SetString(PyExc_TypeError, "error");
+ return 0;
+ }
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(argc, argv);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ for (int i = 0; i &lt; argc; ++i)
+ free(argv[i]);
+ delete[] argv;
+ </inject-code>
+ </modify-function>
+
+ <!-- Tested in InjectCodeTest.testArgsModification2 -->
+ <modify-function signature="simpleMethod3(int, char**)">
+ <modify-argument index="1">
+ <replace-type modified-type="PySequence" />
+ </modify-argument>
+ <modify-argument index="2">
+ <remove-argument />
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ int argc;
+ char** argv;
+ if (!Shiboken::listToArgcArgv(%PYARG_1, &amp;argc, &amp;argv)) {
+ PyErr_SetString(PyExc_TypeError, "error");
+ return 0;
+ }
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(argc, argv);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ for (int i = 0; i &lt; argc; ++i)
+ free(argv[i]);
+ delete[] argv;
+ </inject-code>
+ </modify-function>
+ </value-type>
+
+ <value-type name="ImplicitBase"/>
+ <value-type name="SortedOverload">
+ <add-function signature="overload(PyObject *)" return-type="const char *">
+ <inject-code class="target" position="beginning">
+ return Shiboken::String::fromCString("PyObject");
+ </inject-code>
+ </add-function>
+
+ <add-function signature="overloadDeep(int, PyObject *)" return-type="const char *">
+ <inject-code class="target" position="beginning">
+ return Shiboken::String::fromCString("PyObject");
+ </inject-code>
+ </add-function>
+ <modify-function signature="pyObjOverload(unsigned char*, int)">
+ <modify-argument index="1">
+ <replace-type modified-type="PyObject" />
+ <conversion-rule class="native">
+ unsigned char* %out = 0;
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+ <value-type name="ImplicitTarget"/>
+
+ <object-type name="CustomOverloadSequence">
+ <modify-function signature="overload(int) const" overload-number="0"/>
+ <modify-function signature="overload(short) const" overload-number="1"/>
+ </object-type>
+
+ <value-type name="Point">
+ <add-function signature="__str__" return-type="PyObject*">
+ <inject-code class="target" position="beginning">
+ int x1 = (int) %CPPSELF.x();
+ int x2 = ((int) (%CPPSELF.x() * 100)) - (x1 * 100);
+ int y1 = (int) %CPPSELF.y();
+ int y2 = ((int) (%CPPSELF.y() * 100)) - (y1 * 100);
+ %PYARG_0 = Shiboken::String::fromFormat("Point(%d.%d, %d.%d)", x1, x2, y1, y2);
+ </inject-code>
+ </add-function>
+ <add-function signature="__repr__" return-type="PyObject*">
+ <inject-code class="target" position="beginning">
+ int x1 = (int) %CPPSELF.x();
+ int x2 = ((int) (%CPPSELF.x() * 10)) - (x1 * 10);
+ int y1 = (int) %CPPSELF.y();
+ int y2 = ((int) (%CPPSELF.y() * 10)) - (y1 * 10);
+ %PYARG_0 = Shiboken::String::fromFormat("&lt;Point object at %p: (%d.%d, %d.%d)&gt;", %CPPSELF, x1, x2, y1, y2);
+ </inject-code>
+ </add-function>
+
+ <add-function signature="__reduce__" return-type="PyObject*">
+ <inject-code class="target" position="beginning">
+ PyObject* type = PyObject_Type(%PYSELF);
+ PyObject* args = NULL;
+
+ args = Py_BuildValue("(dd)", %CPPSELF.x(), %CPPSELF.y());
+
+ %PYARG_0 = Py_BuildValue("(OO)", type, args);
+ </inject-code>
+ </add-function>
+
+ <modify-function signature="midpoint(const Point&amp;, Point*)const">
+ <modify-argument index="2">
+ <remove-argument />
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="Point" />
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ Point _midpoint;
+ // The test consists in *NOT* using the ARGUMENT_NAMES type system variable.
+ %CPPSELF.%FUNCTION_NAME(%1, &amp;_midpoint);
+ %PYARG_0 = %CONVERTTOPYTHON[Point](_midpoint);
+ </inject-code>
+ </modify-function>
+
+ <template name="return_self">
+ %PYARG_0 = %PYARG_1;
+ Py_INCREF(%PYARG_1);
+ </template>
+ <add-function signature="operator-(PyUnicode)">
+ <inject-code>
+ <insert-template name="return_self" />
+ </inject-code>
+ </add-function>
+ <!-- A reverse operator -->
+ <add-function signature="operator-(PyUnicode, Point)">
+ <inject-code>
+ <insert-template name="return_self" />
+ </inject-code>
+ </add-function>
+ </value-type>
+
+ <value-type name="PointF">
+ <add-function signature="__str__" return-type="PyObject*">
+ <inject-code class="target" position="beginning">
+ int x1 = (int) %CPPSELF.x();
+ int x2 = ((int) (%CPPSELF.x() * 100)) - (x1 * 100);
+ int y1 = (int) %CPPSELF.y();
+ int y2 = ((int) (%CPPSELF.y() * 100)) - (y1 * 100);
+ %PYARG_0 = Shiboken::String::fromFormat("PointF(%d.%d, %d.%d)", x1, x2, y1, y2);
+ </inject-code>
+ </add-function>
+ <add-function signature="__repr__" return-type="PyObject*">
+ <inject-code class="target" position="beginning">
+ int x1 = (int) %CPPSELF.x();
+ int x2 = ((int) (%CPPSELF.x() * 10)) - (x1 * 10);
+ int y1 = (int) %CPPSELF.y();
+ int y2 = ((int) (%CPPSELF.y() * 10)) - (y1 * 10);
+ %PYARG_0 = Shiboken::String::fromFormat("&lt;PointF object at %p: (%d.%d, %d.%d)&gt;", %CPPSELF, x1, x2, y1, y2);
+ </inject-code>
+ </add-function>
+
+ <add-function signature="__reduce__" return-type="PyObject*">
+ <inject-code class="target" position="beginning">
+ PyObject *type = PyObject_Type(%PYSELF);
+ PyObject *args = NULL;
+
+ args = Py_BuildValue("(dd)", %CPPSELF.x(), %CPPSELF.y());
+
+ %PYARG_0 = Py_BuildValue("(OO)", type, args);
+ </inject-code>
+ </add-function>
+
+ <modify-function signature="midpoint(const PointF&amp;, PointF*)const">
+ <modify-argument index="2">
+ <remove-argument />
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PointF" />
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ PointF _midpoint;
+ // The test consists in using the ARGUMENT_NAMES type system variable.
+ %CPPSELF.%FUNCTION_NAME(%ARGUMENT_NAMES, &amp;_midpoint);
+ %PYARG_0 = %CONVERTTOPYTHON[PointF](_midpoint);
+ </inject-code>
+ </modify-function>
+ </value-type>
+
+ <value-type name="Rect" />
+ <value-type name="RectF" />
+
+ <value-type name="Polygon">
+ <modify-function signature="stealOwnershipFromPython(Point*)">
+ <modify-argument index="1">
+ <define-ownership owner="c++"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="stealOwnershipFromPython(Polygon*)">
+ <modify-argument index="1">
+ <define-ownership owner="c++"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+ <value-type name="Time">
+ <extra-includes>
+ <include file-name="datetime.h" location="global"/>
+ </extra-includes>
+ <enum-type name="NumArgs"/>
+ <add-function signature="operator!=(const PyObject*)" return-type="PyObject">
+ <inject-code>
+ if (!PyDateTimeAPI)
+ PyDateTime_IMPORT;
+ if (PyTime_Check(%1)) {
+ int pyH = PyDateTime_TIME_GET_HOUR(%1);
+ int pyM = PyDateTime_TIME_GET_MINUTE(%1);
+ int pyS = PyDateTime_TIME_GET_SECOND(%1);
+ if ((pyH == %CPPSELF.hour()) &amp;&amp;
+ (pyM == %CPPSELF.minute()) &amp;&amp;
+ (pyS == %CPPSELF.second()))
+ %PYARG_0 = Py_False;
+ else
+ %PYARG_0 = Py_True;
+ Py_INCREF(%PYARG_0);
+ }
+ </inject-code>
+ </add-function>
+ <add-function signature="operator==(const PyObject*)" return-type="PyObject">
+ <inject-code>
+ if (!PyDateTimeAPI)
+ PyDateTime_IMPORT;
+ if (PyTime_Check(%1)) {
+ int pyH = PyDateTime_TIME_GET_HOUR(%1);
+ int pyM = PyDateTime_TIME_GET_MINUTE(%1);
+ int pyS = PyDateTime_TIME_GET_SECOND(%1);
+ if ((pyH == %CPPSELF.hour()) &amp;&amp;
+ (pyM == %CPPSELF.minute()) &amp;&amp;
+ (pyS == %CPPSELF.second()))
+ %PYARG_0 = Py_True;
+ else
+ %PYARG_0 = Py_False;
+ Py_INCREF(%PYARG_0);
+ }
+ </inject-code>
+ </add-function>
+
+ </value-type>
+ <value-type name="Size">
+ <extra-includes>
+ <include file-name="string" location="global"/>
+ <include file-name="sstream" location="global"/>
+ </extra-includes>
+ <add-function signature="Size(const char*)">
+ <inject-code class="target" position="beginning"
+ file="samplesnippets.cpp" snippet="size_char_ct"/>
+ </add-function>
+ </value-type>
+ <value-type name="SizeF"/>
+ <function signature="SnakeCaseGlobalFunction()" snake-case="yes"/>
+ <object-type name="SnakeCaseTest" snake-case="yes">
+ <modify-function signature="testFunctionDisabled()const" snake-case="no"/>
+ <modify-function signature="testFunctionBoth()const" snake-case="both"/>
+ <modify-field name="testFieldDisabled" snake-case="no"/>
+ <modify-field name="testFieldBoth" snake-case="both"/>
+ </object-type>
+ <object-type name="SnakeCaseDerivedTest" snake-case="yes"/>
+ <value-type name="MapUser"/>
+ <value-type name="PairUser"/>
+ <value-type name="ListUser">
+ <enum-type name="ListOfSomething"/>
+ </value-type>
+ <value-type name="NoImplicitConversion" />
+ <value-type name="NonDefaultCtor" />
+ <value-type name="OddBoolUser" />
+ <object-type name="Overload">
+ <enum-type name="FunctionEnum"/>
+ <enum-type name="ParamEnum"/>
+ <modify-function signature="intOverloads(int, int, double)">
+ <modify-argument index="2">
+ <remove-argument />
+ </modify-argument>
+ <inject-code class="target">
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%1, 2, %3);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </modify-function>
+ <modify-function signature="singleOverload(Point*)">
+ <modify-argument index="1">
+ <define-ownership owner="c++"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="acceptSequence(const char*const[])">
+ <modify-argument index="1">
+ <replace-type modified-type="PySequence" />
+ <conversion-rule class="native">
+ {
+ Shiboken::AutoDecRef strList(PySequence_Fast(%PYARG_1, "The argument must be a sequence."));
+ int lineCount = PySequence_Fast_GET_SIZE(strList.object());
+ for (int line = 0; line &lt; lineCount; ++line) {
+ if (!Shiboken::String::check(PySequence_Fast_GET_ITEM(strList.object(), line))) {
+ PyErr_SetString(PyExc_TypeError, "The argument must be a sequence of strings.");
+ break;
+ }
+ }
+ }
+ // PySIDE-1735: Enums are now implemented in Python, so we need to avoid asserts.
+ if (PyErr_Occurred())
+ break;
+ const char** %out = 0;
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="acceptSequence(void*)">
+ <modify-argument index="1">
+ <replace-type modified-type="PyObject" />
+ <conversion-rule class="native">
+ void* %out = 0;
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+
+ <template name="buffer_argument">
+ unsigned char* %out = (unsigned char*) Shiboken::Buffer::getPointer(%PYARG_1);
+ </template>
+
+ <modify-function signature="strBufferOverloads(unsigned char*,int)">
+ <modify-argument index="1">
+ <replace-type modified-type="PyBuffer"/>
+ <conversion-rule class="native">
+ <insert-template name="buffer_argument" />
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+ <!--
+ This added function simulates the solution given to PySide's QImage
+ constructor problem, as seen in PySide/bbba1cc4, and described in
+ bug #489 [http://bugs.pyside.org/show_bug.cgi?id=489].
+ This is not the best solution, just one that works. The proper way
+ to handle it would be to fix the overload decisor.
+ -->
+ <add-function signature="strBufferOverloads(Str&amp;,int)" return-type="Overload::FunctionEnum">
+ <inject-code class="target" position="beginning">
+ <insert-template name="buffer_argument">
+ <replace from="%out" to="argOut" />
+ </insert-template>
+ %BEGIN_ALLOW_THREADS
+ %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(argOut, %2);
+ %END_ALLOW_THREADS
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+ </object-type>
+ <object-type name="Overload2" />
+
+ <object-type name="Collector" stream="yes"/>
+
+ <value-type name="IntWrapper">
+ <inject-code class="native" position="beginning"
+ file="samplesnippets.cpp" snippet="intwrapper_add_ints"/>
+ <add-pymethoddef name="add_ints" function="Sbk_IntWrapper_add_ints"
+ flags="METH_VARARGS"/>
+ </value-type>
+
+ <value-type name="Str" hash-function="strHash">
+ <add-function signature="__str__" return-type="PyObject*">
+ <inject-code class="target" position="beginning">
+ %PYARG_0 = Shiboken::String::fromCString(%CPPSELF.cstring());
+ </inject-code>
+ </add-function>
+ <add-function signature="__len__" >
+ <inject-code class="target" position="end">
+ return %CPPSELF.size();
+ </inject-code>
+ </add-function>
+ <add-function signature="__getitem__" >
+ <inject-code class="target" position="beginning">
+ if (_i &lt; 0 || _i >= %CPPSELF.size()) {
+ PyErr_BadArgument();
+ return 0;
+ } else {
+ char res[2];
+ res[0] = %CPPSELF.get_char(_i);
+ res[1] = 0;
+ return Shiboken::String::fromCString(res);
+ }
+ </inject-code>
+ </add-function>
+ <add-function signature="__setitem__" >
+ <inject-code class="target" position="beginning">
+ PyObject* args = Py_BuildValue("(iO)", _i, _value);
+ PyObject* result = Sbk_StrFunc_set_char(self, args);
+ Py_DECREF(args);
+ int ok = result == Py_True;
+ if (result) {
+ Py_DECREF(result);
+ }
+ return !ok ? -1 : 0;
+ </inject-code>
+ </add-function>
+ <modify-function signature="toInt(bool*, int)const">
+ <modify-argument index="1">
+ <remove-argument/>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject*"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ <insert-template name="boolptr_at_start_and_one_arg_fix_beginning"/>
+ </inject-code>
+ <inject-code class="target" position="end">
+ <insert-template name="boolptr_fix_end"/>
+ </inject-code>
+ </modify-function>
+ </value-type>
+
+ <value-type name="ByteArray" hash-function="ByteArray::hash">
+ <conversion-rule>
+ <target-to-native>
+ <add-conversion type="Py_None">
+ SBK_UNUSED(%in)
+ %out = %OUTTYPE();
+ </add-conversion>
+ <add-conversion type="PyObject" check="Shiboken::String::check(%in) || PyBytes_Check(%in)">
+ Py_ssize_t len;
+ const char* str = Shiboken::String::toCString(%in, &amp;len);
+ %out = %OUTTYPE(str, len);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+
+ <modify-function signature="ByteArray(const char*,int)" remove="all" />
+ <modify-function signature="ByteArray(const char*)" remove="all" >
+ <!-- Keep \x00 bytes passed in Python strings. -->
+ <modify-argument index="1">
+ <replace-type modified-type="PyBytes"/>
+ </modify-argument>
+ <inject-code class="target" position="beginning">
+ PyObject* data = 0;
+ if (PyUnicode_CheckExact(%PYARG_1)) {
+ data = PyUnicode_AsASCIIString(%PYARG_1);
+ } else {
+ data = %PYARG_1;
+ Py_INCREF(data);
+ }
+
+ %0 = new %TYPE(PyBytes_AsString(data), PyBytes_GET_SIZE(data));
+ Py_DECREF(data);
+ </inject-code>
+ </modify-function>
+
+ <!-- buffer protocol -->
+ <inject-code class="target" position="end">
+ </inject-code>
+
+ <modify-function signature="data() const">
+ <inject-code class="target" position="beginning">
+ %PYARG_0 = PyBytes_FromStringAndSize(%CPPSELF.%FUNCTION_NAME(), %CPPSELF.size());
+ </inject-code>
+ </modify-function>
+
+ <modify-function signature="hash(const ByteArray&amp;)" remove="all" />
+ <!-- Functions removed to proper deal with strings containing zeroes -->
+ <modify-function signature="append(const char*)" remove="all" />
+ <modify-function signature="append(const char*,int)" remove="all" />
+ <modify-function signature="operator==(const char*,ByteArray)" remove="all" />
+ <modify-function signature="operator==(ByteArray,const char*)" remove="all" />
+ <modify-function signature="operator!=(const char*,ByteArray)" remove="all" />
+ <modify-function signature="operator!=(ByteArray,const char*)" remove="all" />
+ <modify-function signature="operator+(ByteArray,const char*)" remove="all" />
+ <modify-function signature="operator+(const char*,ByteArray)" remove="all" />
+ <modify-function signature="operator+=(const char*)" remove="all" />
+ <modify-function signature="operator[](int)const" remove="all"/>
+
+ <add-function signature="operator+(PyUnicode)" return-type="ByteArray">
+ <inject-code>
+ Shiboken::AutoDecRef data(PyUnicode_AsASCIIString(%PYARG_1));
+ if (!data.isNull()) {
+ ByteArray ba(*%CPPSELF);
+ ba.append(PyBytes_AsString(data.object()), PyBytes_GET_SIZE(data.object()));
+ %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba);
+ }
+ </inject-code>
+ </add-function>
+ <add-function signature="operator+(PyUnicode,ByteArray)" return-type="ByteArray">
+ <inject-code>
+ Shiboken::AutoDecRef data(PyUnicode_AsASCIIString(%PYARG_1));
+ if (!data.isNull()) {
+ ByteArray ba(PyBytes_AsString(data.object()), PyBytes_GET_SIZE(data.object()));
+ ba.append(*%CPPSELF);
+ %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba);
+ }
+ </inject-code>
+ </add-function>
+ <add-function signature="operator+(PyBytes,ByteArray)">
+ <inject-code>
+ ByteArray ba(PyBytes_AsString(%PYARG_1), PyBytes_GET_SIZE(%PYARG_1));
+ ba = ba + *%CPPSELF;
+ %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba);
+ </inject-code>
+ </add-function>
+ <add-function signature="operator+(PyBytes)">
+ <inject-code>
+ ByteArray ba(PyBytes_AsString(%PYARG_1), PyBytes_GET_SIZE(%PYARG_1));
+ ba.append(*%CPPSELF);
+ %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba);
+ </inject-code>
+ </add-function>
+ <add-function signature="__repr__" return-type="PyObject*">
+ <inject-code class="target" position="beginning">
+ ByteArray b(Py_TYPE(%PYSELF)->tp_name);
+ PyObject* aux = Shiboken::String::fromStringAndSize(%CPPSELF.data(), %CPPSELF.size());
+ if (PyUnicode_CheckExact(aux)) {
+ PyObject* tmp = PyUnicode_AsASCIIString(aux);
+ Py_DECREF(aux);
+ aux = tmp;
+ }
+ b += "('";
+ b += ByteArray(PyBytes_AS_STRING(aux), PyBytes_GET_SIZE(aux));
+ b += "')";
+ %PYARG_0 = Shiboken::String::fromStringAndSize(b.data(), b.size());
+ </inject-code>
+ </add-function>
+
+ <add-function signature="__str__" return-type="str">
+ <inject-code class="target" position="beginning">
+ %PYARG_0 = Shiboken::String::fromStringAndSize(%CPPSELF.data(), %CPPSELF.size());
+ </inject-code>
+ </add-function>
+
+ <add-function signature="__len__">
+ <inject-code class="target" position="beginning">
+ return %CPPSELF.size();
+ </inject-code>
+ </add-function>
+ <add-function signature="__getitem__">
+ <inject-code class="target" position="beginning">
+ if (_i &lt; 0 || _i >= %CPPSELF.size()) {
+ PyErr_SetString(PyExc_IndexError, "index out of bounds");
+ return 0;
+ } else {
+ char res[2];
+ res[0] = %CPPSELF.at(_i);
+ res[1] = 0;
+ return PyBytes_FromStringAndSize(res, 1);
+ }
+ </inject-code>
+ </add-function>
+ </value-type>
+
+ <value-type name="StrList">
+ <enum-type name="CtorEnum"/>
+ <add-function signature="__len__" >
+ <inject-code class="target" position="end">
+ return %CPPSELF.size();
+ </inject-code>
+ </add-function>
+ <add-function signature="__getitem__" >
+ <inject-code class="target" position="beginning">
+ if (_i &lt; 0 || _i >= static_cast&lt;Py_ssize_t>(%CPPSELF.size())) {
+ PyErr_BadArgument();
+ return 0;
+ } else {
+ %TYPE::const_iterator it = %CPPSELF.begin();
+ for (Py_ssize_t i = 1; i &lt;= _i; i++)
+ ++it;
+ return %CONVERTTOPYTHON[Str](*it);
+ }
+ </inject-code>
+ </add-function>
+ </value-type>
+
+ <object-type name="SimpleFile">
+ <modify-function signature="open()">
+ <modify-argument index="return">
+ <remove-argument/>
+ </modify-argument>
+ <inject-code class="target" position="end" file="simplefile_glue.cpp"/>
+ </modify-function>
+ </object-type>
+
+ <value-type name="VoidHolder" />
+
+ <object-type name="PrivateCtor" />
+ <object-type name="PrivateDtor" />
+ <value-type name="DeletedDefaultCtor"/>
+
+ <object-type name="Base1"/>
+ <object-type name="Base2"/>
+ <object-type name="Base3"/>
+ <object-type name="Base4"/>
+ <object-type name="Base5"/>
+ <object-type name="Base6"/>
+ <object-type name="MDerived1"/>
+ <object-type name="MDerived2"/>
+ <object-type name="MDerived3"/>
+ <object-type name="MDerived4"/>
+ <object-type name="MDerived5"/>
+ <object-type name="SonOfMDerived1"/>
+
+ <object-type name="Bucket" private="true">
+ <modify-function signature="lock()" allow-thread="yes" />
+ <modify-function signature="virtualBlockerMethod()" allow-thread="yes"/>
+ <modify-function signature="callVirtualBlockerMethodButYouDontKnowThis()" allow-thread="yes"/>
+ </object-type>
+
+ <value-type name="Echo">
+ <add-function signature="echo(const char *)" return-type="PyObject*">
+ <inject-code class="target" position="beginning">
+ %PYARG_0 = Shiboken::String::fromCString(%1);
+ </inject-code>
+ </add-function>
+ <add-function signature="operator>(int)">
+ <inject-code>
+ // This should test if code injections works inside rich comparison operators
+ Py_INCREF(Py_True);
+ %PYARG_0 = Py_True;
+ </inject-code>
+ </add-function>
+ </value-type>
+
+ <value-type name="Color" />
+ <value-type name="Brush" operator-bool="true">
+ <enum-type name="Style"/>
+ </value-type>
+ <value-type name="Pen">
+ <enum-type identified-by-value="EnumCtor"/>
+ <enum-type name="RenderHints"/>
+ <property type="RenderHints" name="renderHints" get="getRenderHints" set="setRenderHints"/>
+ </value-type>
+
+ <value-type name="CtorConvRule" private="true">
+ <modify-function signature="CtorConvRule(long)">
+ <modify-argument index="1">
+ <!--<replace-type modified-type="long"/>-->
+ <conversion-rule class="native">
+ // Does nothing really, just test the code generation
+ // of constructors whose arguments where
+ long %out = PyLong_AS_LONG(%PYARG_1) + 1;
+ </conversion-rule>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+ <add-function signature="multiplyString(str, unsigned int)" return-type="const char*">
+ <inject-code class="target" position="beginning">
+ %PYARG_0 = Shiboken::String::fromCString("");
+ for (unsigned int i = 0; i &lt; %2; ++i)
+ Shiboken::String::concat(&amp;%PYARG_0, %PYARG_1);
+ </inject-code>
+ </add-function>
+
+ <add-function signature="countVarargs(int, ...)" return-type="int">
+ <inject-code class="target" position="beginning">
+ %RETURN_TYPE %0 = PyTuple_GET_SIZE(%PYARG_2);
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+
+ <value-type name="SbkDate">
+ <extra-includes>
+ <include file-name="datetime.h" location="global"/>
+ </extra-includes>
+ <inject-code class="native" position="beginning">
+ static bool PyDate_ImportAndCheck(PyObject* pyIn) {
+ if (!PyDateTimeAPI)
+ PyDateTime_IMPORT;
+ return PyDate_Check(pyIn);
+ }
+ </inject-code>
+ <conversion-rule>
+ <target-to-native>
+ <add-conversion type="PyDate" check="PyDate_ImportAndCheck(%in)">
+ int day = PyDateTime_GET_DAY(%in);
+ int month = PyDateTime_GET_MONTH(%in);
+ int year = PyDateTime_GET_YEAR(%in);
+ %out = %OUTTYPE(day, month, year);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ <add-function signature="toPython()" return-type="PyDate">
+ <inject-code class="target">
+ if (!PyDateTimeAPI)
+ PyDateTime_IMPORT;
+ %PYARG_0 = PyDate_FromDate(%CPPSELF.day(), %CPPSELF.month(), %CPPSELF.year());
+ </inject-code>
+ </add-function>
+ </value-type>
+
+ <object-type name="HandleHolder" />
+ <value-type name="PrimitiveStructPointerHolder" />
+
+ <object-type name="ObjectTypeOperators">
+ <add-function signature="operator!=(std::string)" return-type="bool">
+ <inject-code class="target">
+ %RETURN_TYPE %0 = %CPPSELF.key() != %1;
+ %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+ </object-type>
+
+ <value-type name="Filter" />
+ <value-type name="Data">
+ <enum-type name="Field" />
+ <add-function signature="operator&amp;(const Union&amp;)" return-type="Intersection">
+ <inject-code class="target">
+ %RETURN_TYPE %0 = *%CPPSELF &amp; %1;
+ return %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+ </value-type>
+ <value-type name="Union">
+ <add-function signature="operator&amp;(const Data&amp;)" return-type="Intersection">
+ <inject-code class="target">
+ %RETURN_TYPE %0 = *%CPPSELF &amp; %1;
+ return %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+ </inject-code>
+ </add-function>
+ </value-type>
+ <value-type name="Intersection" />
+
+ <!-- type used in abstract method -->
+ <object-type name="HideType" generate="no" />
+
+ <value-type name="Expression" />
+
+ <object-type name="ExceptionTest" exception-handling="auto-on">
+ <modify-function signature="create(bool)">
+ <modify-argument index="return">
+ <define-ownership owner="c++"/>
+ </modify-argument>
+ <inject-code class="target" position="end">
+ // Test comment
+ </inject-code>
+ </modify-function>
+ </object-type>
+
+ <value-type name="ModelIndex" />
+ <value-type name="ReferentModelIndex">
+ <modify-function signature="operator const ModelIndex&amp;()const">
+ <modify-argument index="return">
+ <define-ownership owner="c++"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+ <value-type name="PersistentModelIndex" />
+
+ <!-- test rejections using full signatures; this method is a template and
+ cannot be wrapped, but is otherwise recognized by shiboken and will
+ result in a compile error if the rejection is not matched -->
+ <rejection class="Photon::Base" function-name="isType()"/>
+
+ <value-type name="ValueAndVirtual" />
+
+ <object-type name="ObjectTypeByValue" />
+
+ <value-type name="StdComplex">
+ <extra-includes>
+ <include file-name="cmath" location="global"/>
+ </extra-includes>
+ <!-- PYSIDE-2446: number protocols without a Py_nb_ constant. -->
+ <add-function signature="__floor__()" return-type="double">
+ <inject-code class="target" position="end"
+ file="samplesnippets.cpp" snippet="stdcomplex_floor"/>
+ </add-function>
+ <add-function signature="__ceil__()" return-type="double">
+ <inject-code class="target" position="end"
+ file="samplesnippets.cpp" snippet="stdcomplex_ceil"/>
+ </add-function>
+ <!-- PYSIDE-2446: number protocols with Py_nb_ constants. -->
+ <add-function signature="__abs__()" return-type="double">
+ <inject-code class="target" position="end"
+ file="samplesnippets.cpp" snippet="stdcomplex_abs"/>
+ </add-function>
+ <add-function signature="__pow__(StdComplex@exp@)" return-type="StdComplex">
+ <inject-code class="target" position="end"
+ file="samplesnippets.cpp" snippet="stdcomplex_pow"/>
+ </add-function>
+
+ </value-type>
+
+ <object-type name="TemplatePtr">
+ <modify-function signature="dummy(std::list&lt;std::pair&lt;BlackBox *, BlackBox *&gt; &gt; &amp;)" rename="dummy_method" />
+ </object-type>
+
+ <value-type name="ToBeRenamedValue" target-lang-name="RenamedValue"/>
+ <value-type name="RenamedUser"/>
+
+ <enum-type name="LengthUnit"/>
+ <value-type name="ValueWithUnit" generate="no"/>
+ <typedef-type name="ValueWithUnitDoubleInch" source="ValueWithUnit&lt;double,LengthUnit::Inch&gt;"/>
+ <typedef-type name="ValueWithUnitDoubleMillimeter" source="ValueWithUnit&lt;double,LengthUnit::Millimeter&gt;"/>
+ <value-type name="ValueWithUnitUser"/>
+
+ <suppress-warning text="horribly broken type '__off64_t'" />
+ <suppress-warning text="enum '__codecvt_result' does not have a type entry or is not an enum" />
+ <suppress-warning text="Pure virtual method 'Abstract::hideFunction(HideType*)' must be implemented but was completely removed on type system." />
+ <suppress-warning text="Shadowing: MDerived2::castToBase3() and MDerived3::castToBase3()" />
+ <suppress-warning text="Visibility of function 'publicMethod' modified in class 'MDerived1'" />
+
+ <suppress-warning text="^skipping public function 'std::enable_if.*ComparisonTester::operator[!=]=.*ComparisonTester.*$"/>
+</typesystem>
diff --git a/sources/shiboken6/tests/samplebinding/typesystypedef_test.py b/sources/shiboken6/tests/samplebinding/typesystypedef_test.py
new file mode 100644
index 000000000..f7f5342ee
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/typesystypedef_test.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for a class that holds a void pointer.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ValueWithUnitUser, ValueWithUnitDoubleInch
+
+
+class TypeSysTypeDefTest(unittest.TestCase):
+ '''Test case type system typedefs.'''
+
+ def test(self):
+ inch_value = ValueWithUnitDoubleInch(10)
+ mm_value = ValueWithUnitUser.doubleInchToMillimeter(inch_value)
+ self.assertEqual(int(mm_value.value()), 2540)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/unsafe_parent_test.py b/sources/shiboken6/tests/samplebinding/unsafe_parent_test.py
new file mode 100644
index 000000000..2a7e5cac7
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/unsafe_parent_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for ...'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType
+
+
+class DerivedObjectType(ObjectType):
+ def isPython(self):
+ return True
+
+ def createChild(self, parent):
+ return DerivedObjectType(parent)
+
+
+class ParentTest(unittest.TestCase):
+
+ def testUunsafeParent(self):
+ o = DerivedObjectType()
+ o.callVirtualCreateChild()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/useraddedctor_test.py b/sources/shiboken6/tests/samplebinding/useraddedctor_test.py
new file mode 100644
index 000000000..45d4095b6
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/useraddedctor_test.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for user added constructors'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from sample import Size
+
+
+class PointTest(unittest.TestCase):
+ def testUsingSelfOnCtor(self):
+ # This is a user added ctor and no errors should happen!
+ s = Size("3x2")
+ self.assertEqual(s.height(), 2)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/virtualdtor_test.py b/sources/shiboken6/tests/samplebinding/virtualdtor_test.py
new file mode 100644
index 000000000..6be870269
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/virtualdtor_test.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for virtual destructor.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import VirtualDtor
+
+
+class ExtendedVirtualDtor(VirtualDtor):
+ def __init__(self):
+ VirtualDtor.__init__(self)
+
+
+class VirtualDtorTest(unittest.TestCase):
+ '''Test case for virtual destructor.'''
+
+ def setUp(self):
+ VirtualDtor.resetDtorCounter()
+
+ def testVirtualDtor(self):
+ '''Original virtual destructor is being called.'''
+ dtor_called = VirtualDtor.dtorCalled()
+ for i in range(1, 10):
+ vd = VirtualDtor()
+ del vd
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(VirtualDtor.dtorCalled(), dtor_called + i)
+
+ def testVirtualDtorOnCppCreatedObject(self):
+ '''Original virtual destructor is being called for a C++ created object.'''
+ dtor_called = VirtualDtor.dtorCalled()
+ for i in range(1, 10):
+ vd = VirtualDtor.create()
+ del vd
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(VirtualDtor.dtorCalled(), dtor_called + i)
+
+ def testDtorOnDerivedClass(self):
+ '''Original virtual destructor is being called for a derived class.'''
+ dtor_called = ExtendedVirtualDtor.dtorCalled()
+ for i in range(1, 10):
+ evd = ExtendedVirtualDtor()
+ del evd
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(ExtendedVirtualDtor.dtorCalled(), dtor_called + i)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/virtualmethods_test.py b/sources/shiboken6/tests/samplebinding/virtualmethods_test.py
new file mode 100644
index 000000000..52dc66c90
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/virtualmethods_test.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for virtual methods.'''
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point, Str, StrList, VirtualDaughter, VirtualMethods
+
+import warnings
+
+
+class ExtendedVirtualMethods(VirtualMethods):
+ def __init__(self):
+ VirtualMethods.__init__(self)
+ self.virtual_method0_called = False
+
+ def virtualMethod0(self, pt, val, cpx, b):
+ self.virtual_method0_called = True
+ return VirtualMethods.virtualMethod0(self, pt, val, cpx, b) * -1.0
+
+ def strListToStdList(self, arg):
+ warnings.simplefilter('error')
+ # returning wrong type for test purposes.
+ return True
+
+ def recursionOnModifiedVirtual(self, arg):
+ # check if recursion is caused by injected code that calls C++.
+ return VirtualMethods.recursionOnModifiedVirtual(self, arg) + 10
+
+
+class ExtendedVirtualDaughter(VirtualDaughter):
+ def __init__(self, name):
+ VirtualDaughter.__init__(self, name)
+ self.grand_daughter_name_called = False
+
+ def name(self):
+ self.grand_daughter_name_called = True
+ return VirtualDaughter.name(self).prepend('Extended')
+
+
+class ExtendedExtendedVirtualDaughter(ExtendedVirtualDaughter):
+ def __init__(self, name):
+ ExtendedVirtualDaughter.__init__(self, name)
+ self.grand_grand_daughter_name_called = False
+
+ def name(self):
+ self.grand_grand_daughter_name_called = True
+ return ExtendedVirtualDaughter.name(self).prepend('Extended')
+
+
+class VirtualMethodsTest(unittest.TestCase):
+ '''Test case for virtual methods'''
+
+ def setUp(self):
+ self.prefix_from_codeinjection = Str('Pimped')
+
+ def tearDown(self):
+ del self.prefix_from_codeinjection
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+
+ def testReimplementedVirtualMethod0(self):
+ '''Test Python override of a virtual method with various different parameters
+ is correctly called from C++.'''
+ vm = VirtualMethods()
+ evm = ExtendedVirtualMethods()
+ pt = Point(1.1, 2.2)
+ val = 4
+ cpx = complex(3.3, 4.4)
+ b = True
+ result0 = vm.callVirtualMethod0(pt, val, cpx, b)
+ result1 = evm.callVirtualMethod0(pt, val, cpx, b)
+ self.assertEqual(result0 * -1.0, result1)
+
+ def testRecursionOnModifiedVirtual(self):
+ evm = ExtendedVirtualMethods()
+ self.assertEqual(evm.recursionOnModifiedVirtual(''), 10)
+ self.assertEqual(evm.callRecursionOnModifiedVirtual(''), 10)
+
+ def testReimplementedVirtualMethodInheritedFromGrandParent(self):
+ '''Test Python override of a virtual method inherited from a grand parent.'''
+ original_name = 'Foo'
+ evd = ExtendedVirtualDaughter(original_name)
+
+ self.assertEqual(VirtualDaughter.name(evd), original_name)
+ self.assertEqual(VirtualMethods.name(evd), original_name)
+ self.assertFalse(evd.grand_daughter_name_called)
+
+ name = evd.callName()
+ self.assertTrue(evd.grand_daughter_name_called)
+ self.assertEqual(evd.name().prepend(self.prefix_from_codeinjection), name)
+
+ def testReimplementedVirtualMethodInheritedFromGrandGrandParent(self):
+ '''Test Python override of a virtual method inherited from a grand grand parent.'''
+ original_name = 'Foo'
+ eevd = ExtendedExtendedVirtualDaughter(original_name)
+
+ self.assertEqual(VirtualDaughter.name(eevd), original_name)
+ self.assertEqual(VirtualMethods.name(eevd), original_name)
+ self.assertFalse(eevd.grand_daughter_name_called)
+ self.assertFalse(eevd.grand_grand_daughter_name_called)
+
+ name = eevd.callName()
+ self.assertTrue(eevd.grand_daughter_name_called)
+ self.assertTrue(eevd.grand_grand_daughter_name_called)
+ self.assertEqual(eevd.name().prepend(self.prefix_from_codeinjection), name)
+
+ def testStringView(self):
+ virtual_methods = VirtualMethods()
+ self.assertEqual(virtual_methods.stringViewLength('bla'), 3)
+
+
+class PrettyErrorMessageTest(unittest.TestCase):
+ def testIt(self):
+ obj = ExtendedVirtualMethods()
+ self.assertRaises(RuntimeWarning, obj.callStrListToStdList, StrList())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/visibilitychange_test.py b/sources/shiboken6/tests/samplebinding/visibilitychange_test.py
new file mode 100644
index 000000000..becdf7423
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/visibilitychange_test.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Base1, MDerived1
+
+
+class VisibilityChangeTest(unittest.TestCase):
+
+ def testVisibilityChange(self):
+ b1 = Base1()
+ b1.publicMethod() # ok...
+ d1 = MDerived1()
+ self.assertRaises(TypeError, d1.publicMethod)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/voidholder_test.py b/sources/shiboken6/tests/samplebinding/voidholder_test.py
new file mode 100644
index 000000000..186cb473e
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/voidholder_test.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test case for a class that holds a void pointer.'''
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import VoidHolder, Point
+from shiboken6 import Shiboken
+
+
+class VoidHolderTest(unittest.TestCase):
+ '''Test case for void pointer manipulation.'''
+
+ def testGetVoidPointerFromCppAndPutsOnVoidHolder(self):
+ '''Passes a void pointer created in C++ to be kept by VoidHolder.'''
+ voidptr = VoidHolder.gimmeMeSomeVoidPointer()
+ voidholder = VoidHolder(voidptr)
+ self.assertEqual(voidptr, voidholder.voidPointer())
+
+ def testPassVoidPointerAsArgument(self):
+ '''Passes a void pointer created in C++ as an argument to a function.'''
+ voidptr = VoidHolder.gimmeMeSomeVoidPointer()
+ voidHolder = VoidHolder()
+ returnValue = voidHolder.takeVoidPointer(voidptr)
+ self.assertEqual(returnValue, voidptr)
+
+ def testPutRandomObjectInsideVoidHolder(self):
+ '''Passes a C++ pointer for an object created in Python to be kept by VoidHolder.'''
+ obj = Point(1, 2)
+ voidholder = VoidHolder(obj)
+ self.assertEqual(Shiboken.getCppPointer(obj)[0], int(voidholder.voidPointer()))
+
+ def testGetNoneObjectFromVoidHolder(self):
+ '''A VoidHolder created without parameters returns a NULL pointer
+ that should be converted to a Python None.'''
+ voidholder = VoidHolder()
+ self.assertEqual(voidholder.voidPointer(), None)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/weakref_test.py b/sources/shiboken6/tests/samplebinding/weakref_test.py
new file mode 100644
index 000000000..01c6d58d5
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/weakref_test.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test weakref support'''
+
+import gc
+import os
+import sys
+import unittest
+import weakref
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import ObjectType, PrivateDtor
+
+
+class WeakrefBasicTest(unittest.TestCase):
+ '''Simple test case of using a weakref'''
+
+ def setUp(self):
+ self.called = False
+
+ def cb(self, *args):
+ self.called = True
+
+ def testBasic(self):
+ '''ObjectType weakref'''
+ obj = ObjectType()
+ ref = weakref.ref(obj, self.cb) # noqa: F841
+ del obj
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertTrue(self.called)
+
+ def testPrivateDtor(self):
+ '''PrivateDtor weakref'''
+ obj = PrivateDtor.instance()
+ ref = weakref.ref(obj, self.cb) # noqa: F841
+ del obj
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertTrue(self.called)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/writableclassdict_test.py b/sources/shiboken6/tests/samplebinding/writableclassdict_test.py
new file mode 100644
index 000000000..dfc962db9
--- /dev/null
+++ b/sources/shiboken6/tests/samplebinding/writableclassdict_test.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from sample import Point
+
+
+class ExtPoint(Point):
+ pass
+
+
+class TestWritableClassDict(unittest.TestCase):
+ def testSetattrOnClass(self):
+ setattr(Point, 'foo', 123)
+ self.assertEqual(Point.foo, 123)
+ pt = Point()
+ self.assertEqual(pt.foo, 123)
+
+ def testSetattrOnInheritingClass(self):
+ setattr(Point, 'bar', 321)
+ self.assertEqual(Point.bar, 321)
+ self.assertEqual(ExtPoint.bar, 321)
+ pt = ExtPoint()
+ self.assertEqual(pt.bar, 321)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/shiboken_paths.py b/sources/shiboken6/tests/shiboken_paths.py
new file mode 100644
index 000000000..3ec940f2e
--- /dev/null
+++ b/sources/shiboken6/tests/shiboken_paths.py
@@ -0,0 +1,109 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+import os
+import sys
+from pathlib import Path
+
+
+def get_dir_env_var(var_name):
+ """Return a directory set by an environment variable"""
+ result = os.environ.get(var_name)
+ if not result:
+ raise ValueError(f'{var_name} is not set!')
+ if not Path(result).is_dir():
+ raise ValueError(f'{result} is not a directory!')
+ return result
+
+
+def get_build_dir():
+ """
+ Return the env var `BUILD_DIR`.
+ If not set (interactive mode), take the last build history entry.
+ """
+ try:
+ return get_dir_env_var('BUILD_DIR')
+ except ValueError:
+ look_for = Path("testing")
+ here = Path(__file__).resolve().parent
+ while here / look_for not in here.iterdir():
+ import pprint
+ parent = here.parent
+ if parent == here:
+ raise SystemError(look_for + " not found!")
+ here = parent
+ try:
+ sys.path.insert(0, os.fspath(here))
+ from testing.buildlog import builds
+ if not builds.history:
+ raise
+ return builds.history[-1].build_dir
+ finally:
+ del sys.path[0]
+
+
+def _prepend_path_var(var_name, paths):
+ """Prepend additional paths to a path environment variable
+ like PATH, LD_LIBRARY_PATH"""
+ old_paths = os.environ.get(var_name)
+ new_paths = os.pathsep.join(paths)
+ if old_paths:
+ new_paths += f'{os.pathsep}{old_paths}'
+ os.environ[var_name] = new_paths
+
+
+def add_python_dirs(python_dirs):
+ """Add directories to the Python path unless present.
+ Care is taken that the added directories come before
+ site-packages."""
+ new_paths = []
+ for python_dir in python_dirs:
+ new_paths.append(python_dir)
+ if python_dir in sys.path:
+ sys.path.remove(python_dir)
+ sys.path[:0] = new_paths
+
+
+def add_lib_dirs(lib_dirs):
+ """Add directories to the platform's library path."""
+ if sys.platform == 'win32':
+ if sys.version_info >= (3, 8, 0):
+ for lib_dir in lib_dirs:
+ os.add_dll_directory(lib_dir)
+ else:
+ _prepend_path_var('PATH', lib_dirs)
+ else:
+ _prepend_path_var('LD_LIBRARY_PATH', lib_dirs)
+
+
+def shiboken_paths(include_shiboken_tests=False):
+ """Return a tuple of python directories/lib directories to be set for
+ using the shiboken6 module from the build directory or running the
+ shiboken tests depending on a single environment variable BUILD_DIR
+ pointing to the build directory."""
+ src_dir = Path(__file__).resolve().parent
+ python_dirs = []
+ if include_shiboken_tests:
+ python_dirs.append(os.fspath(src_dir)) # For shiboken_test_helper
+ python_dirs.append(get_build_dir()) # for toplevel shiboken6 import
+ shiboken_dir = Path(get_build_dir()) / 'shiboken6'
+ lib_dirs = [os.fspath(shiboken_dir / 'libshiboken')]
+ if include_shiboken_tests:
+ shiboken_test_dir = shiboken_dir /'tests'
+ for module in ['minimal', 'sample', 'smart', 'other']:
+ module_dir = shiboken_test_dir / f"{module}binding"
+ python_dirs.append(os.fspath(module_dir))
+ lib_dir = shiboken_test_dir / f"lib{module}"
+ lib_dirs.append(os.fspath(lib_dir))
+ return (python_dirs, lib_dirs)
+
+
+def init_paths():
+ """Sets the correct import paths (Python modules and C++ library
+ paths) for testing shiboken depending on a single
+ environment variable BUILD_DIR pointing to the build
+ directory."""
+ paths = shiboken_paths(True)
+ add_python_dirs(paths[0])
+ add_lib_dirs(paths[1])
diff --git a/sources/shiboken6/tests/shiboken_test_helper.py b/sources/shiboken6/tests/shiboken_test_helper.py
new file mode 100644
index 000000000..14fe6a2d1
--- /dev/null
+++ b/sources/shiboken6/tests/shiboken_test_helper.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+def objectFullname(t):
+ # '__qualname__' for Python 2 does exist for PySide types, only.
+ name = getattr(t, "__qualname__", t.__name__)
+ module = t.__module__
+ if module is None or module == str.__class__.__module__:
+ return name
+ else:
+ return module + '.' + name
diff --git a/sources/shiboken6/tests/shibokenmodule/module_test.py b/sources/shiboken6/tests/shibokenmodule/module_test.py
new file mode 100644
index 000000000..9f9f8f5a4
--- /dev/null
+++ b/sources/shiboken6/tests/shibokenmodule/module_test.py
@@ -0,0 +1,112 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths # noqa: E402
+init_paths()
+
+from shiboken6 import Shiboken # noqa: E402
+from sample import BlackBox, ObjectType, ObjectModel, ObjectView, Point # noqa: E402
+
+
+class MultipleInherited (ObjectType, Point):
+ def __init__(self):
+ ObjectType.__init__(self)
+ Point.__init__(self)
+
+
+class TestShiboken(unittest.TestCase):
+ def testIsValid(self):
+ self.assertTrue(Shiboken.isValid(object()))
+ self.assertTrue(Shiboken.isValid(None))
+
+ bb = BlackBox()
+ item = ObjectType()
+ ticket = bb.keepObjectType(item)
+ bb.disposeObjectType(ticket)
+ self.assertFalse(Shiboken.isValid(item))
+
+ def testWrapInstance(self):
+ addr = ObjectType.createObjectType()
+ obj = Shiboken.wrapInstance(addr, ObjectType)
+ self.assertFalse(Shiboken.createdByPython(obj))
+ obj.setObjectName("obj")
+ self.assertEqual(obj.objectName(), "obj")
+ self.assertEqual(addr, obj.identifier())
+ self.assertFalse(Shiboken.createdByPython(obj))
+
+ # avoid mem leak =]
+ bb = BlackBox()
+ self.assertTrue(Shiboken.createdByPython(bb))
+ bb.disposeObjectType(bb.keepObjectType(obj))
+
+ def testWrapInstancePreserveId(self):
+ """PYSIDE-31: Verify that wrapInstance() returns the existing wrapper
+ even if a base class type is specified."""
+ v = ObjectView() # inherits ObjectType
+ addresses = Shiboken.getCppPointer(v)
+ self.assertTrue(addresses)
+ address = addresses[0]
+ wrapped = Shiboken.wrapInstance(address, ObjectType)
+ self.assertEqual(id(wrapped), id(v))
+
+ def testIsOwnedByPython(self):
+ obj = ObjectType()
+ self.assertTrue(Shiboken.ownedByPython(obj))
+ p = ObjectType()
+ obj.setParent(p)
+ self.assertFalse(Shiboken.ownedByPython(obj))
+
+ def testDump(self):
+ """Just check if dump doesn't crash on certain use cases"""
+ p = ObjectType()
+ obj = ObjectType(p)
+ obj2 = ObjectType(obj)
+ obj3 = ObjectType(obj) # noqa: F841
+ self.assertEqual(Shiboken.dump(None), "Ordinary Python type.")
+ Shiboken.dump(obj)
+
+ model = ObjectModel(p)
+ v = ObjectView(model, p)
+ Shiboken.dump(v)
+
+ m = MultipleInherited()
+ Shiboken.dump(m)
+ self.assertEqual(len(Shiboken.getCppPointer(m)), 2)
+
+ # Don't crash even after deleting an object
+ Shiboken.invalidate(obj)
+ Shiboken.dump(obj) # deleted
+ Shiboken.dump(p) # child deleted
+ Shiboken.dump(obj2) # parent deleted
+
+ def testDelete(self):
+ obj = ObjectType()
+ child = ObjectType(obj)
+ self.assertTrue(Shiboken.isValid(obj))
+ self.assertTrue(Shiboken.isValid(child))
+ # Note: this test doesn't assure that the object dtor was really called
+ Shiboken.delete(obj)
+ self.assertFalse(Shiboken.isValid(obj))
+ self.assertFalse(Shiboken.isValid(child))
+
+ def testVersionAttr(self):
+ self.assertEqual(type(Shiboken.__version__), str)
+ self.assertTrue(len(Shiboken.__version__) >= 5)
+ self.assertEqual(type(Shiboken.__version_info__), tuple)
+ self.assertEqual(len(Shiboken.__version_info__), 5)
+
+ def testAllWrappers(self):
+ obj = ObjectType()
+ self.assertTrue(obj in Shiboken.getAllValidWrappers())
+ Shiboken.delete(obj)
+ self.assertFalse(obj in Shiboken.getAllValidWrappers())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/smartbinding/CMakeLists.txt b/sources/shiboken6/tests/smartbinding/CMakeLists.txt
new file mode 100644
index 000000000..594744840
--- /dev/null
+++ b/sources/shiboken6/tests/smartbinding/CMakeLists.txt
@@ -0,0 +1,65 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(smart)
+
+set(smart_TYPESYSTEM
+${CMAKE_CURRENT_SOURCE_DIR}/typesystem_smart.xml
+)
+
+set(smart_SRC
+${CMAKE_CURRENT_BINARY_DIR}/smart/smart_module_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/obj_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/integer_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/sharedptr_obj_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/sharedptr_integer_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/registry_wrapper.cpp
+${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
+${CMAKE_CURRENT_BINARY_DIR}/smart/std_unique_ptr_integer_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/std_unique_ptr_integer2_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/std_unique_ptr_int_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/stdoptionaltestbench_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/stduniqueptrtestbench_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/stduniqueptrvirtualmethodtester_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/test_wrapper.cpp
+)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/smart-binding.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt" @ONLY)
+
+shiboken_get_tool_shell_wrapper(shiboken tool_wrapper)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+ BYPRODUCTS ${smart_SRC}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Shiboken6::shiboken6>
+ --project-file=${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt
+ ${GENERATOR_EXTRA_FLAGS}
+ DEPENDS ${smart_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h Shiboken6::shiboken6
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Running generator for 'smart' test binding..."
+)
+
+add_library(smart MODULE ${smart_SRC})
+target_include_directories(smart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(smart PUBLIC libsmart libshiboken)
+set_property(TARGET smart PROPERTY PREFIX "")
+set_property(TARGET smart PROPERTY OUTPUT_NAME "smart${PYTHON_EXTENSION_SUFFIX}")
+
+if(WIN32)
+ set_property(TARGET smart PROPERTY SUFFIX ".pyd")
+endif()
+
+create_generator_target(smart)
diff --git a/sources/shiboken6/tests/smartbinding/global.h b/sources/shiboken6/tests/smartbinding/global.h
new file mode 100644
index 000000000..5bec15063
--- /dev/null
+++ b/sources/shiboken6/tests/smartbinding/global.h
@@ -0,0 +1,4 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "smart.h"
diff --git a/sources/shiboken6/tests/smartbinding/smart-binding.txt.in b/sources/shiboken6/tests/smartbinding/smart-binding.txt.in
new file mode 100644
index 000000000..a2c73c6bf
--- /dev/null
+++ b/sources/shiboken6/tests/smartbinding/smart-binding.txt.in
@@ -0,0 +1,16 @@
+[generator-project]
+
+generator-set = shiboken
+
+header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h
+typesystem-file = @smart_TYPESYSTEM@
+
+output-directory = @CMAKE_CURRENT_BINARY_DIR@
+
+include-path = @libsmart_SOURCE_DIR@
+
+typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@
+
+enable-parent-ctor-heuristic
+use-isnull-as-nb_nonzero
+lean-headers
diff --git a/sources/shiboken6/tests/smartbinding/smart_pointer_test.py b/sources/shiboken6/tests/smartbinding/smart_pointer_test.py
new file mode 100644
index 000000000..8d4272558
--- /dev/null
+++ b/sources/shiboken6/tests/smartbinding/smart_pointer_test.py
@@ -0,0 +1,302 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import gc
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+from copy import copy
+from smart import (Obj, Registry, Integer, SharedPtr_Integer, std)
+
+
+def objCount():
+ return Registry.getInstance().countObjects()
+
+
+def integerCount():
+ return Registry.getInstance().countIntegers()
+
+
+def integerFromValue(v):
+ result = Integer()
+ result.setValue(v)
+ return result
+
+
+class SmartPointerTests(unittest.TestCase):
+
+ def setUp(self):
+ super().setUp()
+ if os.environ.get("VERBOSE"):
+ Registry.getInstance().setVerbose(True)
+
+ def testObjSmartPointer(self):
+ # Create Obj.
+ o = Obj()
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 1)
+
+ # Create a shared pointer to an Obj together with an Obj.
+ ptrToObj = o.createSharedPtrObj()
+ self.assertEqual(objCount(), 2)
+
+ # Delete the old Obj.
+ o = None
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 1)
+
+ # Get a wrapper to the Obj inside of the shared pointer, object count
+ # should not change.
+ obj = ptrToObj.data()
+ self.assertEqual(objCount(), 1)
+ obj.m_integer = 50
+ self.assertEqual(obj.m_integer, 50)
+
+ # Set and get a member value via shared pointer (like operator->).
+ ptrToObj.m_integer = 100
+ self.assertEqual(ptrToObj.m_integer, 100)
+
+ # Get inner PyObject via shared pointer (like operator->) and set
+ # value in it.
+ ptrToObj.m_internalInteger.m_int = 200
+ self.assertEqual(ptrToObj.m_internalInteger.m_int, 200)
+
+ # Pass smart pointer as argument to a method, return value is the value
+ # of m_integer of passed Obj inside the smart pointer.
+ result = ptrToObj.takeSharedPtrToObj(ptrToObj)
+ self.assertEqual(result, 100)
+
+ # Pass an Integer as an argument that returns itself.
+ result = ptrToObj.takeInteger(ptrToObj.m_internalInteger)
+ self.assertEqual(integerCount(), 2)
+ result = None
+ if integerCount() > 1:
+ gc.collect()
+ print('Running garbage collector for reference test',
+ file=sys.stderr)
+ self.assertEqual(integerCount(), 1)
+
+ # Make a copy of the shared pointer, object count should not change.
+ ptrToObj2 = copy(ptrToObj)
+ self.assertEqual(objCount(), 1)
+
+ # Delete the first shared pointer, object count should not change
+ # because the second one still has a reference.
+ del ptrToObj
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 1)
+
+ # Delete the second smart pointer, object should be deleted.
+ del ptrToObj2
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 0)
+ self.assertEqual(integerCount(), 0)
+
+ def testIntegerSmartPointer(self):
+ # Create Obj.
+ o = Obj()
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 1)
+
+ # Create a shared pointer to an Integer together with an Integer.
+ ptrToInteger = o.createSharedPtrInteger()
+ self.assertEqual(objCount(), 1)
+ self.assertEqual(integerCount(), 2)
+
+ # Get a wrapper to the Integer inside of the shared pointer, integer
+ # count should not change.
+ integer = ptrToInteger.data()
+ self.assertEqual(integerCount(), 2)
+ integer.m_int = 50
+ self.assertEqual(integer.m_int, 50)
+
+ # Set and get a member value via shared pointer (like operator->).
+ ptrToInteger.setValue(150)
+ self.assertEqual(ptrToInteger.value(), 150)
+
+ # Set and get a member field via shared pointer (like operator->).
+ ptrToInteger.m_int = 100
+ self.assertEqual(ptrToInteger.m_int, 100)
+
+ # Pass smart pointer as argument to a method, return value is the
+ # value of m_int of passed Integer inside the smart pointer.
+ result = o.takeSharedPtrToInteger(ptrToInteger)
+ self.assertEqual(result, 100)
+
+ # Make a copy of the shared pointer, integer count should not change.
+ ptrToInteger2 = copy(ptrToInteger)
+ self.assertEqual(integerCount(), 2)
+
+ # Delete the first shared pointer, integer count should not change
+ # because the second one still has a reference.
+ del ptrToInteger
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(integerCount(), 2)
+
+ # Delete the second smart pointer, integer should be deleted.
+ del ptrToInteger2
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 1)
+ self.assertEqual(integerCount(), 1)
+
+ # Delete the original object which was used to create the integer.
+ del o
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 0)
+ self.assertEqual(integerCount(), 0)
+
+ def testConstIntegerSmartPointer(self):
+ # Create Obj.
+ o = Obj()
+ ptrToConstInteger = o.createSharedPtrConstInteger()
+ self.assertEqual(ptrToConstInteger.m_int, 456)
+ result = o.takeSharedPtrToConstInteger(ptrToConstInteger)
+ self.assertEqual(result, 456)
+ self.assertEqual(ptrToConstInteger.value(), 456)
+
+ def testSmartPointersWithNamespace(self):
+ # Create the main object
+ o = Obj()
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 1)
+
+ # Create a shared pointer to an Integer together with an Integer.
+ ptrToInteger = o.createSharedPtrInteger2()
+ self.assertEqual(objCount(), 1)
+ self.assertEqual(integerCount(), 2)
+
+ integer = ptrToInteger.data()
+ self.assertTrue(integer)
+
+ def testListOfSmartPointers(self):
+ # Create the main object
+ o = Obj()
+
+ # Create a list of shared objects
+ ptrToObjList = o.createSharedPtrObjList(10)
+ self.assertEqual(len(ptrToObjList), 10)
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 11)
+
+ # Remove one from the list
+ ptrToObjList.pop()
+ self.assertEqual(len(ptrToObjList), 9)
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ # PYSIDE-535: Why do I need to do it twice, here?
+ gc.collect()
+ self.assertEqual(objCount(), 10)
+
+ # clear and delete all objects in the list
+ del ptrToObjList[:] # Python 2.7 lists have no clear method
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(len(ptrToObjList), 0)
+ self.assertEqual(objCount(), 1)
+
+ def testInvalidParameter(self):
+ # Create Obj.
+ o = Obj()
+ # Create a shared pointer to an Obj together with an Obj.
+ ptrToObj = o.createSharedPtrObj()
+ try:
+ ptrToObj.typo
+ self.assertFail()
+ except AttributeError as error:
+ self.assertEqual(error.args[0], "'smart.SharedPtr_Obj' object has no attribute 'typo'")
+
+ def testSmartPointerConversions(self):
+ # Create Obj.
+ o = Obj()
+ # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+ gc.collect()
+ self.assertEqual(objCount(), 1)
+ self.assertEqual(integerCount(), 1)
+
+ # Create a shared pointer to an Integer2
+ integer2 = o.createSharedPtrInteger2()
+ # User defined name
+ self.assertEqual(type(integer2).__name__, "SmartInteger2Ptr")
+ self.assertTrue("smart.Test.SmartInteger2Ptr" in repr(type(integer2)))
+ self.assertEqual(integer2.value(), 456)
+
+ # pass Smart<Integer2> to a function that accepts Smart<Integer>
+ r = o.takeSharedPtrToInteger(integer2)
+ self.assertEqual(r, integer2.value())
+
+ def testSmartPointerValueComparison(self):
+ """Test a pointee class with comparison operators."""
+ four = Obj.createSharedPtrInteger(4)
+ four2 = Obj.createSharedPtrInteger(4)
+ five = Obj.createSharedPtrInteger(5)
+ self.assertTrue(four == four)
+ self.assertTrue(four == four2)
+ self.assertFalse(four != four)
+ self.assertFalse(four != four2)
+ self.assertFalse(four < four)
+ self.assertTrue(four <= four)
+ self.assertFalse(four > four)
+ self.assertTrue(four >= four)
+ self.assertFalse(four == five)
+ self.assertTrue(four != five)
+ self.assertTrue(four < five)
+ self.assertTrue(four <= five)
+ self.assertFalse(four > five)
+ self.assertFalse(four >= five)
+ self.assertTrue(five > four)
+
+ self.assertRaises(NotImplementedError,
+ lambda: Obj.createNullSharedPtrInteger() == four)
+
+ def testSmartPointerObjectComparison(self):
+ """Test a pointee class without comparison operators."""
+ o1 = Obj.createSharedPtrObj()
+ o2 = Obj.createSharedPtrObj()
+ self.assertTrue(o1 == o1)
+ self.assertFalse(o1 != o1)
+ self.assertFalse(o1 == o2)
+ self.assertTrue(o1 != o2)
+
+ def testOperatorNbBool(self):
+ null_ptr = Obj.createNullSharedPtrInteger()
+ self.assertFalse(null_ptr)
+ zero = Obj.createSharedPtrInteger(0)
+ self.assertTrue(zero)
+
+ def testParameterNone(self):
+ o = Obj()
+ null_ptr = Obj.createNullSharedPtrInteger()
+ o.takeSharedPtrToInteger(null_ptr)
+ o.takeSharedPtrToIntegerByConstRef(null_ptr)
+ o.takeSharedPtrToInteger(None)
+ o.takeSharedPtrToIntegerByConstRef(None)
+
+ def testConstruction(self):
+ p1 = SharedPtr_Integer(integerFromValue(42))
+ self.assertEqual(p1.value(), 42)
+
+ p2 = std.shared_ptr_Integer(integerFromValue(42))
+ self.assertEqual(p2.value(), 42)
+ p2.reset(integerFromValue(43))
+ self.assertEqual(p2.value(), 43)
+ gc.collect()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/smartbinding/smartbinding.pyproject b/sources/shiboken6/tests/smartbinding/smartbinding.pyproject
new file mode 100644
index 000000000..d0855ef82
--- /dev/null
+++ b/sources/shiboken6/tests/smartbinding/smartbinding.pyproject
@@ -0,0 +1,7 @@
+{
+ "files": ["smart_pointer_test.py",
+ "std_optional_test.py",
+ "std_shared_ptr_test.py",
+ "std_unique_ptr_test.py",
+ "typesystem_smart.xml"]
+}
diff --git a/sources/shiboken6/tests/smartbinding/std_optional_test.py b/sources/shiboken6/tests/smartbinding/std_optional_test.py
new file mode 100644
index 000000000..bee573548
--- /dev/null
+++ b/sources/shiboken6/tests/smartbinding/std_optional_test.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+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, StdOptionalTestBench, std
+
+
+def call_func_on_optional(o):
+ o.printInteger()
+
+
+def integer_from_value(v):
+ result = Integer()
+ result.setValue(v)
+ return result
+
+
+class StdOptionalTests(unittest.TestCase):
+
+ def testCInt(self):
+ b = StdOptionalTestBench()
+ ci = b.optionalInt()
+ self.assertFalse(ci.has_value())
+ b.setOptionalIntValue(42)
+ ci = b.optionalInt()
+ self.assertTrue(ci.has_value())
+ self.assertEqual(ci.value(), 42)
+ b.setOptionalInt(ci)
+ ci = b.optionalInt()
+ self.assertTrue(ci.has_value())
+ self.assertEqual(ci.value(), 42)
+
+ ci = std.optional_int(43)
+ self.assertEqual(ci.value(), 43)
+
+ def testInteger(self):
+ b = StdOptionalTestBench()
+ i = b.optionalInteger()
+ self.assertFalse(i.has_value())
+ self.assertFalse(i)
+ # Must not throw a C++ exception
+ self.assertRaises(AttributeError, call_func_on_optional, i)
+
+ b.setOptionalIntegerValue(integer_from_value(42))
+ i = b.optionalInteger()
+ self.assertTrue(i.has_value())
+ self.assertEqual(i.value().value(), 42)
+ i.printInteger()
+ print(i)
+ b.setOptionalInteger(i)
+ i = b.optionalInteger()
+ self.assertTrue(i.has_value())
+ self.assertEqual(i.value().value(), 42)
+ call_func_on_optional(i)
+
+ i = std.optional_Integer(integer_from_value(43))
+ self.assertEqual(i.value().value(), 43)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py b/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py
new file mode 100644
index 000000000..a37a307a5
--- /dev/null
+++ b/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+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, StdDoublePtr, StdSharedPtrTestBench, StdSharedPtrVirtualMethodTester, std
+
+
+def call_func_on_ptr(ptr):
+ ptr.printInteger()
+
+
+class VirtualTester(StdSharedPtrVirtualMethodTester):
+
+ def doModifyInteger(self, p):
+ p.setValue(p.value() * 2)
+ return p
+
+
+class StdSharedPtrTests(unittest.TestCase):
+ def testInteger(self):
+ p = StdSharedPtrTestBench.createInteger()
+ # PYSIDE-2462: Ensure Integer's __dir__ entries in the pointer's
+ self.assertTrue("printInteger" in dir(p))
+ StdSharedPtrTestBench.printInteger(p)
+ self.assertTrue(p)
+ call_func_on_ptr(p)
+
+ np = StdSharedPtrTestBench.createNullInteger()
+ StdSharedPtrTestBench.printInteger(np)
+ self.assertFalse(np)
+ self.assertRaises(AttributeError, call_func_on_ptr, np)
+
+ iv = Integer()
+ iv.setValue(42)
+ np = std.shared_ptr_Integer(iv)
+ self.assertEqual(np.value(), 42)
+
+ def testInt(self):
+ np = StdSharedPtrTestBench.createNullInt()
+ StdSharedPtrTestBench.printInt(np)
+ 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
+ correctly."""
+ p = StdSharedPtrTestBench.createInteger()
+ p.setValue(42)
+ v = StdSharedPtrVirtualMethodTester()
+ r = v.callModifyInteger(p) # Base implementation increments
+ self.assertEqual(r.value(), 43)
+
+ p.setValue(42)
+ v = VirtualTester()
+ r = v.callModifyInteger(p) # Derived implementation doubles
+ self.assertEqual(r.value(), 84)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/smartbinding/std_unique_ptr_test.py b/sources/shiboken6/tests/smartbinding/std_unique_ptr_test.py
new file mode 100644
index 000000000..9c7ef2f01
--- /dev/null
+++ b/sources/shiboken6/tests/smartbinding/std_unique_ptr_test.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+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, Integer2, StdUniquePtrTestBench, StdUniquePtrVirtualMethodTester, std
+
+
+def call_func_on_ptr(ptr):
+ ptr.printInteger()
+
+
+class VirtualTester(StdUniquePtrVirtualMethodTester):
+
+ def doCreateInteger(self, v):
+ iv = Integer() # Construct from pointee
+ iv.setValue(2 * v)
+ return std.unique_ptr_Integer(iv)
+
+ def doModifyIntegerByRef(self, p):
+ return 2 * p.value()
+
+ def doModifyIntegerByValue(self, p):
+ return 2 * p.value()
+
+
+class StdUniquePtrTests(unittest.TestCase):
+ def testInteger(self):
+ p = StdUniquePtrTestBench.createInteger()
+ StdUniquePtrTestBench.printInteger(p) # unique_ptr by ref
+ self.assertTrue(p)
+
+ call_func_on_ptr(p)
+ self.assertTrue(p)
+
+ StdUniquePtrTestBench.takeInteger(p) # unique_ptr by value, takes pointee
+ self.assertFalse(p)
+
+ np = StdUniquePtrTestBench.createNullInteger()
+ StdUniquePtrTestBench.printInteger(np)
+ self.assertFalse(np)
+ self.assertRaises(AttributeError, call_func_on_ptr, np)
+
+ iv = Integer() # Construct from pointee
+ iv.setValue(42)
+ np = std.unique_ptr_Integer(iv)
+ self.assertEqual(np.value(), 42)
+
+ def test_derived(self):
+ iv2 = Integer2() # Construct from pointee
+ iv2.setValue(42)
+ p = std.unique_ptr_Smart_Integer2(iv2)
+ self.assertEqual(p.value(), 42)
+ StdUniquePtrTestBench.printInteger2(p) # unique_ptr by ref
+ self.assertTrue(p)
+ StdUniquePtrTestBench.printInteger(p) # conversion
+ # FIXME: This fails, pointer is moved in value conversion
+ # self.assertTrue(p)
+
+ def testInt(self):
+ p = StdUniquePtrTestBench.createInt() # unique_ptr by ref
+ StdUniquePtrTestBench.printInt(p)
+ StdUniquePtrTestBench.takeInt(p) # unique_ptr by value, takes pointee
+ self.assertFalse(p)
+
+ np = StdUniquePtrTestBench.createNullInt()
+ StdUniquePtrTestBench.printInt(np)
+ self.assertFalse(np)
+
+ def testVirtuals(self):
+ """Test whether code generating virtual function overrides is generated
+ correctly."""
+ p = StdUniquePtrTestBench.createInteger()
+ p.setValue(42)
+ v = StdUniquePtrVirtualMethodTester()
+ self.assertTrue(v.testCreateInteger(42, 42))
+ self.assertTrue(v.testModifyIntegerByRef(42, 43)) # Default implementation increments
+ self.assertTrue(v.testModifyIntegerValue(42, 43))
+
+ v = VirtualTester() # Reimplemented methods double values
+ self.assertTrue(v.testCreateInteger(42, 84))
+ self.assertTrue(v.testModifyIntegerByRef(42, 84))
+ self.assertTrue(v.testModifyIntegerValue(42, 84))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken6/tests/smartbinding/typesystem_smart.xml b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml
new file mode 100644
index 000000000..e479e4ddf
--- /dev/null
+++ b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<typesystem package="smart">
+ <rejection class="*" argument-type="^std::nullptr_t&amp;?$"/>
+
+ <template name="cpplist_to_pylist_convertion">
+ PyObject *%out = PyList_New(int(%in.size()));
+ int idx = 0;
+ for (const auto &amp;cppItem : %in)
+ PyList_SET_ITEM(%out, idx++, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
+ return %out;
+ </template>
+ <template name="pyseq_to_cpplist_convertion">
+ Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0));
+ for (int i = 0, size = PySequence_Fast_GET_SIZE(seq.object()); i &lt; size; ++i) {
+ PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), i);
+ %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
+ %out.push_back(cppItem);
+ }
+ </template>
+
+ <!-- Used in tests to check what C++ objects are allocated. -->
+ <object-type name="Registry" />
+
+ <!-- Current limitation: shared pointer python objects can only be instantiated from API usage,
+ like when they are returned as a result of a method, or passed as arguments. It is not
+ possible to explicitly instantiate a new shared pointer in python e.g. o = SharedPtr_Foo()
+ won't work.
+ -->
+ <smart-pointer-type name="SharedPtr" type="shared" getter="data" ref-count-method="useCount"
+ null-check-method="isNull"
+ instantiations="Integer,Smart::Integer2=Test::SmartInteger2Ptr,Obj"/>
+
+ <object-type name="Obj" />
+ <value-type name="Integer" />
+ <namespace-type name="Smart" generate="no">
+ <value-type name="Integer2" />
+ </namespace-type>
+ <!-- Just used to silence the warnings that shiboken doens't know what to do with this type -->
+ <custom-type name="RefData" />
+
+ <value-type name="StdOptionalTestBench"/>
+
+ <system-include file-name="memory"/>
+
+ <namespace-type name="std">
+ <include file-name="memory" location="global"/>
+ <modify-function signature="^.*$" remove="all"/>
+ <enum-type name="pointer_safety"/>
+ <smart-pointer-type name="shared_ptr" type="shared" getter="get"
+ value-check-method="operator bool"
+ ref-count-method="use_count"
+ reset-method="reset"
+ instantiations="Integer,int=StdIntPtr,double=::StdDoublePtr,std::string">
+ <include file-name="memory" location="global"/>
+ </smart-pointer-type>
+
+ <smart-pointer-type name="unique_ptr" type="unique" getter="get"
+ value-check-method="operator bool"
+ reset-method="reset"
+ instantiations="Integer,Smart::Integer2,int">
+ <include file-name="memory" location="global"/>
+ </smart-pointer-type>
+
+ <smart-pointer-type name="optional" type="value-handle" getter="value"
+ value-check-method="has_value"
+ instantiations="Integer,int">
+ <include file-name="optional" location="global"/>
+ </smart-pointer-type>
+
+ </namespace-type>
+ <object-type name="StdSharedPtrTestBench"/>
+ <object-type name="StdSharedPtrVirtualMethodTester"/>
+
+ <object-type name="StdUniquePtrTestBench"/>
+ <object-type name="StdUniquePtrVirtualMethodTester"/>
+
+ <namespace-type name="Test">
+ <enum-type name="DummyEnum"/>
+ </namespace-type>
+
+</typesystem>
diff --git a/sources/shiboken6/tests/test_generator/CMakeLists.txt b/sources/shiboken6/tests/test_generator/CMakeLists.txt
new file mode 100644
index 000000000..e1d078894
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/CMakeLists.txt
@@ -0,0 +1,65 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.18)
+project(test_generator)
+
+set(dummy_generator_SRC dummygenerator.cpp)
+add_library(dummy_generator SHARED ${dummy_generator_SRC})
+target_link_libraries(dummy_generator ${APIEXTRACTOR_LIBRARY} ${QT_QTCORE_LIBRARY} genrunner)
+set_property(TARGET dummy_generator PROPERTY PREFIX "")
+
+add_executable(dummygenerator main.cpp)
+set(DUMMYGENERATOR_EXECUTABLE dummygenerator${generator_SUFFIX})
+set_target_properties(dummygenerator PROPERTIES OUTPUT_NAME ${DUMMYGENERATOR_EXECUTABLE})
+target_link_libraries(dummygenerator ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES})
+
+configure_file(dummygentestconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/dummygentestconfig.h" @ONLY)
+
+get_filename_component(APIEXTRACTOR_LIBRARY_DIRS ${APIEXTRACTOR_LIBRARY} PATH)
+if(WIN32)
+ set(PATH_SEP ";")
+ find_program(APIEXTRACTOR_BINARY apiextractor.dll HINTS ${APIEXTRACTOR_LIBRARY_DIRS})
+ get_filename_component(APIEXTRACTOR_BINARY_DIR ${APIEXTRACTOR_BINARY} PATH)
+ set(APIEXTRACTOR_LIBRARY_DIRS "${APIEXTRACTOR_LIBRARY_DIRS}${PATH_SEP}${APIEXTRACTOR_BINARY_DIR}")
+else()
+ set(PATH_SEP ":")
+endif()
+
+set(ENV_PATH "${generatorrunner_BINARY_DIR}${PATH_SEP}${CMAKE_CURRENT_BINARY_DIR}${PATH_SEP}$ENV{PATH}${PATH_SEP}${APIEXTRACTOR_LIBRARY_DIRS}")
+set(ENV_QT_PLUGIN_PATH "${CMAKE_CURRENT_BINARY_DIR}${PATH_SEP}$ENV{QT_PLUGIN_PATH}")
+if(WIN32)
+ string(REPLACE "\\;" ";" ENV_PATH "${ENV_PATH}")
+ string(REPLACE ";" "\\;" ENV_PATH "${ENV_PATH}")
+ string(REPLACE "\\;" ";" ENV_QT_PLUGIN_PATH "${ENV_QT_PLUGIN_PATH}")
+ string(REPLACE ";" "\\;" ENV_QT_PLUGIN_PATH "${ENV_QT_PLUGIN_PATH}")
+endif()
+
+macro(m_add_test testname)
+ add_test(${testname} ${testname})
+ set_property(TEST ${testname} PROPERTY ENVIRONMENT "PATH=${ENV_PATH}" "QT_PLUGIN_PATH=${ENV_QT_PLUGIN_PATH}")
+endmacro()
+
+macro(declare_test testname)
+ qt4_automoc("${testname}.cpp")
+ add_executable(${testname} "${testname}.cpp")
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+ target_link_libraries(${testname}
+ ${QT_QTTEST_LIBRARY}
+ ${QT_QTCORE_LIBRARY}
+ ${Qt${QT_MAJOR_VERSION}Test_LIBRARIES}
+ ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
+ )
+ m_add_test(${testname})
+endmacro(declare_test testname)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_global.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/test_global.h" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_typesystem.xml"
+ "${CMAKE_CURRENT_BINARY_DIR}/test_typesystem.xml" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/dummygentest-project.txt.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/dummygentest-project.txt" @ONLY)
+declare_test(dummygentest)
+
+add_dependencies(dummygenerator generatorrunner)
+
diff --git a/sources/shiboken6/tests/test_generator/dummygenerator.cpp b/sources/shiboken6/tests/test_generator/dummygenerator.cpp
new file mode 100644
index 000000000..8a5079820
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/dummygenerator.cpp
@@ -0,0 +1,45 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <iostream>
+#include "dummygenerator.h"
+
+EXPORT_GENERATOR_PLUGIN(new DummyGenerator)
+
+using namespace std;
+
+QString
+DummyGenerator::fileNameForClass(const AbstractMetaClass* metaClass) const
+{
+ return metaClass->name().toLower() + u"_generated.txt"_qs;
+}
+
+void
+DummyGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ s << "// Generated code for class: " << qPrintable(metaClass->name()) << endl;
+}
+
+bool
+DummyGenerator::doSetup(const QMap<QString, QString>& args)
+{
+ if (args.contains("dump-arguments") && !args["dump-arguments"].isEmpty()) {
+ QFile logFile(args["dump-arguments"]);
+ logFile.open(QIODevice::WriteOnly | QIODevice::Text);
+ QTextStream out(&logFile);
+ for (QMap<QString, QString>::const_iterator it = args.cbegin(), end = args.cend(); it != end; ++it) {
+ const QString& key = it.key();
+ if (key == "arg-1")
+ out << "header-file";
+ else if (key == "arg-2")
+ out << "typesystem-file";
+ else
+ out << key;
+ if (!args[key].isEmpty())
+ out << " = " << args[key];
+ out << endl;
+ }
+ }
+ return true;
+}
+
diff --git a/sources/shiboken6/tests/test_generator/dummygenerator.h b/sources/shiboken6/tests/test_generator/dummygenerator.h
new file mode 100644
index 000000000..d17206809
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/dummygenerator.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#ifndef DUMMYGENERATOR_H
+#define DUMMYGENERATOR_H
+
+#include "generator.h"
+
+class GENRUNNER_API DummyGenerator : public Generator
+{
+public:
+ DummyGenerator() {}
+ ~DummyGenerator() {}
+ bool doSetup(const QMap<QString, QString>& args);
+ const char* name() const { return "DummyGenerator"; }
+
+protected:
+ void writeFunctionArguments(QTextStream&, const AbstractMetaFunction*, Options) const {}
+ void writeArgumentNames(QTextStream&, const AbstractMetaFunction*, Options) const {}
+ QString fileNameForClass(const AbstractMetaClass* metaClass) const;
+ void generateClass(QTextStream& s, const AbstractMetaClass* metaClass);
+ void finishGeneration() {}
+};
+
+#endif // DUMMYGENERATOR_H
diff --git a/sources/shiboken6/tests/test_generator/dummygentest-project.txt.in b/sources/shiboken6/tests/test_generator/dummygentest-project.txt.in
new file mode 100644
index 000000000..0a076d8bd
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/dummygentest-project.txt.in
@@ -0,0 +1,20 @@
+[generator-project]
+
+generator-set = dummy
+header-file = @CMAKE_CURRENT_BINARY_DIR@/test_global.h
+typesystem-file = @CMAKE_CURRENT_BINARY_DIR@/test_typesystem.xml
+output-directory = /tmp/output
+
+dump-arguments = @CMAKE_CURRENT_BINARY_DIR@/dummygen-args.log
+
+include-path = /include/path/location1
+include-path = /include/path/location2
+
+typesystem-path = /typesystem/path/location1
+typesystem-path = /typesystem/path/location2
+
+api-version = 1.2.3
+debug = sparse
+
+no-suppress-warnings
+
diff --git a/sources/shiboken6/tests/test_generator/dummygentest.cpp b/sources/shiboken6/tests/test_generator/dummygentest.cpp
new file mode 100644
index 000000000..d439e3d8c
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/dummygentest.cpp
@@ -0,0 +1,114 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "dummygentest.h"
+#include "dummygenerator.h"
+#include "dummygentestconfig.h"
+
+#include <QtCore/QProcess>
+#include <QtCore/QTemporaryFile>
+#include <QtTest/QTest>
+
+#define GENERATED_CONTENTS "// Generated code for class: Dummy"
+
+void DummyGenTest::initTestCase()
+{
+ int argc = 0;
+ char* argv[] = {NULL};
+ QCoreApplication app(argc, argv);
+ workDir = QDir::currentPath();
+
+ headerFilePath = workDir + "/test_global.h";
+ typesystemFilePath = workDir + "/test_typesystem.xml";
+ projectFilePath = workDir + "/dummygentest-project.txt";
+ generatedFilePath = QDir::tempPath() + u"/dummy/dummy_generated.txt"_qs;
+}
+
+void DummyGenTest::testCallGenRunnerWithFullPathToDummyGenModule()
+{
+ QStringList args;
+ args.append("--generator-set=" DUMMYGENERATOR_BINARY_DIR "/dummy_generator" MODULE_EXTENSION);
+ args.append(u"--output-directory="_qs + QDir::tempPath());
+ args.append(headerFilePath);
+ args.append(typesystemFilePath);
+ int result = QProcess::execute("generatorrunner", args);
+ QCOMPARE(result, 0);
+
+ QFile generatedFile(generatedFilePath);
+ generatedFile.open(QIODevice::ReadOnly);
+ QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed());
+ generatedFile.close();
+
+ QVERIFY(generatedFile.remove());
+}
+
+void DummyGenTest::testCallGenRunnerWithNameOfDummyGenModule()
+{
+ QStringList args;
+ args.append("--generator-set=dummy");
+ args.append(u"--output-directory="_qs + QDir::tempPath());
+ args.append(headerFilePath);
+ args.append(typesystemFilePath);
+ int result = QProcess::execute("generatorrunner", args);
+ QCOMPARE(result, 0);
+
+ QFile generatedFile(generatedFilePath);
+ generatedFile.open(QIODevice::ReadOnly);
+ QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed());
+ generatedFile.close();
+
+ QVERIFY(generatedFile.remove());
+}
+
+void DummyGenTest::testCallDummyGeneratorExecutable()
+{
+ QStringList args;
+ args.append(u"--output-directory="_qs + QDir::tempPath());
+ args.append(headerFilePath);
+ args.append(typesystemFilePath);
+ int result = QProcess::execute(DUMMYGENERATOR_BINARY, args);
+ QCOMPARE(result, 0);
+
+ QFile generatedFile(generatedFilePath);
+ generatedFile.open(QIODevice::ReadOnly);
+ QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed());
+ generatedFile.close();
+
+ QVERIFY(generatedFile.remove());
+}
+
+void DummyGenTest::testProjectFileArgumentsReading()
+{
+ QStringList args(u"--project-file="_qs + workDir + u"/dummygentest-project.txt"_qs);
+ int result = QProcess::execute("generatorrunner", args);
+ QCOMPARE(result, 0);
+
+ QFile logFile(workDir + "/dummygen-args.log");
+ logFile.open(QIODevice::ReadOnly);
+ QStringList logContents;
+ while (!logFile.atEnd())
+ logContents << logFile.readLine().trimmed();
+ logContents.sort();
+ QCOMPARE(logContents[0], QString("api-version = 1.2.3"));
+ QCOMPARE(logContents[1], QString("debug = sparse"));
+ QVERIFY(logContents[2].startsWith("dump-arguments = "));
+ QVERIFY(logContents[2].endsWith("dummygen-args.log"));
+ QCOMPARE(logContents[3], QString("generator-set = dummy"));
+ QVERIFY(logContents[4].startsWith("header-file = "));
+ QVERIFY(logContents[4].endsWith("test_global.h"));
+ QCOMPARE(logContents[5],
+ QDir::toNativeSeparators(QString("include-paths = /include/path/location1%1/include/path/location2").arg(PATH_SPLITTER)));
+ QCOMPARE(logContents[6], QString("no-suppress-warnings"));
+ QCOMPARE(logContents[7], QString("output-directory = /tmp/output"));
+ QVERIFY(logContents[8].startsWith("project-file = "));
+ QVERIFY(logContents[8].endsWith("dummygentest-project.txt"));
+ QVERIFY(logContents[9].startsWith("typesystem-file = "));
+ QVERIFY(logContents[9].endsWith("test_typesystem.xml"));
+ QCOMPARE(logContents[10],
+ QDir::toNativeSeparators(QString("typesystem-paths = /typesystem/path/location1%1/typesystem/path/location2").arg(PATH_SPLITTER)));
+}
+
+QTEST_APPLESS_MAIN(DummyGenTest)
+
+#include "dummygentest.moc"
+
diff --git a/sources/shiboken6/tests/test_generator/dummygentest.h b/sources/shiboken6/tests/test_generator/dummygentest.h
new file mode 100644
index 000000000..1b1143b0a
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/dummygentest.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DUMMYGENTABLETEST_H
+#define DUMMYGENTABLETEST_H
+
+#include <QObject>
+
+class DummyGenerator;
+
+class DummyGenTest : public QObject
+{
+ Q_OBJECT
+
+private:
+ QString workDir;
+ QString headerFilePath;
+ QString typesystemFilePath;
+ QString generatedFilePath;
+ QString projectFilePath;
+
+private slots:
+ void initTestCase();
+ void testCallGenRunnerWithFullPathToDummyGenModule();
+ void testCallGenRunnerWithNameOfDummyGenModule();
+ void testCallDummyGeneratorExecutable();
+ void testProjectFileArgumentsReading();
+};
+
+#endif
+
diff --git a/sources/shiboken6/tests/test_generator/dummygentestconfig.h.in b/sources/shiboken6/tests/test_generator/dummygentestconfig.h.in
new file mode 100644
index 000000000..9da17dcd3
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/dummygentestconfig.h.in
@@ -0,0 +1,15 @@
+#ifndef DUMMYGENTESTCONFIG_H
+#define DUMMYGENTESTCONFIG_H
+
+#define MODULE_EXTENSION "@CMAKE_SHARED_LIBRARY_SUFFIX@"
+#define DUMMYGENERATOR_BINARY "@DUMMYGENERATOR_EXECUTABLE@"
+#define DUMMYGENERATOR_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@"
+
+#ifdef _WINDOWS
+ #define PATH_SPLITTER ";"
+#else
+ #define PATH_SPLITTER ":"
+#endif
+
+#endif // DUMMYGENTESTCONFIG_H
+
diff --git a/sources/shiboken6/tests/test_generator/main.cpp b/sources/shiboken6/tests/test_generator/main.cpp
new file mode 100644
index 000000000..ba4440b2f
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/main.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <QtCore>
+
+int main(int argc, char *argv[])
+{
+ QStringList args;
+ args.append("--generator-set=dummy");
+ for (int i = 1; i < argc; i++)
+ args.append(argv[i]);
+ return QProcess::execute("generatorrunner", args);
+}
+
diff --git a/sources/shiboken6/tests/test_generator/run_test.cmake b/sources/shiboken6/tests/test_generator/run_test.cmake
new file mode 100644
index 000000000..37e40b993
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/run_test.cmake
@@ -0,0 +1,14 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# The tests are run through this script due to a limitation
+# on versions of CMake lesser than 2.8, that prevent setting
+# environment variables for tests from working.
+
+set(ENV{PATH} "${ENV_PATH}")
+set(ENV{QT_PLUGIN_PATH} "${ENV_QT_PLUGIN_PATH}")
+execute_process(COMMAND ${TEST} WORKING_DIRECTORY "${WORKDIR}" RESULT_VARIABLE OK)
+
+if(NOT OK EQUAL 0)
+ message(SEND_ERROR "${TEST} failed!")
+endif()
diff --git a/sources/shiboken6/tests/test_generator/test_global.h b/sources/shiboken6/tests/test_generator/test_global.h
new file mode 100644
index 000000000..6a95200cf
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/test_global.h
@@ -0,0 +1 @@
+struct Dummy {};
diff --git a/sources/shiboken6/tests/test_generator/test_typesystem.xml b/sources/shiboken6/tests/test_generator/test_typesystem.xml
new file mode 100644
index 000000000..c19a4e95e
--- /dev/null
+++ b/sources/shiboken6/tests/test_generator/test_typesystem.xml
@@ -0,0 +1,3 @@
+<typesystem package='dummy'>
+ <value-type name='Dummy'/>
+</typesystem>