aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--MANIFEST.in40
-rw-r--r--README.md52
-rw-r--r--README.pyside2.md71
-rw-r--r--README.shiboken2-generator.md37
-rw-r--r--README.shiboken2.md13
-rw-r--r--build_scripts/build_scripts.pyqtc18
-rw-r--r--build_scripts/config.py393
-rw-r--r--build_scripts/main.py387
-rw-r--r--build_scripts/options.py78
-rw-r--r--build_scripts/platforms/linux.py136
-rw-r--r--build_scripts/platforms/macos.py119
-rw-r--r--build_scripts/platforms/unix.py257
-rw-r--r--build_scripts/platforms/windows_desktop.py460
-rw-r--r--build_scripts/setup_runner.py165
-rw-r--r--build_scripts/utils.py225
-rw-r--r--coin_build_instructions.py40
-rw-r--r--coin_test_instructions.py17
-rw-r--r--examples/samplebinding/CMakeLists.txt26
-rw-r--r--examples/scriptableapplication/CMakeLists.txt34
-rw-r--r--examples/scriptableapplication/pyside2.pri40
-rw-r--r--examples/scriptableapplication/scriptableapplication.pro4
-rw-r--r--examples/utils/pyside2_config.py328
-rw-r--r--keyword-errors.lst43
-rw-r--r--popenasync.py360
-rw-r--r--setup.py112
-rw-r--r--sources/cmake_helpers/helpers.cmake78
m---------sources/pyside2-tools0
-rw-r--r--sources/pyside2/CMakeLists.txt63
-rw-r--r--sources/pyside2/PySide2/CMakeLists.txt6
-rw-r--r--sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml33
-rw-r--r--sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml25
-rw-r--r--sources/pyside2/PySide2/QtCore/CMakeLists.txt10
-rw-r--r--sources/pyside2/PySide2/QtCore/typesystem_core_common.xml130
-rw-r--r--sources/pyside2/PySide2/QtGui/CMakeLists.txt18
-rw-r--r--sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml401
-rw-r--r--sources/pyside2/PySide2/QtNetwork/CMakeLists.txt66
-rw-r--r--sources/pyside2/PySide2/QtNetwork/typesystem_network.xml15
-rw-r--r--sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml29
-rw-r--r--sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp6
-rw-r--r--sources/pyside2/PySide2/QtQml/typesystem_qml.xml4
-rw-r--r--sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp1
-rw-r--r--sources/pyside2/PySide2/QtQuick/typesystem_quick.xml2
-rw-r--r--sources/pyside2/PySide2/QtSql/typesystem_sql.xml3
-rw-r--r--sources/pyside2/PySide2/QtWidgets/CMakeLists.txt7
-rw-r--r--sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml53
-rw-r--r--sources/pyside2/PySide2/QtXmlPatterns/typesystem_xmlpatterns.xml2
-rw-r--r--sources/pyside2/PySide2/__init__.py.in20
-rw-r--r--sources/pyside2/PySide2/_config.py.in13
-rw-r--r--sources/pyside2/PySide2/support/signature/__init__.py6
-rw-r--r--sources/pyside2/PySide2/support/signature/fix-complaints.py2
-rw-r--r--sources/pyside2/PySide2/support/signature/layout.py237
-rw-r--r--sources/pyside2/PySide2/support/signature/lib/__init__.py40
-rw-r--r--sources/pyside2/PySide2/support/signature/lib/enum_sig.py113
-rw-r--r--sources/pyside2/PySide2/support/signature/loader.py29
-rw-r--r--sources/pyside2/PySide2/support/signature/mapping.py31
-rw-r--r--sources/pyside2/PySide2/support/signature/parser.py47
-rw-r--r--sources/pyside2/PySide2/typesystem_templates.xml30
-rw-r--r--sources/pyside2/cmake/Macros/PySideModules.cmake75
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtcore.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtcore.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtnetwork.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtnetwork.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtopengl.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtopengl.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtprintsupport.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtprintsupport.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtqml.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtqml.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtquick.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtquick.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtsql.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtsql.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qttest.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qttest.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtwidgets.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtwidgets.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtxml.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtxml.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtcharts.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtcharts.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtgui.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtgui.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtmultimedia.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtmultimedia.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtxmlpatterns.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtxmlpatterns.cpp)0
-rw-r--r--sources/pyside2/doc/codesnippets/doc/src/snippets/quiloader/doc_src_qtuiloader.py (renamed from sources/pyside2/doc/codesnippets/doc/src/snippets/quiloader/doc_src_qtuiloader.cpp)0
-rw-r--r--sources/pyside2/doc/gettingstarted.rst18
-rw-r--r--sources/pyside2/doc/pysideapi2.rst7
-rw-r--r--sources/pyside2/doc/pysideversion.rst14
-rw-r--r--sources/pyside2/doc/tutorials/index.rst4
-rw-r--r--sources/pyside2/libpyside/CMakeLists.txt13
-rw-r--r--sources/pyside2/libpyside/destroylistener.cpp3
-rw-r--r--sources/pyside2/libpyside/destroylistener.h6
-rw-r--r--sources/pyside2/libpyside/dynamicqmetaobject.cpp946
-rw-r--r--sources/pyside2/libpyside/dynamicqmetaobject.h45
-rw-r--r--sources/pyside2/libpyside/dynamicqmetaobject_p.h5
-rw-r--r--sources/pyside2/libpyside/globalreceiver.cpp329
-rw-r--r--sources/pyside2/libpyside/globalreceiverv2.cpp48
-rw-r--r--sources/pyside2/libpyside/globalreceiverv2.h26
-rw-r--r--sources/pyside2/libpyside/pyside.cpp90
-rw-r--r--sources/pyside2/libpyside/pyside.h12
-rw-r--r--sources/pyside2/libpyside/pyside_p.h (renamed from sources/pyside2/libpyside/globalreceiver.h)53
-rw-r--r--sources/pyside2/libpyside/pysideclassinfo.cpp20
-rw-r--r--sources/pyside2/libpyside/pysideclassinfo.h6
-rw-r--r--sources/pyside2/libpyside/pysidemetafunction.cpp7
-rw-r--r--sources/pyside2/libpyside/pysidemetafunction.h7
-rw-r--r--sources/pyside2/libpyside/pysidemetafunction_p.h4
-rw-r--r--sources/pyside2/libpyside/pysideproperty.cpp33
-rw-r--r--sources/pyside2/libpyside/pysideproperty.h4
-rw-r--r--sources/pyside2/libpyside/pysideqflags.cpp12
-rw-r--r--sources/pyside2/libpyside/pysidesignal.cpp41
-rw-r--r--sources/pyside2/libpyside/pysidesignal.h13
-rw-r--r--sources/pyside2/libpyside/pysideslot.cpp9
-rw-r--r--sources/pyside2/libpyside/pysideweakref.cpp2
-rw-r--r--sources/pyside2/libpyside/signalmanager.cpp (renamed from sources/pyside2/libpyside/signalmanager.cpp.in)132
-rw-r--r--sources/pyside2/libpyside/signalmanager.h34
-rw-r--r--sources/pyside2/pyside_version.py14
-rw-r--r--sources/pyside2/tests/CMakeLists.txt2
-rw-r--r--sources/pyside2/tests/QtCore/CMakeLists.txt1
-rw-r--r--sources/pyside2/tests/QtCore/qcbor_test.py74
-rw-r--r--sources/pyside2/tests/QtCore/qmetaobject_test.py6
-rw-r--r--sources/pyside2/tests/QtGui/qmatrix_test.py15
-rw-r--r--sources/pyside2/tests/QtNetwork/CMakeLists.txt1
-rw-r--r--sources/pyside2/tests/QtNetwork/qpassworddigestor_test.py45
-rw-r--r--sources/pyside2/tests/QtWidgets/python_properties_test.py2
-rw-r--r--sources/pyside2/tests/QtWidgets/qwidget_test.py23
-rw-r--r--sources/pyside2/tests/pysidetest/CMakeLists.txt8
-rw-r--r--sources/pyside2/tests/pysidetest/new_inherited_functions_test.py153
-rw-r--r--sources/pyside2/tests/registry/init_platform.py90
-rw-r--r--sources/shiboken2/ApiExtractor/CMakeLists.txt1
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp698
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.h14
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h45
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp398
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h99
-rw-r--r--sources/shiboken2/ApiExtractor/apiextractor.cpp34
-rw-r--r--sources/shiboken2/ApiExtractor/apiextractor.h3
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp236
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp2
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp49
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangutils.h13
-rw-r--r--sources/shiboken2/ApiExtractor/doc/conf.py.in4
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst50
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst65
-rw-r--r--sources/shiboken2/ApiExtractor/docparser.cpp79
-rw-r--r--sources/shiboken2/ApiExtractor/docparser.h16
-rw-r--r--sources/shiboken2/ApiExtractor/doxygenparser.cpp30
-rw-r--r--sources/shiboken2/ApiExtractor/fileout.cpp180
-rw-r--r--sources/shiboken2/ApiExtractor/fileout.h15
-rw-r--r--sources/shiboken2/ApiExtractor/include.cpp5
-rw-r--r--sources/shiboken2/ApiExtractor/include.h3
-rw-r--r--sources/shiboken2/ApiExtractor/messages.cpp446
-rw-r--r--sources/shiboken2/ApiExtractor/messages.h142
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel.cpp222
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel.h54
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel_enums.h13
-rw-r--r--sources/shiboken2/ApiExtractor/parser/enumvalue.h1
-rw-r--r--sources/shiboken2/ApiExtractor/qtdocparser.cpp1
-rw-r--r--sources/shiboken2/ApiExtractor/tests/CMakeLists.txt17
-rw-r--r--sources/shiboken2/ApiExtractor/tests/injectedcode.txt5
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp37
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp3
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp45
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcodeinjection.h3
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcodeinjection.qrc6
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp6
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testenum.cpp3
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.qrc5
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp99
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp3
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtemplates.cpp119
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtemplates.h2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp49
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtyperevision.h2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testutil.h11
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.cpp379
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.h28
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase_typedefs.h25
-rw-r--r--sources/shiboken2/ApiExtractor/typeparser.cpp57
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.cpp3764
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.h366
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_enums.h21
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_p.h112
-rw-r--r--sources/shiboken2/CMakeLists.txt5
-rw-r--r--sources/shiboken2/doc/commandlineoptions.rst110
-rw-r--r--sources/shiboken2/generator/CMakeLists.txt30
-rw-r--r--sources/shiboken2/generator/__init__.py.in2
-rw-r--r--sources/shiboken2/generator/_config.py.in9
-rw-r--r--sources/shiboken2/generator/generator.cpp408
-rw-r--r--sources/shiboken2/generator/generator.h182
-rw-r--r--sources/shiboken2/generator/main.cpp329
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp132
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.h6
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp670
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h15
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.cpp145
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.h4
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.cpp18
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.h2
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp451
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h284
-rw-r--r--sources/shiboken2/libshiboken/autodecref.h29
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp360
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.h8
-rw-r--r--sources/shiboken2/libshiboken/basewrapper_p.h106
-rw-r--r--sources/shiboken2/libshiboken/bindingmanager.cpp49
-rw-r--r--sources/shiboken2/libshiboken/bindingmanager.h13
-rw-r--r--sources/shiboken2/libshiboken/gilstate.h5
-rw-r--r--sources/shiboken2/libshiboken/helper.cpp26
-rw-r--r--sources/shiboken2/libshiboken/helper.h11
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.cpp27
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.h8
-rw-r--r--sources/shiboken2/libshiboken/sbkconverter.cpp8
-rw-r--r--sources/shiboken2/libshiboken/sbkconverter_p.h6
-rw-r--r--sources/shiboken2/libshiboken/sbkdbg.h5
-rw-r--r--sources/shiboken2/libshiboken/sbkenum.cpp36
-rw-r--r--sources/shiboken2/libshiboken/sbkpython.h58
-rw-r--r--sources/shiboken2/libshiboken/sbkstring.cpp5
-rw-r--r--sources/shiboken2/libshiboken/shibokenbuffer.cpp4
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp291
-rw-r--r--sources/shiboken2/libshiboken/signature.h6
-rw-r--r--sources/shiboken2/libshiboken/threadstatesaver.h8
-rw-r--r--sources/shiboken2/libshiboken/typespec.cpp45
-rw-r--r--sources/shiboken2/libshiboken/typespec.h4
-rwxr-xr-xsources/shiboken2/shiboken_tool.py53
-rw-r--r--sources/shiboken2/shiboken_version.py14
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt27
-rw-r--r--sources/shiboken2/shibokenmodule/__init__.py.in4
-rw-r--r--sources/shiboken2/shibokenmodule/_config.py.in11
-rw-r--r--sources/shiboken2/tests/libsample/CMakeLists.txt1
-rw-r--r--sources/shiboken2/tests/libsample/exceptiontest.cpp64
-rw-r--r--sources/shiboken2/tests/libsample/exceptiontest.h48
-rw-r--r--sources/shiboken2/tests/libsample/mapuser.cpp5
-rw-r--r--sources/shiboken2/tests/libsample/mapuser.h2
-rw-r--r--sources/shiboken2/tests/libsample/nontypetemplate.h51
-rw-r--r--sources/shiboken2/tests/libsample/objecttype.cpp1
-rw-r--r--sources/shiboken2/tests/libsample/objecttype.h2
-rw-r--r--sources/shiboken2/tests/libsample/samplenamespace.cpp7
-rw-r--r--sources/shiboken2/tests/libsample/samplenamespace.h6
-rw-r--r--sources/shiboken2/tests/minimalbinding/CMakeLists.txt5
-rw-r--r--sources/shiboken2/tests/otherbinding/CMakeLists.txt5
-rw-r--r--sources/shiboken2/tests/samplebinding/CMakeLists.txt8
-rw-r--r--sources/shiboken2/tests/samplebinding/exception_test.py78
-rw-r--r--sources/shiboken2/tests/samplebinding/global.h2
-rw-r--r--sources/shiboken2/tests/samplebinding/nontypetemplate_test.py44
-rw-r--r--sources/shiboken2/tests/samplebinding/typesystem_sample.xml9
-rw-r--r--sources/shiboken2/tests/smartbinding/CMakeLists.txt5
-rw-r--r--testing/wheel_tester.py295
239 files changed, 12079 insertions, 8109 deletions
diff --git a/.gitignore b/.gitignore
index 6a8b69288..903fc81f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
/build
/dist
/pyside*_build
-/pyside*_package
/pyside*_install
/PySide
/PySide-*.*.*
@@ -13,3 +12,5 @@ distribute-*.egg
distribute-*.tar.gz
explore2
build_history/2*
+*.qdocconf
+*.qdocconf.in
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index dd79b2380..000000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# MANIFEST.in
-#
-# Manifest template for creating the PySide source distribution.
-
-include MANIFEST.in
-include CHANGES.rst
-include README.rst
-include ez_setup.py
-include setup.py
-include popenasync.py
-include qtinfo.py
-include utils.py
-
-# sources
-recursive-include sources/patchelf **
-recursive-include sources/shiboken2 **
-recursive-include sources/pyside2 **
-recursive-include sources/pyside2-tools **
-# ignore .git
-recursive-exclude sources/shiboken2/.git **
-recursive-exclude sources/pyside2/.git **
-recursive-exclude sources/pyside2-tools/.git **
-
-# PySide package
-recursive-include pyside_package/PySide2 **
-recursive-include pyside_package/PySide2/docs **
-recursive-include pyside_package/PySide2/plugins **
-recursive-include pyside_package/PySide2s **
-recursive-include pyside_package/PySide2/translations **
-recursive-include pyside_package/PySide2include **
-recursive-include pyside_package/PySide2/typesystems **
-recursive-include pyside_package/PySide2/examples **
-
-# pysideuic package
-recursive-include pyside_package/pysideuic **
-recursive-include pyside_package/pysideuic/Compiler **
-recursive-include pyside_package/pysideuic/port_v2 **
-recursive-include pyside_package/pysideuic/port_v3 **
-recursive-include pyside_package/pysideuic/widget-plugins **
diff --git a/README.md b/README.md
index cde05940d..fe61136b2 100644
--- a/README.md
+++ b/README.md
@@ -1,53 +1,9 @@
-# PySide2
+# Qt For Python
-### Introduction
-
-PySide is the [Python Qt bindings project](http://wiki.qt.io/PySide2), providing
+Qt For Python is the [Python Qt bindings project](http://wiki.qt.io/PySide2), providing
access to the complete Qt 5.x framework as well as to generator tools for rapidly
generating bindings for any C++ libraries.
-The PySide project is developed in the open, with all facilities you'd expect
-from any modern OSS project such as all code in a git repository and an open
-design process. We welcome any contribution conforming to the
-[Qt Contribution Agreement](https://www.qt.io/contributionagreement/).
-
-
-PySide 2 supports Qt5. For building, please read about
-[getting started](https://wiki.qt.io/PySide2_GettingStarted).
-Then download the sources by running
-
- git clone https://code.qt.io/pyside/pyside-setup
-
-### Building
-
-#### Dependencies
-
-PySide versions following 5.6 use a C++ parser based on
-[Clang](http://clang.org/). The Clang library (C-bindings), version 3.9 or
-higher is required for building. Prebuilt versions of it can be downloaded from
-[download.qt.io](http://download.qt.io/development_releases/prebuilt/libclang/).
-
-After unpacking the archive, set the environment variable *LLVM_INSTALL_DIR* to
-point to the folder containing the *include* and *lib* directories of Clang:
-
- 7z x .../libclang-release_39-linux-Rhel7.2-gcc5.3-x86_64.7z
- export LLVM_INSTALL_DIR=$PWD/libclang
-
-On Windows:
-
- 7z x .../libclang-release_39-windows-vs2015_64.7z
- SET LLVM_INSTALL_DIR=%CD%\libclang
-
-#### Build Instructions
-
-You might consider using a virtual environment as described at
-[getting started](https://wiki.qt.io/PySide2_GettingStarted).
-You should be able to build:
-
- cd pyside-setup
- python setup.py install
+shiboken2 is the generator used to build the bindings.
-The setup script will try to find the location of the qmake tool of the Qt
-version to be used and the cmake build tool in the path. Non-standard
-locations can be specified by the *--qmake=path_to_qmake* or
-*--cmake=path_to_cmake* command line options.
+See README.pyside2.md and README.shiboken2.md for details.
diff --git a/README.pyside2.md b/README.pyside2.md
new file mode 100644
index 000000000..53f7bc9d0
--- /dev/null
+++ b/README.pyside2.md
@@ -0,0 +1,71 @@
+# PySide2
+
+### Introduction
+
+PySide is the [Python Qt bindings project](http://wiki.qt.io/Qt_for_Python),
+providing access to the complete Qt 5.12+ framework as well as to generator
+tools for rapidly generating Python bindings for any C++ libraries.
+
+The PySide project is developed in the open, with all facilities you'd expect
+from any modern OSS project such as all code in a git repository and an open
+design process. We welcome any contribution conforming to the
+[Qt Contribution Agreement](https://www.qt.io/contributionagreement/).
+
+### Installation
+
+Since the release of the [Technical Preview](https://blog.qt.io/blog/2018/06/13/qt-python-5-11-released/)
+it is possible to install via `pip`, both from Qt's servers
+and [PyPi](https://pypi.org/project/PySide2/):
+
+ pip install PySide2
+
+#### Dependencies
+
+PySide versions following 5.12 use a C++ parser based on
+[Clang](http://clang.org/). The Clang library (C-bindings), version 6.0 or
+higher is required for building. Prebuilt versions of it can be downloaded from
+[download.qt.io](http://download.qt.io/development_releases/prebuilt/libclang/).
+
+After unpacking the archive, set the environment variable *LLVM_INSTALL_DIR* to
+point to the folder containing the *include* and *lib* directories of Clang:
+
+ 7z x .../libclang-release_60-linux-Rhel7.2-gcc5.3-x86_64-clazy.7z
+ export LLVM_INSTALL_DIR=$PWD/libclang
+
+On Windows:
+
+ 7z x .../libclang-release_60-windows-vs2015_64-clazy.7z
+ SET LLVM_INSTALL_DIR=%CD%\libclang
+
+### Building from source
+
+For building PySide2 from scratch, please read about
+[getting started](https://wiki.qt.io/Qt_for_Python/GettingStarted).
+This process will include getting the code:
+
+ git clone https://code.qt.io/pyside/pyside-setup
+ cd pyside-setup
+ git branch --track 5.12 origin/5.12
+ git checkout 5.12
+
+then install the dependencies, and following the instructions per platform.
+A common build command will look like:
+
+ python setup.py install --qmake=<path/to/qmake/> --jobs=8 --build-tests
+
+You can obtain more information about the options to build PySide
+and Shiboken in [our wiki](https://wiki.qt.io/Qt_for_Python/).
+
+### Documentation and Bugs
+
+You can find more information about the PySide2 module API in the
+[official Qt for Python documentation](https://doc.qt.io/qtforpython/).
+
+If you come across any issue, please file a bug report at our
+[JIRA tracker](https://bugreports.qt.io/projects/PYSIDE) following
+our [guidelines](https://wiki.qt.io/Qt_for_Python/Reporting_Bugs).
+
+### Community
+
+Check *#qt-pyside*, our official IRC channel on FreeNode,
+or contact us via our [mailing list](http://lists.qt-project.org/mailman/listinfo/pyside).
diff --git a/README.shiboken2-generator.md b/README.shiboken2-generator.md
new file mode 100644
index 000000000..f29f40634
--- /dev/null
+++ b/README.shiboken2-generator.md
@@ -0,0 +1,37 @@
+# shiboken2-generator
+
+Shiboken is the generator used by the Qt for Python project.
+It outputs C++ code for CPython extensions, which can be compiled
+and transformed into a Python module.
+
+C++ projects based on Qt can be wrapped, but also projects
+which are not related to Qt.
+
+## How does it work?
+
+Shiboken uses an API Extractor that does most of the job,
+but it requires a typesystem (XML file) to customize how the
+C++ classes/methods will be exposed to Python.
+
+The typesystem allows you to remove arguments from signatures,
+modify return types, inject code and add conversion rules
+from the C++ data types to Python data types, manipulate
+the ownership of the objects, etc.
+
+# Examples
+
+An example related to wrap a C++ library not depending on Qt
+can be found in our [repository](https://code.qt.io/cgit/pyside/pyside-setup.git/tree/examples/samplebinding).
+
+Additionally, you can find a couple of tests inside the
+[git repository](https://code.qt.io/cgit/pyside/pyside-setup.git/tree/sources/shiboken2/tests).
+
+For a more advanced case regarding extending a Qt/C++ application
+with Python bindings based on the idea of the PySide module,
+you can check the [scriptableapplication](https://code.qt.io/cgit/pyside/pyside-setup.git/tree/examples/scriptableapplication)
+example in our repository.
+
+# Documentation
+
+You can find more information about Shiboken in our
+[official documentation page](https://doc.qt.io/qtforpython/shiboken2/).
diff --git a/README.shiboken2.md b/README.shiboken2.md
new file mode 100644
index 000000000..d9cd32a40
--- /dev/null
+++ b/README.shiboken2.md
@@ -0,0 +1,13 @@
+# shiboken2 module
+
+The purpose of the shiboken2 Python module is to access information
+related to the binding generation that could be used to integrate
+C++ programs to Python, or even to get useful information to debug
+an application.
+
+Mostly the idea is to interact with Shiboken objects,
+where one can check if it is valid, or if the generated Python wrapper
+is invalid after the underlying C++ object has been destroyed.
+
+More information on the available functions can be found
+in our [official documentation](https://doc.qt.io/qtforpython/shiboken2/shibokenmodule.html)
diff --git a/build_scripts/build_scripts.pyqtc b/build_scripts/build_scripts.pyqtc
new file mode 100644
index 000000000..1fc1c9664
--- /dev/null
+++ b/build_scripts/build_scripts.pyqtc
@@ -0,0 +1,18 @@
+__init__.py
+config.py
+main.py
+options.py
+platforms
+qtinfo.py
+setup_runner.py
+utils.py
+wheel_override.py
+platforms/__init__.py
+platforms/linux.py
+platforms/macos.py
+platforms/unix.py
+platforms/windows_desktop.py
+../setup.py
+../coin_build_instructions.py
+../coin_test_instructions.py
+
diff --git a/build_scripts/config.py b/build_scripts/config.py
new file mode 100644
index 000000000..78d7d4040
--- /dev/null
+++ b/build_scripts/config.py
@@ -0,0 +1,393 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import sys, os
+import distutils.log as log
+
+
+class Config(object):
+ def __init__(self):
+ # Constants
+ self._build_type_all = "all"
+ self._invocation_type_top_level = "top-level"
+ self._invocation_type_internal = "internal"
+
+ # The keyword arguments which will be given to setuptools.setup
+ self.setup_kwargs = {}
+
+ # The setup.py invocation type.
+ # top-level
+ # internal
+ self.invocation_type = None
+
+ # The type of the top-level build.
+ # all - build shiboken2 module, shiboken2-generator and PySide2
+ # modules
+ # shiboken2 - build only shiboken2 module
+ # shiboken2-generator - build only the shiboken2-generator
+ # pyside2 - build only PySide2 modules
+ self.build_type = None
+
+ # The internal build type, used for internal invocations of
+ # setup.py to build a specific module only.
+ self.internal_build_type = None
+
+ # Options that can be given to --build-type and
+ # --internal-build-type
+ self.shiboken_module_option_name = "shiboken2"
+ self.shiboken_generator_option_name = "shiboken2-generator"
+ self.pyside_option_name = "pyside2"
+
+ # Names to be passed to setuptools.setup() name key,
+ # so not package name, but rather project name as it appears
+ # in the wheel name and on PyPi.
+ self.shiboken_module_st_name = "shiboken2"
+ self.shiboken_generator_st_name = "shiboken2-generator"
+ self.pyside_st_name = "PySide2"
+
+ # Used by check_allowed_python_version to validate the
+ # interpreter version.
+ self.python_version_classifiers = [
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ ]
+
+ self.setup_script_dir = None
+
+ def init_config(self, build_type=None, internal_build_type=None,
+ cmd_class_dict=None, package_version=None,
+ ext_modules=None, setup_script_dir=None):
+ """
+ Sets up the global singleton config which is used in many parts
+ of the setup process.
+ """
+
+ # if --internal-build-type was passed, it means that this is a
+ # sub-invocation to build a specific package.
+ if internal_build_type:
+ self.set_is_internal_invocation()
+ self.set_internal_build_type(internal_build_type)
+ else:
+ self.set_is_top_level_invocation()
+
+ # --build-type was specified explicitly, so set it. Otherwise
+ # default to all.
+ if build_type:
+ self.build_type = build_type
+ else:
+ self.build_type = self._build_type_all
+
+ self.setup_script_dir = setup_script_dir
+
+ setup_kwargs = {}
+ setup_kwargs['long_description'] = self.get_long_description()
+ setup_kwargs['long_description_content_type'] = 'text/markdown',
+ setup_kwargs['keywords'] = 'Qt'
+ setup_kwargs['author'] = 'Qt for Python Team'
+ setup_kwargs['author_email'] = 'pyside@qt-project.org'
+ setup_kwargs['url'] = 'https://www.pyside.org'
+ setup_kwargs['download_url'] = 'https://download.qt.io/official_releases/QtForPython'
+ setup_kwargs['license'] = 'LGPL'
+ setup_kwargs['zip_safe'] = False
+ setup_kwargs['cmdclass'] = cmd_class_dict
+ setup_kwargs['version'] = package_version
+
+ # Setting these two keys is still a bit of a discussion point.
+ # In general not setting them will allow using "build" and
+ # "bdist_wheel" just fine. What they do, is they specify to the
+ # setuptools.command.build_py command that certain pure python
+ # modules (.py files) exist in the specified package location,
+ # and that they should be copied over to the setuptools build
+ # dir.
+ # But it doesn't really make sense for us, because we copy all
+ # the necessary files to the build dir via prepare_packages()
+ # function anyway.
+ # If we don't set them, the build_py sub-command will be
+ # skipped, but the build command will still be executed, which
+ # is where we run cmake / make.
+ # The only plausible usage of it, is if we will implement a
+ # correctly functioning setup.py develop command (or bdist_egg).
+ # But currently that doesn't seem to work.
+ setup_kwargs['packages'] = self.get_setup_tools_packages_for_current_build()
+ setup_kwargs['package_dir'] = self.get_package_name_to_dir_path_mapping()
+
+ # Add a bogus extension module (will never be built here since
+ # we are overriding the build command to do it using cmake) so
+ # things like bdist_egg will know that there are extension
+ # modules and will name the dist with the full platform info.
+ setup_kwargs['ext_modules'] = ext_modules
+
+ common_classifiers = [
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Console',
+ 'Environment :: MacOS X',
+ 'Environment :: X11 Applications :: Qt',
+ 'Environment :: Win32 (MS Windows)',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
+ 'Operating System :: MacOS :: MacOS X',
+ 'Operating System :: POSIX',
+ 'Operating System :: POSIX :: Linux',
+ 'Operating System :: Microsoft',
+ 'Operating System :: Microsoft :: Windows',
+ 'Programming Language :: C++']
+ common_classifiers.extend(self.python_version_classifiers)
+ common_classifiers.extend([
+ 'Topic :: Database',
+ 'Topic :: Software Development',
+ 'Topic :: Software Development :: Code Generators',
+ 'Topic :: Software Development :: Libraries :: Application Frameworks',
+ 'Topic :: Software Development :: User Interfaces',
+ 'Topic :: Software Development :: Widget Sets'])
+ setup_kwargs['classifiers'] = common_classifiers
+
+ if self.internal_build_type == self.shiboken_module_option_name:
+ setup_kwargs['name'] = self.shiboken_module_st_name
+ setup_kwargs['description'] = "Python / C++ bindings helper module",
+ setup_kwargs['entry_points'] = {}
+
+ elif self.internal_build_type == self.shiboken_generator_option_name:
+ setup_kwargs['name'] = self.shiboken_generator_st_name
+ setup_kwargs['description'] = "Python / C++ bindings generator",
+ setup_kwargs['install_requires'] = [self.shiboken_module_st_name]
+ setup_kwargs['entry_points'] = {
+ 'console_scripts': [
+ 'shiboken2 = {}.scripts.shiboken_tool:main'.format(self.package_name()),
+ ]
+ }
+
+ elif self.internal_build_type == self.pyside_option_name:
+ setup_kwargs['name'] = self.pyside_st_name
+ setup_kwargs['description'] = ("Python bindings for the Qt cross-platform application"
+ " and UI framework"),
+ setup_kwargs['install_requires'] = [self.shiboken_module_st_name]
+ setup_kwargs['entry_points'] = {
+ 'console_scripts': [
+ 'pyside2-uic = {}.scripts.uic:main'.format(self.package_name()),
+ 'pyside2-rcc = {}.scripts.pyside_tool:main'.format(self.package_name()),
+ 'pyside2-lupdate = {}.scripts.pyside_tool:main'.format(self.package_name()),
+ ]
+ }
+ self.setup_kwargs = setup_kwargs
+
+ def get_long_description(self):
+ readme_filename = 'README.md'
+ changes_filename = 'CHANGES.rst'
+
+ if self.is_internal_shiboken_module_build():
+ readme_filename = 'README.shiboken2.md'
+ elif self.is_internal_shiboken_generator_build():
+ readme_filename = 'README.shiboken2-generator.md'
+ elif self.is_internal_pyside_build():
+ readme_filename = 'README.pyside2.md'
+
+ content = ''
+ changes = ''
+ try:
+ with open(os.path.join(self.setup_script_dir, readme_filename)) as f:
+ readme = f.read()
+ except Exception as e:
+ log.error("Couldn't read contents of {}.".format(readme_filename))
+ raise
+
+ # Don't include CHANGES.rst for now, because we have not decided
+ # how to handle change files yet.
+ include_changes = False
+ if include_changes:
+ try:
+ with open(os.path.join(self.setup_script_dir, changes_filename)) as f:
+ changes = f.read()
+ except Exception as e:
+ log.error("Couldn't read contents of {}".format(changes_filename))
+ raise
+ content += readme
+
+ if changes:
+ content += "\n\n" + changes
+
+ return content
+
+ def package_name(self):
+ """
+ Returns package name as it appears in Python's site-packages
+ directory.
+
+ Package names can only be delimited by underscores, and not by
+ dashes.
+ """
+ if self.is_internal_shiboken_module_build():
+ return "shiboken2"
+ elif self.is_internal_shiboken_generator_build():
+ return "shiboken2_generator"
+ elif self.is_internal_pyside_build():
+ return "PySide2"
+ else:
+ return None
+
+ def get_setup_tools_packages_for_current_build(self):
+ """
+ Returns a list of packages for setup tools to consider in the
+ build_py command, so that it can copy the pure python files.
+ Not really necessary because it's done in prepare_packages()
+ anyway.
+
+ This is really just to satisfy some checks in setuptools
+ build_py command, and if we ever properly implement the develop
+ command.
+ """
+ if self.internal_build_type == self.pyside_option_name:
+ return [
+ config.package_name(),
+ 'pyside2uic',
+ 'pyside2uic.Compiler',
+ 'pyside2uic.port_v{}'.format(sys.version_info[0])
+ ]
+ elif self.internal_build_type == self.shiboken_module_option_name:
+ return [self.package_name()]
+ else:
+ return []
+
+ def get_package_name_to_dir_path_mapping(self):
+ """
+ Used in setuptools.setup 'package_dir' argument to specify where
+ the actual module packages are located.
+
+ For example when building the shiboken module, setuptools will
+ expect to find the "shiboken2" module sources under
+ "sources/shiboken2/shibokenmodule".
+
+ This is really just to satisfy some checks in setuptools
+ build_py command, and if we ever properly implement the develop
+ command.
+ """
+ if self.is_internal_shiboken_module_build():
+ return {
+ self.package_name(): "sources/shiboken2/shibokenmodule"
+ }
+ elif self.is_internal_shiboken_generator_build():
+ # This is left empty on purpose, because the shiboken
+ # generator doesn't have a python module for now.
+ return {}
+ elif self.is_internal_pyside_build():
+ return {
+ self.package_name(): "sources/pyside2/PySide2",
+ "pyside2uic": "sources/pyside2-tools/pyside2uic"
+ }
+ else:
+ return {}
+
+ def get_buildable_extensions(self):
+ """
+ Used by PysideBuild.run to build the CMake projects.
+ :return: A list of directory names under the sources directory.
+ """
+ if self.is_internal_shiboken_module_build() or self.is_internal_shiboken_generator_build():
+ return ['shiboken2']
+ elif self.is_internal_pyside_build():
+ return ['pyside2', 'pyside2-tools']
+ return None
+
+ def set_is_top_level_invocation(self):
+ self.invocation_type = self._invocation_type_top_level
+
+ def set_is_internal_invocation(self):
+ self.invocation_type = self._invocation_type_internal
+
+ def is_top_level_invocation(self):
+ return self.invocation_type == self._invocation_type_top_level
+
+ def is_internal_invocation(self):
+ return self.invocation_type == self._invocation_type_internal
+
+ def is_top_level_build_all(self):
+ return self.build_type == self._build_type_all
+
+ def is_top_level_build_shiboken_module(self):
+ return self.build_type == self.shiboken_module_option_name
+
+ def is_top_level_build_shiboken_generator(self):
+ return self.build_type == self.shiboken_generator_option_name
+
+ def is_top_level_build_pyside(self):
+ return self.build_type == self.pyside_option_name
+
+ def set_internal_build_type(self, internal_build_type):
+ self.internal_build_type = internal_build_type
+
+ def is_internal_shiboken_module_build(self):
+ return self.internal_build_type == self.shiboken_module_option_name
+
+ def is_internal_shiboken_generator_build(self):
+ return self.internal_build_type == self.shiboken_generator_option_name
+
+ def is_internal_pyside_build(self):
+ return self.internal_build_type == self.pyside_option_name
+
+ def is_internal_shiboken_generator_build_and_part_of_top_level_all(self):
+ """
+ Used to skip certain build rules and output, when we know that
+ the CMake build of shiboken was already done as part of the
+ top-level "all" build when shiboken2-module was built.
+ """
+ return self.is_internal_shiboken_generator_build() and self.is_top_level_build_all()
+
+ def get_allowed_top_level_build_values(self):
+ return [
+ self._build_type_all,
+ self.shiboken_module_option_name,
+ self.shiboken_generator_option_name,
+ self.pyside_option_name
+ ]
+
+ def get_allowed_internal_build_values(self):
+ return [
+ self.shiboken_module_option_name,
+ self.shiboken_generator_option_name,
+ self.pyside_option_name
+ ]
+
+
+config = Config()
diff --git a/build_scripts/main.py b/build_scripts/main.py
index b64d6f1a9..50f751caa 100644
--- a/build_scripts/main.py
+++ b/build_scripts/main.py
@@ -42,6 +42,7 @@ from distutils.version import LooseVersion
import os
import time
+from .config import config
from .utils import memoize, get_python_dict
from .options import *
@@ -90,15 +91,11 @@ def get_setuptools_extension_modules():
extension_modules = [Extension(*extension_args, **extension_kwargs)]
return extension_modules
-# Buildable extensions.
-contained_modules = ['shiboken2', 'pyside2', 'pyside2-tools']
# Git submodules: ["submodule_name",
# "location_relative_to_sources_folder"]
submodules = [["pyside2-tools"]]
-pyside_package_dir_name = "pyside_package"
-
try:
import setuptools
except ImportError:
@@ -108,13 +105,8 @@ except ImportError:
import sys
import platform
import re
-import fnmatch
-
-import difflib # for a close match of dirname and module
-import functools
-from distutils import log
-from distutils.errors import DistutilsOptionError
+import distutils.log as log
from distutils.errors import DistutilsSetupError
from distutils.sysconfig import get_config_var
from distutils.sysconfig import get_python_lib
@@ -123,7 +115,7 @@ from distutils.command.build import build as _build
from distutils.command.build_ext import build_ext as _build_ext
from distutils.util import get_platform
-from setuptools import setup, Extension
+from setuptools import Extension
from setuptools.command.install import install as _install
from setuptools.command.install_lib import install_lib as _install_lib
from setuptools.command.bdist_egg import bdist_egg as _bdist_egg
@@ -132,39 +124,40 @@ from setuptools.command.build_py import build_py as _build_py
from .qtinfo import QtInfo
from .utils import rmtree, detect_clang, copyfile, copydir, run_process_output, run_process
-from .utils import update_env_path, init_msvc_env, filter_match, macos_fix_rpaths_for_library
+from .utils import update_env_path, init_msvc_env, filter_match
+from .utils import macos_fix_rpaths_for_library
+from .utils import linux_fix_rpaths_for_library
from .platforms.unix import prepare_packages_posix
from .platforms.windows_desktop import prepare_packages_win32
from .wheel_override import wheel_module_exists, get_bdist_wheel_override
from textwrap import dedent
-# make sure that setup.py is run with an allowed python version
+
def check_allowed_python_version():
+ """
+ Make sure that setup.py is run with an allowed python version.
+ """
+
import re
- pattern = "'Programming Language :: Python :: (\d+)\.(\d+)'"
+ pattern = "Programming Language :: Python :: (\d+)\.(\d+)"
supported = []
- with open(setup_py_path) as setup:
- for line in setup.readlines():
- found = re.search(pattern, line)
- if found:
- major = int(found.group(1))
- minor = int(found.group(2))
- supported.append( (major, minor) )
+
+ for line in config.python_version_classifiers:
+ found = re.search(pattern, line)
+ if found:
+ major = int(found.group(1))
+ minor = int(found.group(2))
+ supported.append( (major, minor) )
this_py = sys.version_info[:2]
if this_py not in supported:
- print("only these python versions are supported:", supported)
+ print("Unsupported python version detected. Only these python versions are supported: {}"
+ .format(supported))
sys.exit(1)
-check_allowed_python_version()
qt_src_dir = ''
-# This is used automatically by distutils.command.install object, to
-# specify final installation location.
-OPTION_FINAL_INSTALL_PREFIX = option_value("prefix")
-
-
if OPTION_QT_VERSION is None:
OPTION_QT_VERSION = "5"
if OPTION_QMAKE is None:
@@ -293,8 +286,7 @@ def get_qt_version():
qt_version = qtinfo.version
if not qt_version:
- log.error("Failed to query the Qt version with qmake {0}".format(
- self.qtinfo.qmake_command))
+ log.error("Failed to query the Qt version with qmake {0}".format(qtinfo.qmake_command))
sys.exit(1)
if LooseVersion(qtinfo.version) < LooseVersion("5.7"):
@@ -304,12 +296,13 @@ def get_qt_version():
return qt_version
+
def prepare_build():
if (os.path.isdir(".git") and not OPTION_IGNOREGIT and
not OPTION_ONLYPACKAGE and not OPTION_REUSE_BUILD):
prepare_sub_modules()
- # Clean up temp and package folders
- for n in [pyside_package_dir_name, "build"]:
+ # Clean up temp build folder.
+ for n in ["build"]:
d = os.path.join(setup_script_dir, n)
if os.path.isdir(d):
print("Removing {}".format(d))
@@ -318,13 +311,7 @@ def prepare_build():
except Exception as e:
print('***** problem removing "{}"'.format(d))
print('ignored error: {}'.format(e))
- # Prepare package folders
- ppdn = pyside_package_dir_name
- absolute_paths = [os.path.join(ppdn, "PySide2"),
- os.path.join(ppdn, "pyside2uic")]
- for pkg in absolute_paths:
- pkg_dir = os.path.join(setup_script_dir, pkg)
- os.makedirs(pkg_dir)
+
# locate Qt sources for the documentation
if OPTION_QT_SRC is None:
install_prefix = qtinfo.prefix_dir
@@ -389,26 +376,15 @@ class PysideBuildExt(_build_ext):
pass
-
-# pyside_build_py and pyside_install_lib are reimplemented to preserve
-# symlinks when distutils / setuptools copy files to various
-# directories through the different build stages.
class PysideBuildPy(_build_py):
def __init__(self, *args, **kwargs):
_build_py.__init__(self, *args, **kwargs)
- def build_package_data(self):
- """Copies files from pyside_package into build/xxx directory"""
-
- for package, src_dir, build_dir, filenames in self.data_files:
- for filename in filenames:
- target = os.path.join(build_dir, filename)
- self.mkpath(os.path.dirname(target))
- srcfile = os.path.abspath(os.path.join(src_dir, filename))
- # Using our own copyfile makes sure to preserve symlinks.
- copyfile(srcfile, target)
+# _install_lib is reimplemented to preserve
+# symlinks when distutils / setuptools copy files to various
+# directories from the setup tools build dir to the install dir.
class PysideInstallLib(_install_lib):
def __init__(self, *args, **kwargs):
@@ -539,10 +515,12 @@ class PysideBuild(_build):
py_prefix = get_config_var("prefix")
if not py_prefix or not os.path.exists(py_prefix):
py_prefix = sys.prefix
+ self.py_prefix = py_prefix
if sys.platform == "win32":
py_scripts_dir = os.path.join(py_prefix, "Scripts")
else:
py_scripts_dir = os.path.join(py_prefix, "bin")
+ self.py_scripts_dir = py_scripts_dir
if py_libdir is None or not os.path.exists(py_libdir):
if sys.platform == "win32":
py_libdir = os.path.join(py_prefix, "libs")
@@ -656,7 +634,7 @@ class PysideBuild(_build):
qt_version = get_qt_version()
# Update the PATH environment variable
- additional_paths = [py_scripts_dir, qt_dir]
+ additional_paths = [self.py_scripts_dir, qt_dir]
# Add Clang to path for Windows.
# Revisit once Clang is bundled with Qt.
@@ -685,19 +663,11 @@ class PysideBuild(_build):
install_dir = os.path.join(script_dir, prefix() + "_install",
"{}".format(build_name))
- # Try to ensure that tools built by this script (such as shiboken2)
- # are found before any that may already be installed on the system.
- update_env_path([os.path.join(install_dir, 'bin')])
-
- # Tell cmake to look here for *.cmake files
- os.environ['CMAKE_PREFIX_PATH'] = install_dir
-
self.make_path = make_path
self.make_generator = make_generator
self.debug = OPTION_DEBUG
self.script_dir = script_dir
- self.pyside_package_dir = os.path.join(self.script_dir,
- pyside_package_dir_name)
+ self.st_build_dir = os.path.join(self.script_dir, self.build_lib)
self.sources_dir = sources_dir
self.build_dir = build_dir
self.install_dir = install_dir
@@ -709,14 +679,61 @@ class PysideBuild(_build):
self.site_packages_dir = get_python_lib(1, 0, prefix=install_dir)
self.build_tests = OPTION_BUILDTESTS
- setuptools_install_prefix = get_python_lib(1)
- if OPTION_FINAL_INSTALL_PREFIX:
- setuptools_install_prefix = OPTION_FINAL_INSTALL_PREFIX
-
# Save the shiboken build dir path for clang deployment
# purposes.
self.shiboken_build_dir = os.path.join(self.build_dir, "shiboken2")
+ self.log_pre_build_info()
+
+ # Prepare folders
+ if not os.path.exists(self.sources_dir):
+ log.info("Creating sources folder {}...".format(self.sources_dir))
+ os.makedirs(self.sources_dir)
+ if not os.path.exists(self.build_dir):
+ log.info("Creating build folder {}...".format(self.build_dir))
+ os.makedirs(self.build_dir)
+ if not os.path.exists(self.install_dir):
+ log.info("Creating install folder {}...".format(self.install_dir))
+ os.makedirs(self.install_dir)
+
+ if not (OPTION_ONLYPACKAGE
+ and not config.is_internal_shiboken_generator_build_and_part_of_top_level_all()):
+ # Build extensions
+ for ext in config.get_buildable_extensions():
+ self.build_extension(ext)
+
+ if OPTION_BUILDTESTS:
+ # we record the latest successful build and note the
+ # build directory for supporting the tests.
+ timestamp = time.strftime('%Y-%m-%d_%H%M%S')
+ build_history = os.path.join(setup_script_dir, 'build_history')
+ unique_dir = os.path.join(build_history, timestamp)
+ os.makedirs(unique_dir)
+ fpath = os.path.join(unique_dir, 'build_dir.txt')
+ with open(fpath, 'w') as f:
+ print(build_dir, file=f)
+ log.info("Created {}".format(build_history))
+
+ if not OPTION_SKIP_PACKAGING:
+ # Build patchelf if needed
+ self.build_patchelf()
+
+ # Prepare packages
+ self.prepare_packages()
+
+ # Build packages
+ _build.run(self)
+ else:
+ log.info("Skipped preparing and building packages.")
+ log.info('*** Build completed')
+
+ def log_pre_build_info(self):
+ if config.is_internal_shiboken_generator_build_and_part_of_top_level_all():
+ return
+
+ setuptools_install_prefix = get_python_lib(1)
+ if OPTION_FINAL_INSTALL_PREFIX:
+ setuptools_install_prefix = OPTION_FINAL_INSTALL_PREFIX
log.info("=" * 30)
log.info("Package version: {}".format(get_package_version()))
log.info("Build type: {}".format(self.build_type))
@@ -726,40 +743,34 @@ class PysideBuild(_build):
log.info("Make generator: {}".format(self.make_generator))
log.info("Make jobs: {}".format(OPTION_JOBS))
log.info("-" * 3)
-
log.info("setup.py directory: {}".format(self.script_dir))
log.info("Build scripts directory: {}".format(build_scripts_dir))
log.info("Sources directory: {}".format(self.sources_dir))
-
log.info(dedent("""
- Building PySide2 will create and touch directories
+ Building {st_package_name} will create and touch directories
in the following order:
make build directory (py*_build/*/*) ->
make install directory (py*_install/*/*) ->
- {} directory (pyside_package/*) ->
setuptools build directory (build/*/*) ->
setuptools install directory
(usually path-installed-python/lib/python*/site-packages/*)
- """).format(pyside_package_dir_name))
-
+ """).format(st_package_name=config.package_name()))
log.info("make build directory: {}".format(self.build_dir))
log.info("make install directory: {}".format(self.install_dir))
- log.info("{} directory: {}".format(pyside_package_dir_name,
- self.pyside_package_dir))
- log.info("setuptools build directory: {}".format(
- os.path.join(self.script_dir, "build")))
- log.info("setuptools install directory: {}".format(
- setuptools_install_prefix))
- log.info("make-installed site-packages directory: {} \n"
- " (only relevant for copying files from "
- "'make install directory' to '{} directory'".format(
- self.site_packages_dir, pyside_package_dir_name))
+ log.info("setuptools build directory: {}".format(self.st_build_dir))
+ log.info("setuptools install directory: {}".format(setuptools_install_prefix))
+ log.info(dedent("""
+ make-installed site-packages directory: {}
+ (only relevant for copying files from 'make install directory'
+ to 'setuptools build directory'
+ """).format(
+ self.site_packages_dir))
log.info("-" * 3)
log.info("Python executable: {}".format(self.py_executable))
log.info("Python includes: {}".format(self.py_include_dir))
log.info("Python library: {}".format(self.py_library))
- log.info("Python prefix: {}".format(py_prefix))
- log.info("Python scripts: {}".format(py_scripts_dir))
+ log.info("Python prefix: {}".format(self.py_prefix))
+ log.info("Python scripts: {}".format(self.py_scripts_dir))
log.info("-" * 3)
log.info("Qt qmake: {}".format(self.qtinfo.qmake_command))
log.info("Qt version: {}".format(self.qtinfo.version))
@@ -772,52 +783,11 @@ class PysideBuild(_build):
if sys.platform == 'darwin':
pyside_macos_deployment_target = (
PysideBuild.macos_pyside_min_deployment_target()
- )
+ )
log.info("MACOSX_DEPLOYMENT_TARGET set to: {}".format(
pyside_macos_deployment_target))
log.info("=" * 30)
- # Prepare folders
- if not os.path.exists(self.sources_dir):
- log.info("Creating sources folder {}...".format(self.sources_dir))
- os.makedirs(self.sources_dir)
- if not os.path.exists(self.build_dir):
- log.info("Creating build folder {}...".format(self.build_dir))
- os.makedirs(self.build_dir)
- if not os.path.exists(self.install_dir):
- log.info("Creating install folder {}...".format(self.install_dir))
- os.makedirs(self.install_dir)
-
- if not OPTION_ONLYPACKAGE:
- # Build extensions
- for ext in contained_modules:
- self.build_extension(ext)
-
- if OPTION_BUILDTESTS:
- # we record the latest successful build and note the
- # build directory for supporting the tests.
- timestamp = time.strftime('%Y-%m-%d_%H%M%S')
- build_history = os.path.join(setup_script_dir, 'build_history')
- unique_dir = os.path.join(build_history, timestamp)
- os.makedirs(unique_dir)
- fpath = os.path.join(unique_dir, 'build_dir.txt')
- with open(fpath, 'w') as f:
- print(build_dir, file=f)
- log.info("Created {}".format(build_history))
-
- if not OPTION_SKIP_PACKAGING:
- # Build patchelf if needed
- self.build_patchelf()
-
- # Prepare packages
- self.prepare_packages()
-
- # Build packages
- _build.run(self)
- else:
- log.info("Skipped preparing and building packages.")
- log.info('*** Build completed')
-
@staticmethod
def macos_qt_min_deployment_target():
target = qtinfo.macos_min_deployment_target
@@ -953,6 +923,17 @@ class PysideBuild(_build):
cmake_cmd.append("-DPYTHON_EXECUTABLE={}".format(self.py_executable))
cmake_cmd.append("-DPYTHON_INCLUDE_DIR={}".format(self.py_include_dir))
cmake_cmd.append("-DPYTHON_LIBRARY={}".format(self.py_library))
+
+ # If a custom shiboken cmake config directory path was provided, pass it to CMake.
+ if OPTION_SHIBOKEN_CONFIG_DIR and config.is_internal_pyside_build():
+ if os.path.exists(OPTION_SHIBOKEN_CONFIG_DIR):
+ log.info("Using custom provided shiboken2 installation: {}"
+ .format(OPTION_SHIBOKEN_CONFIG_DIR))
+ cmake_cmd.append("-DShiboken2_DIR={}".format(OPTION_SHIBOKEN_CONFIG_DIR))
+ else:
+ log.info("Custom provided shiboken2 installation not found. Path given: {}"
+ .format(OPTION_SHIBOKEN_CONFIG_DIR))
+
if OPTION_MODULE_SUBSET:
module_sub_set = ''
for m in OPTION_MODULE_SUBSET.split(','):
@@ -1014,20 +995,20 @@ class PysideBuild(_build):
cmake_cmd.append("-DPYSIDE_QT_CONF_PREFIX={}".format(
pyside_qt_conf_prefix))
- # Pass package version to CMake, so this string can be
- # embedded into _config.py file.
- package_version = get_package_version()
- cmake_cmd.append("-DPYSIDE_SETUP_PY_PACKAGE_VERSION={}".format(
- package_version))
-
- # In case if this is a snapshot build, also pass the
- # timestamp as a separate value, because it the only
- # version component that is actually generated by setup.py.
- timestamp = ''
- if OPTION_SNAPSHOT_BUILD:
- timestamp = get_package_timestamp()
- cmake_cmd.append("-DPYSIDE_SETUP_PY_PACKAGE_TIMESTAMP={}".format(
- timestamp))
+ # Pass package version to CMake, so this string can be
+ # embedded into _config.py file.
+ package_version = get_package_version()
+ cmake_cmd.append("-DPACKAGE_SETUP_PY_PACKAGE_VERSION={}".format(
+ package_version))
+
+ # In case if this is a snapshot build, also pass the
+ # timestamp as a separate value, because it is the only
+ # version component that is actually generated by setup.py.
+ timestamp = ''
+ if OPTION_SNAPSHOT_BUILD:
+ timestamp = get_package_timestamp()
+ cmake_cmd.append("-DPACKAGE_SETUP_PY_PACKAGE_TIMESTAMP={}".format(
+ timestamp))
if extension.lower() in ["shiboken2", "pyside2-tools"]:
cmake_cmd.append("-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=yes")
@@ -1129,15 +1110,24 @@ class PysideBuild(_build):
os.chdir(self.script_dir)
def prepare_packages(self):
+ """
+ This will copy all relevant files from the various locations in the "cmake install dir",
+ to the setup tools build dir (which is read from self.build_lib provided by distutils).
+
+ After that setuptools.command.build_py is smart enough to copy everything
+ from the build dir to the install dir (the virtualenv site-packages for example).
+ """
try:
- log.info("Preparing packages...")
+ log.info("\nPreparing setup tools build directory.\n")
vars = {
"site_packages_dir": self.site_packages_dir,
"sources_dir": self.sources_dir,
"install_dir": self.install_dir,
"build_dir": self.build_dir,
"script_dir": self.script_dir,
- "pyside_package_dir": self.pyside_package_dir,
+ "st_build_dir": self.st_build_dir,
+ "cmake_package_name": config.package_name(),
+ "st_package_name": config.package_name(),
"ssl_libs_dir": OPTION_OPENSSL,
"py_version": self.py_version,
"qt_version": self.qtinfo.version,
@@ -1151,6 +1141,12 @@ class PysideBuild(_build):
"qt_qml_dir": self.qtinfo.qml_dir,
"target_arch": self.py_arch,
}
+
+ # Needed for correct file installation in generator build
+ # case.
+ if config.is_internal_shiboken_generator_build():
+ vars['cmake_package_name'] = config.shiboken_module_option_name
+
os.chdir(self.script_dir)
if sys.platform == "win32":
@@ -1170,19 +1166,21 @@ class PysideBuild(_build):
def get_built_pyside_config(self, vars):
# Get config that contains list of built modules, and
# SOVERSIONs of the built libraries.
- pyside_package_dir = vars['pyside_package_dir']
- config_path = os.path.join(pyside_package_dir, "PySide2", "_config.py")
- config = get_python_dict(config_path)
- return config
+ st_build_dir = vars['st_build_dir']
+ config_path = os.path.join(st_build_dir, config.package_name(), "_config.py")
+ temp_config = get_python_dict(config_path)
+ if 'built_modules' not in temp_config:
+ temp_config['built_modules'] = []
+ return temp_config
def is_webengine_built(self, built_modules):
return ('WebEngineWidgets' in built_modules or 'WebEngineCore' in built_modules
or 'WebEngine' in built_modules)
- def prepare_standalone_clang(self, is_win = False):
+ def prepare_standalone_clang(self, is_win=False):
"""
- Copies the libclang library to the pyside package so that
- shiboken executable works.
+ Copies the libclang library to the shiboken2-generator
+ package so that the shiboken executable works.
"""
log.info('Finding path to the libclang shared library.')
cmake_cmd = [
@@ -1205,47 +1203,54 @@ class PysideBuild(_build):
if not clang_lib_path:
raise RuntimeError("Could not find the location of the libclang "
- "library inside the CMake cache file.")
+ "library inside the CMake cache file.")
- target_name = None
if is_win:
# clang_lib_path points to the static import library
# (lib/libclang.lib), whereas we want to copy the shared
# library (bin/libclang.dll).
- clang_lib_path = re.sub(r'lib/libclang.lib$', 'bin/libclang.dll',
- clang_lib_path)
+ clang_lib_path = re.sub(r'lib/libclang.lib$',
+ 'bin/libclang.dll',
+ clang_lib_path)
else:
- if sys.platform != 'darwin' and os.path.islink(clang_lib_path):
- # On Linux, we get "libclang.so" from CMake which is
- # a symlink:
- # libclang.so -> libclang.so.6 -> libclang.so.6.0.
- # shiboken2 links against libclang.so.6. So, we
- # determine the target name by resolving just
- # one symlink (note: os.path.realpath() resolves all).
- target_name = os.readlink(clang_lib_path)
- # We want to resolve any symlink on Linux and macOS, and
- # copy the actual file.
- clang_lib_path = os.path.realpath(clang_lib_path)
-
- if not target_name:
- target_name = os.path.basename(clang_lib_path)
-
- # Path to directory containing libclang.
- clang_lib_dir = os.path.dirname(clang_lib_path)
-
- # The destination will be the package folder near the other
- # extension modules.
- destination_dir = "{}/PySide2".format(os.path.join(self.script_dir,
- 'pyside_package'))
+ # shiboken2 links against libclang.so.6 or a similarly
+ # named library.
+ # If the linked against library is a symlink, resolve
+ # the symlink once (but not all the way to the real
+ # file) on Linux and macOS,
+ # so that we get the path to the "SO version" symlink
+ # (the one used as the install name in the shared library
+ # dependency section).
+ # E.g. On Linux libclang.so -> libclang.so.6 ->
+ # libclang.so.6.0.
+ # "libclang.so.6" is the name we want for the copied file.
+ if os.path.islink(clang_lib_path):
+ link_target = os.readlink(clang_lib_path)
+ if os.path.isabs(link_target):
+ clang_lib_path = link_target
+ else:
+ # link_target is relative, transform to absolute.
+ clang_lib_path = os.path.join(os.path.dirname(clang_lib_path), link_target)
+ clang_lib_path = os.path.abspath(clang_lib_path)
+
+ # The destination will be the shiboken package folder.
+ vars = {}
+ vars['st_build_dir'] = self.st_build_dir
+ vars['st_package_name'] = config.package_name()
+ destination_dir = "{st_build_dir}/{st_package_name}".format(**vars)
+
if os.path.exists(clang_lib_path):
- log.info('Copying libclang shared library {} to the package folder as {}.'.format(
- clang_lib_path, target_name))
basename = os.path.basename(clang_lib_path)
- destination_path = os.path.join(destination_dir, target_name)
+ log.info('Copying libclang shared library {} to the package folder as {}.'.format(
+ clang_lib_path, basename))
+ destination_path = os.path.join(destination_dir, basename)
# Need to modify permissions in case file is not writable
# (a reinstall would cause a permission denied error).
- copyfile(clang_lib_path, destination_path, make_writable_by_owner=True)
+ copyfile(clang_lib_path,
+ destination_path,
+ force_copy_symlink=True,
+ make_writable_by_owner=True)
else:
raise RuntimeError("Error copying libclang library "
"from {} to {}. ".format(
@@ -1265,18 +1270,17 @@ class PysideBuild(_build):
else:
# Add rpath values pointing to $ORIGIN and the
# installed qt lib directory.
- local_rpath = '$ORIGIN/'
- qt_lib_dir = self.qtinfo.libs_dir
+ final_rpath = self.qtinfo.libs_dir
if OPTION_STANDALONE:
- qt_lib_dir = "$ORIGIN/Qt/lib"
- final_rpath = local_rpath + ':' + qt_lib_dir
- cmd = [self._patchelf_path, '--set-rpath', final_rpath, srcpath]
- if run_process(cmd) != 0:
- raise RuntimeError("Error patching rpath in " + srcpath)
+ final_rpath = "$ORIGIN/Qt/lib"
+ override = OPTION_STANDALONE
+ linux_fix_rpaths_for_library(self._patchelf_path, srcpath, final_rpath,
+ override=override)
elif sys.platform == 'darwin':
pyside_libs = [lib for lib in os.listdir(
package_path) if filter_match(lib, ["*.so", "*.dylib"])]
+
def rpath_cmd(srcpath):
final_rpath = ''
# Command line rpath option takes precedence over
@@ -1308,15 +1312,6 @@ class PysideBuild(_build):
"updated rpath (OS/X) in {}.".format(srcpath))
-try:
- with open(os.path.join(setup_script_dir, 'README.rst')) as f:
- README = f.read()
- with open(os.path.join(setup_script_dir, 'CHANGES.rst')) as f:
- CHANGES = f.read()
-except IOError:
- README = CHANGES = ''
-
-
cmd_class_dict = {
'build': PysideBuild,
'build_py': PysideBuildPy,
diff --git a/build_scripts/options.py b/build_scripts/options.py
index fd8b0718e..daf3bb00e 100644
--- a/build_scripts/options.py
+++ b/build_scripts/options.py
@@ -38,16 +38,88 @@
#############################################################################
from __future__ import print_function
+import sys
+import os
+
+
+class Options(object):
+ def __init__(self):
+
+ # Dictionary containing values of all the possible options.
+ self.dict = {}
+
+ def has_option(self, name):
+ """ Returns True if argument '--name' was passed on the command
+ line. """
+ try:
+ sys.argv.remove("--{}".format(name))
+ self.dict[name] = True
+ return True
+ except ValueError:
+ pass
+ return False
+
+ def option_value(self, name, remove=True):
+ """
+ Returns the value of a command line option or environment
+ variable.
+
+ :param name: The name of the command line option or environment
+ variable.
+
+ :param remove: Whether the option and its value should be
+ removed from sys.argv. Useful when there's a need to query for
+ the value and also pass it along to setuptools for example.
+
+ :return: Either the option value or None.
+ """
+ for index, option in enumerate(sys.argv):
+ if option == '--' + name:
+ if index + 1 >= len(sys.argv):
+ raise RuntimeError("The option {} requires a value".format(option))
+ value = sys.argv[index + 1]
+
+ if remove:
+ sys.argv[index:index + 2] = []
+
+ self.dict[name] = value
+ return value
+
+ if option.startswith('--' + name + '='):
+ value = option[len(name) + 3:]
+
+ if remove:
+ sys.argv[index:index + 1] = []
+
+ self.dict[name] = value
+ return value
+
+ env_val = os.getenv(name.upper().replace('-', '_'))
+ self.dict[name] = env_val
+ return env_val
+
+
+options = Options()
+
+
+def has_option(name):
+ return options.has_option(name)
+
+
+def option_value(*args,**kwargs):
+ return options.option_value(*args,**kwargs)
-from .utils import has_option, option_value
# Declare options
+OPTION_BUILD_TYPE = option_value("build-type")
+OPTION_INTERNAL_BUILD_TYPE = option_value("internal-build-type")
OPTION_DEBUG = has_option("debug")
OPTION_RELWITHDEBINFO = has_option('relwithdebinfo')
OPTION_QMAKE = option_value("qmake")
OPTION_QT_VERSION = option_value("qt")
OPTION_CMAKE = option_value("cmake")
OPTION_OPENSSL = option_value("openssl")
+OPTION_SHIBOKEN_CONFIG_DIR = option_value("shiboken-config-dir")
OPTION_ONLYPACKAGE = has_option("only-package")
OPTION_STANDALONE = has_option("standalone")
OPTION_MAKESPEC = option_value("make-spec")
@@ -82,3 +154,7 @@ OPTION_SANITIZE_ADDRESS = has_option("sanitize-address")
OPTION_SNAPSHOT_BUILD = has_option("snapshot-build")
OPTION_LIMITED_API = option_value("limited-api")
OPTION_PACKAGE_TIMESTAMP = option_value("package-timestamp")
+
+# This is used automatically by distutils.command.install object, to
+# specify the final installation location.
+OPTION_FINAL_INSTALL_PREFIX = option_value("prefix", remove=False)
diff --git a/build_scripts/platforms/linux.py b/build_scripts/platforms/linux.py
index 4c38fef6c..067179cdc 100644
--- a/build_scripts/platforms/linux.py
+++ b/build_scripts/platforms/linux.py
@@ -37,76 +37,100 @@
##
#############################################################################
-from ..options import *
from ..utils import copydir, copyfile, copy_icu_libs, find_files_using_glob
+from ..config import config
-def prepare_standalone_package_linux(self, executables, vars):
+
+def prepare_standalone_package_linux(self, vars):
built_modules = vars['built_modules']
- # <qt>/lib/* -> <setup>/PySide2/Qt/lib
- destination_lib_dir = "{pyside_package_dir}/PySide2/Qt/lib"
+ constrain_modules = None
+ copy_plugins = True
+ copy_qml = True
+ copy_translations = True
+ copy_qt_conf = True
+ should_copy_icu_libs = True
+
+ if config.is_internal_shiboken_generator_build():
+ constrain_modules = ["Core", "Network", "Xml", "XmlPatterns"]
+ copy_plugins = False
+ copy_qml = False
+ copy_translations = False
+ copy_qt_conf = False
+ should_copy_icu_libs = False
+
+ # <qt>/lib/* -> <setup>/{st_package_name}/Qt/lib
+ destination_lib_dir = "{st_build_dir}/{st_package_name}/Qt/lib"
+
+ accepted_modules = ['libQt5*.so.?']
+ if constrain_modules:
+ accepted_modules = ["libQt5" + module + "*.so.?" for module in constrain_modules]
+ accepted_modules.append("libicu*.so.??")
+
copydir("{qt_lib_dir}", destination_lib_dir,
- filter=[
- "libQt5*.so.?",
- "libicu*.so.??",
- ],
- recursive=False, vars=vars, force_copy_symlinks=True)
-
- # Check if ICU libraries were copied over to the destination
- # Qt libdir.
- resolved_destination_lib_dir = destination_lib_dir.format(**vars)
- maybe_icu_libs = find_files_using_glob(resolved_destination_lib_dir,
- "libicu*")
-
- # If no ICU libraries are present in the Qt libdir (like when
- # Qt is built against system ICU, or in the Coin CI where ICU
- # libs are in a different directory) try to find out / resolve
- # which ICU libs are used by QtCore (if used at all) using a
- # custom written ldd, and copy the ICU libs to the Pyside Qt
- # dir if necessary. We choose the QtCore lib to inspect, by
- # checking which QtCore library the shiboken2 executable uses.
- if not maybe_icu_libs:
- copy_icu_libs(self._patchelf_path, resolved_destination_lib_dir)
+ filter=accepted_modules,
+ recursive=False, vars=vars, force_copy_symlinks=True)
+
+ if should_copy_icu_libs:
+ # Check if ICU libraries were copied over to the destination
+ # Qt libdir.
+ resolved_destination_lib_dir = destination_lib_dir.format(**vars)
+ maybe_icu_libs = find_files_using_glob(resolved_destination_lib_dir,
+ "libicu*")
+
+ # If no ICU libraries are present in the Qt libdir (like when
+ # Qt is built against system ICU, or in the Coin CI where ICU
+ # libs are in a different directory) try to find out / resolve
+ # which ICU libs are used by QtCore (if used at all) using a
+ # custom written ldd, and copy the ICU libs to the Pyside Qt
+ # dir if necessary. We choose the QtCore lib to inspect, by
+ # checking which QtCore library the shiboken2 executable uses.
+ if not maybe_icu_libs:
+ copy_icu_libs(self._patchelf_path, resolved_destination_lib_dir)
if self.is_webengine_built(built_modules):
copydir("{qt_lib_execs_dir}",
- "{pyside_package_dir}/PySide2/Qt/libexec",
+ "{st_build_dir}/{st_package_name}/Qt/libexec",
filter=None,
recursive=False,
vars=vars)
copydir("{qt_prefix_dir}/resources",
- "{pyside_package_dir}/PySide2/Qt/resources",
+ "{st_build_dir}/{st_package_name}/Qt/resources",
filter=None,
recursive=False,
vars=vars)
- # <qt>/plugins/* -> <setup>/PySide2/Qt/plugins
- copydir("{qt_plugins_dir}",
- "{pyside_package_dir}/PySide2/Qt/plugins",
- filter=["*.so"],
- recursive=True,
- vars=vars)
-
- # <qt>/qml/* -> <setup>/PySide2/Qt/qml
- copydir("{qt_qml_dir}",
- "{pyside_package_dir}/PySide2/Qt/qml",
- filter=None,
- force=False,
- recursive=True,
- ignore=["*.so.debug"],
- vars=vars)
-
- # <qt>/translations/* -> <setup>/PySide2/Qt/translations
-
- copydir("{qt_translations_dir}",
- "{pyside_package_dir}/PySide2/Qt/translations",
- filter=["*.qm", "*.pak"],
- force=False,
- vars=vars)
-
- # Copy the qt.conf file to libexec.
- copyfile(
- "{build_dir}/pyside2/PySide2/qt.conf",
- "{pyside_package_dir}/PySide2/Qt/libexec",
- vars=vars)
+ if copy_plugins:
+ # <qt>/plugins/* -> <setup>/{st_package_name}/Qt/plugins
+ copydir("{qt_plugins_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/plugins",
+ filter=["*.so"],
+ recursive=True,
+ vars=vars)
+
+ if copy_qml:
+ # <qt>/qml/* -> <setup>/{st_package_name}/Qt/qml
+ copydir("{qt_qml_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/qml",
+ filter=None,
+ force=False,
+ recursive=True,
+ ignore=["*.so.debug"],
+ vars=vars)
+
+ if copy_translations:
+ # <qt>/translations/* ->
+ # <setup>/{st_package_name}/Qt/translations
+ copydir("{qt_translations_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/translations",
+ filter=["*.qm", "*.pak"],
+ force=False,
+ vars=vars)
+
+ if copy_qt_conf:
+ # Copy the qt.conf file to libexec.
+ copyfile(
+ "{build_dir}/pyside2/{st_package_name}/qt.conf",
+ "{st_build_dir}/{st_package_name}/Qt/libexec",
+ vars=vars)
diff --git a/build_scripts/platforms/macos.py b/build_scripts/platforms/macos.py
index 936f4ca90..49f02754d 100644
--- a/build_scripts/platforms/macos.py
+++ b/build_scripts/platforms/macos.py
@@ -37,12 +37,29 @@
##
#############################################################################
-import fnmatch, os
+import fnmatch
+import os
from ..utils import copydir, copyfile, macos_fix_rpaths_for_library
+from ..config import config
-def prepare_standalone_package_macos(self, executables, vars):
+
+def prepare_standalone_package_macos(self, vars):
built_modules = vars['built_modules']
+ constrain_modules = None
+ copy_plugins = True
+ copy_qml = True
+ copy_translations = True
+ copy_qt_conf = True
+
+ if config.is_internal_shiboken_generator_build():
+ constrain_modules = ["Core", "Network", "Xml", "XmlPatterns"]
+ constrain_frameworks = ['Qt' + name + '.framework' for name in constrain_modules]
+ copy_plugins = False
+ copy_qml = False
+ copy_translations = False
+ copy_qt_conf = False
+
# Directory filter for skipping unnecessary files.
def general_dir_filter(dir_name, parent_full_path, dir_full_path):
if fnmatch.fnmatch(dir_name, "*.dSYM"):
@@ -52,6 +69,7 @@ def prepare_standalone_package_macos(self, executables, vars):
# Filter out debug plugins and qml plugins in the
# debug_and_release config.
no_copy_debug = True
+
def file_variant_filter(file_name, file_full_path):
if self.qtinfo.build_type != 'debug_and_release':
return True
@@ -59,17 +77,16 @@ def prepare_standalone_package_macos(self, executables, vars):
return False
return True
- # <qt>/lib/* -> <setup>/PySide2/Qt/lib
+ # <qt>/lib/* -> <setup>/{st_package_name}/Qt/lib
if self.qt_is_framework_build():
- framework_built_modules = [
- 'Qt' + name + '.framework' for name in built_modules]
-
- def framework_dir_filter(dir_name, parent_full_path,
- dir_full_path):
+ def framework_dir_filter(dir_name, parent_full_path, dir_full_path):
if '.framework' in dir_name:
- if dir_name.startswith('QtWebEngine') and not \
- self.is_webengine_built(built_modules):
+ if (dir_name.startswith('QtWebEngine') and
+ not self.is_webengine_built(built_modules)):
+ return False
+ if constrain_modules and dir_name not in constrain_frameworks:
return False
+
if dir_name in ['Headers', 'fonts']:
return False
if dir_full_path.endswith('Versions/Current'):
@@ -84,6 +101,7 @@ def prepare_standalone_package_macos(self, executables, vars):
# Filter out debug frameworks in the
# debug_and_release config.
no_copy_debug = True
+
def framework_variant_filter(file_name, file_full_path):
if self.qtinfo.build_type != 'debug_and_release':
return True
@@ -93,7 +111,7 @@ def prepare_standalone_package_macos(self, executables, vars):
return False
return True
- copydir("{qt_lib_dir}", "{pyside_package_dir}/PySide2/Qt/lib",
+ copydir("{qt_lib_dir}", "{st_build_dir}/{st_package_name}/Qt/lib",
recursive=True, vars=vars,
ignore=["*.la", "*.a", "*.cmake", "*.pc", "*.prl"],
dir_filter_function=framework_dir_filter,
@@ -104,7 +122,7 @@ def prepare_standalone_package_macos(self, executables, vars):
# from Versions/5/Helpers, thus adding two more levels of
# directory hierarchy.
if self.is_webengine_built(built_modules):
- qt_lib_path = "{pyside_package_dir}/PySide2/Qt/lib".format(
+ qt_lib_path = "{st_build_dir}/{st_package_name}/Qt/lib".format(
**vars)
bundle = "QtWebEngineCore.framework/Helpers/"
bundle += "QtWebEngineProcess.app"
@@ -120,9 +138,11 @@ def prepare_standalone_package_macos(self, executables, vars):
if 'WebKit' not in built_modules:
ignored_modules.extend(['libQt5WebKit*.dylib'])
accepted_modules = ['libQt5*.5.dylib']
+ if constrain_modules:
+ accepted_modules = ["libQt5" + module + "*.5.dylib" for module in constrain_modules]
copydir("{qt_lib_dir}",
- "{pyside_package_dir}/PySide2/Qt/lib",
+ "{st_build_dir}/{st_package_name}/Qt/lib",
filter=accepted_modules,
ignore=ignored_modules,
file_filter_function=file_variant_filter,
@@ -130,53 +150,58 @@ def prepare_standalone_package_macos(self, executables, vars):
if self.is_webengine_built(built_modules):
copydir("{qt_lib_execs_dir}",
- "{pyside_package_dir}/PySide2/Qt/libexec",
+ "{st_build_dir}/{st_package_name}/Qt/libexec",
filter=None,
recursive=False,
vars=vars)
copydir("{qt_prefix_dir}/resources",
- "{pyside_package_dir}/PySide2/Qt/resources",
+ "{st_build_dir}/{st_package_name}/Qt/resources",
filter=None,
recursive=False,
vars=vars)
# Fix rpath for WebEngine process executable.
- pyside_package_dir = vars['pyside_package_dir']
- qt_libexec_path = "{}/PySide2/Qt/libexec".format(pyside_package_dir)
+ qt_libexec_path = "{st_build_dir}/{st_package_name}/Qt/libexec".format(**vars)
binary = "QtWebEngineProcess"
final_path = os.path.join(qt_libexec_path, binary)
rpath = "@loader_path/../lib"
macos_fix_rpaths_for_library(final_path, rpath)
- # Copy the qt.conf file to libexec.
- copyfile(
- "{build_dir}/pyside2/PySide2/qt.conf",
- "{pyside_package_dir}/PySide2/Qt/libexec",
- vars=vars)
+ if copy_qt_conf:
+ # Copy the qt.conf file to libexec.
+ copyfile(
+ "{build_dir}/pyside2/{st_package_name}/qt.conf",
+ "{st_build_dir}/{st_package_name}/Qt/libexec",
+ vars=vars)
+
+ if copy_plugins:
+ # <qt>/plugins/* -> <setup>/{st_package_name}/Qt/plugins
+ copydir("{qt_plugins_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/plugins",
+ filter=["*.dylib"],
+ recursive=True,
+ dir_filter_function=general_dir_filter,
+ file_filter_function=file_variant_filter,
+ vars=vars)
+
- # <qt>/plugins/* -> <setup>/PySide2/Qt/plugins
- copydir("{qt_plugins_dir}",
- "{pyside_package_dir}/PySide2/Qt/plugins",
- filter=["*.dylib"],
- recursive=True,
- dir_filter_function=general_dir_filter,
- file_filter_function=file_variant_filter,
- vars=vars)
-
- # <qt>/qml/* -> <setup>/PySide2/Qt/qml
- copydir("{qt_qml_dir}",
- "{pyside_package_dir}/PySide2/Qt/qml",
- filter=None,
- recursive=True,
- force=False,
- dir_filter_function=general_dir_filter,
- file_filter_function=file_variant_filter,
- vars=vars)
-
- # <qt>/translations/* -> <setup>/PySide2/Qt/translations
- copydir("{qt_translations_dir}",
- "{pyside_package_dir}/PySide2/Qt/translations",
- filter=["*.qm", "*.pak"],
- force=False,
- vars=vars)
+ if copy_qml:
+ # <qt>/qml/* -> <setup>/{st_package_name}/Qt/qml
+ copydir("{qt_qml_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/qml",
+ filter=None,
+ recursive=True,
+ force=False,
+ dir_filter_function=general_dir_filter,
+ file_filter_function=file_variant_filter,
+ vars=vars)
+
+ if copy_translations:
+ # <qt>/translations/* ->
+ # <setup>/{st_package_name}/Qt/translations
+ copydir("{qt_translations_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/translations",
+ filter=["*.qm", "*.pak"],
+ force=False,
+ vars=vars)
diff --git a/build_scripts/platforms/unix.py b/build_scripts/platforms/unix.py
index c93bbbbbe..7dce11612 100644
--- a/build_scripts/platforms/unix.py
+++ b/build_scripts/platforms/unix.py
@@ -37,69 +37,31 @@
##
#############################################################################
-import os, re, sys
+import os
+import sys
from .linux import prepare_standalone_package_linux
from .macos import prepare_standalone_package_macos
+
+from ..config import config
from ..options import *
from ..utils import copydir, copyfile, rmtree, makefile
from ..utils import regenerate_qt_resources
+
def prepare_packages_posix(self, vars):
executables = []
- # <build>/shiboken2/doc/html/* ->
- # <setup>/PySide2/docs/shiboken2
- copydir(
- "{build_dir}/shiboken2/doc/html",
- "{pyside_package_dir}/PySide2/docs/shiboken2",
- force=False, vars=vars)
- # <install>/lib/site-packages/PySide2/* -> <setup>/PySide2
- copydir(
- "{site_packages_dir}/PySide2",
- "{pyside_package_dir}/PySide2",
- vars=vars)
- # <install>/lib/site-packages/shiboken2.so ->
- # <setup>/PySide2/shiboken2.so
- shiboken_module_name = 'shiboken2.so'
- shiboken_src_path = "{site_packages_dir}".format(**vars)
- maybe_shiboken_names = [f for f in os.listdir(shiboken_src_path)
- if re.match(r'shiboken.*\.so', f)]
- if maybe_shiboken_names:
- shiboken_module_name = maybe_shiboken_names[0]
- vars.update({'shiboken_module_name': shiboken_module_name})
- copyfile(
- "{site_packages_dir}/{shiboken_module_name}",
- "{pyside_package_dir}/PySide2/{shiboken_module_name}",
- vars=vars)
- # <install>/lib/site-packages/pyside2uic/* ->
- # <setup>/pyside2uic
+
+ # <install>/lib/site-packages/{st_package_name}/* ->
+ # <setup>/{st_package_name}
+ # This copies the module .so/.dylib files and various .py files
+ # (__init__, config, git version, etc.)
copydir(
- "{site_packages_dir}/pyside2uic",
- "{pyside_package_dir}/pyside2uic",
- force=False, vars=vars)
- if sys.version_info[0] > 2:
- rmtree("{pyside_package_dir}/pyside2uic/port_v2".format(**vars))
- else:
- rmtree("{pyside_package_dir}/pyside2uic/port_v3".format(**vars))
- # <install>/bin/pyside2-uic -> PySide2/scripts/uic.py
- makefile(
- "{pyside_package_dir}/PySide2/scripts/__init__.py",
+ "{site_packages_dir}/{st_package_name}",
+ "{st_build_dir}/{st_package_name}",
vars=vars)
- copyfile(
- "{install_dir}/bin/pyside2-uic",
- "{pyside_package_dir}/PySide2/scripts/uic.py",
- force=False, vars=vars)
- # <install>/bin/* -> PySide2/
- executables.extend(copydir(
- "{install_dir}/bin/",
- "{pyside_package_dir}/PySide2",
- filter=[
- "pyside2-lupdate",
- "pyside2-rcc",
- "shiboken2",
- ],
- recursive=False, vars=vars))
- # <install>/lib/lib* -> PySide2/
- config = self.get_built_pyside_config(vars)
+
+ generated_config = self.get_built_pyside_config(vars)
+
def adjusted_lib_name(name, version):
postfix = ''
if sys.platform.startswith('linux'):
@@ -107,61 +69,144 @@ def prepare_packages_posix(self, vars):
elif sys.platform == 'darwin':
postfix = '.' + version + '.dylib'
return name + postfix
- copydir(
- "{install_dir}/lib/",
- "{pyside_package_dir}/PySide2",
- filter=[
- adjusted_lib_name("libpyside*",
- config['pyside_library_soversion']),
- adjusted_lib_name("libshiboken*",
- config['shiboken_library_soversion']),
- ],
- recursive=False, vars=vars, force_copy_symlinks=True)
- # <install>/share/PySide2/typesystems/* ->
- # <setup>/PySide2/typesystems
- copydir(
- "{install_dir}/share/PySide2/typesystems",
- "{pyside_package_dir}/PySide2/typesystems",
- vars=vars)
- # <install>/include/* -> <setup>/PySide2/include
- copydir(
- "{install_dir}/include",
- "{pyside_package_dir}/PySide2/include",
- vars=vars)
- # <source>/pyside2/PySide2/support/* ->
- # <setup>/PySide2/support/*
- copydir(
- "{build_dir}/pyside2/PySide2/support",
- "{pyside_package_dir}/PySide2/support",
- vars=vars)
- if not OPTION_NOEXAMPLES:
- # examples/* -> <setup>/PySide2/examples
- copydir(os.path.join(self.script_dir, "examples"),
- "{pyside_package_dir}/PySide2/examples",
- force=False, vars=vars)
- # Re-generate examples Qt resource files for Python 3
- # compatibility
- if sys.version_info[0] == 3:
- examples_path = "{pyside_package_dir}/PySide2/examples".format(
- **vars)
- pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
- **vars)
- pyside_rcc_options = '-py3'
- regenerate_qt_resources(examples_path, pyside_rcc_path,
- pyside_rcc_options)
+
+ if config.is_internal_shiboken_module_build():
+ # <build>/shiboken2/doc/html/* ->
+ # <setup>/{st_package_name}/docs/shiboken2
+ copydir(
+ "{build_dir}/shiboken2/doc/html",
+ "{st_build_dir}/{st_package_name}/docs/shiboken2",
+ force=False, vars=vars)
+
+ # <install>/lib/lib* -> {st_package_name}/
+ copydir(
+ "{install_dir}/lib/",
+ "{st_build_dir}/{st_package_name}",
+ filter=[
+ adjusted_lib_name("libshiboken*",
+ generated_config['shiboken_library_soversion']),
+ ],
+ recursive=False, vars=vars, force_copy_symlinks=True)
+
+ if config.is_internal_shiboken_generator_build():
+ # <install>/bin/* -> {st_package_name}/
+ executables.extend(copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=[
+ "shiboken2",
+ ],
+ recursive=False, vars=vars))
+
+ # Used to create scripts directory.
+ makefile(
+ "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py",
+ vars=vars)
+
+ # For setting up setuptools entry points.
+ copyfile(
+ "{install_dir}/bin/shiboken_tool.py",
+ "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py",
+ force=False, vars=vars)
+
+ if config.is_internal_shiboken_generator_build() or config.is_internal_pyside_build():
+ # <install>/include/* -> <setup>/{st_package_name}/include
+ copydir(
+ "{install_dir}/include/{cmake_package_name}",
+ "{st_build_dir}/{st_package_name}/include",
+ vars=vars)
+
+ if config.is_internal_pyside_build():
+ # <install>/lib/site-packages/pyside2uic/* ->
+ # <setup>/pyside2uic
+ copydir(
+ "{site_packages_dir}/pyside2uic",
+ "{st_build_dir}/pyside2uic",
+ force=False, vars=vars)
+ if sys.version_info[0] > 2:
+ rmtree("{st_build_dir}/pyside2uic/port_v2".format(**vars))
+ else:
+ rmtree("{st_build_dir}/pyside2uic/port_v3".format(**vars))
+
+ # <install>/bin/pyside2-uic -> {st_package_name}/scripts/uic.py
+ makefile(
+ "{st_build_dir}/{st_package_name}/scripts/__init__.py",
+ vars=vars)
+ copyfile(
+ "{install_dir}/bin/pyside2-uic",
+ "{st_build_dir}/{st_package_name}/scripts/uic.py",
+ force=False, vars=vars)
+
+ # For setting up setuptools entry points
+ copyfile(
+ "{install_dir}/bin/pyside_tool.py",
+ "{st_build_dir}/{st_package_name}/scripts/pyside_tool.py",
+ force=False, vars=vars)
+
+ # <install>/bin/* -> {st_package_name}/
+ executables.extend(copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=[
+ "pyside2-lupdate",
+ "pyside2-rcc",
+ ],
+ recursive=False, vars=vars))
+
+ # <install>/lib/lib* -> {st_package_name}/
+ copydir(
+ "{install_dir}/lib/",
+ "{st_build_dir}/{st_package_name}",
+ filter=[
+ adjusted_lib_name("libpyside*",
+ generated_config['pyside_library_soversion']),
+ ],
+ recursive=False, vars=vars, force_copy_symlinks=True)
+
+ # <install>/share/{st_package_name}/typesystems/* ->
+ # <setup>/{st_package_name}/typesystems
+ copydir(
+ "{install_dir}/share/{st_package_name}/typesystems",
+ "{st_build_dir}/{st_package_name}/typesystems",
+ vars=vars)
+
+ # <source>/pyside2/{st_package_name}/support/* ->
+ # <setup>/{st_package_name}/support/*
+ copydir(
+ "{build_dir}/pyside2/{st_package_name}/support",
+ "{st_build_dir}/{st_package_name}/support",
+ vars=vars)
+
+ if not OPTION_NOEXAMPLES:
+ # examples/* -> <setup>/{st_package_name}/examples
+ copydir(os.path.join(self.script_dir, "examples"),
+ "{st_build_dir}/{st_package_name}/examples",
+ force=False, vars=vars)
+ # Re-generate examples Qt resource files for Python 3
+ # compatibility
+ if sys.version_info[0] == 3:
+ examples_path = "{st_build_dir}/{st_package_name}/examples".format(
+ **vars)
+ pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
+ **vars)
+ pyside_rcc_options = '-py3'
+ regenerate_qt_resources(examples_path, pyside_rcc_path,
+ pyside_rcc_options)
+
# Copy Qt libs to package
if OPTION_STANDALONE:
- vars['built_modules'] = config['built_modules']
- if sys.platform == 'darwin':
- prepare_standalone_package_macos(self, executables, vars)
- else:
- prepare_standalone_package_linux(self, executables, vars)
+ if config.is_internal_pyside_build() or config.is_internal_shiboken_generator_build():
+ vars['built_modules'] = generated_config['built_modules']
+ if sys.platform == 'darwin':
+ prepare_standalone_package_macos(self, vars)
+ else:
+ prepare_standalone_package_linux(self, vars)
- # Copy over clang before rpath patching.
- self.prepare_standalone_clang(is_win=False)
+ if config.is_internal_shiboken_generator_build():
+ # Copy over clang before rpath patching.
+ self.prepare_standalone_clang(is_win=False)
# Update rpath to $ORIGIN
- if (sys.platform.startswith('linux') or
- sys.platform.startswith('darwin')):
- self.update_rpath("{pyside_package_dir}/PySide2".format(**vars),
- executables)
+ if sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
+ rpath_path = "{st_build_dir}/{st_package_name}".format(**vars)
+ self.update_rpath(rpath_path, executables)
diff --git a/build_scripts/platforms/windows_desktop.py b/build_scripts/platforms/windows_desktop.py
index 3bf386a17..6307238a1 100644
--- a/build_scripts/platforms/windows_desktop.py
+++ b/build_scripts/platforms/windows_desktop.py
@@ -38,147 +38,225 @@
#############################################################################
import functools
-import os, re, sys
+import os
+import sys
+
+from ..config import config
from ..options import *
from ..utils import copydir, copyfile, rmtree, makefile
from ..utils import regenerate_qt_resources, filter_match
from ..utils import download_and_extract_7z
+
def prepare_packages_win32(self, vars):
# For now, debug symbols will not be shipped into the package.
copy_pdbs = False
pdbs = []
if (self.debug or self.build_type == 'RelWithDebInfo') and copy_pdbs:
pdbs = ['*.pdb']
- # <install>/lib/site-packages/PySide2/* -> <setup>/PySide2
+
+ # <install>/lib/site-packages/{st_package_name}/* ->
+ # <setup>/{st_package_name}
+ # This copies the module .pyd files and various .py files
+ # (__init__, config, git version, etc.)
copydir(
- "{site_packages_dir}/PySide2",
- "{pyside_package_dir}/PySide2",
+ "{site_packages_dir}/{st_package_name}",
+ "{st_build_dir}/{st_package_name}",
vars=vars)
- built_modules = self.get_built_pyside_config(vars)['built_modules']
- # <build>/pyside2/PySide2/*.pdb -> <setup>/PySide2
- copydir(
- "{build_dir}/pyside2/PySide2",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
+ if config.is_internal_shiboken_module_build():
+ # <build>/shiboken2/doc/html/* ->
+ # <setup>/{st_package_name}/docs/shiboken2
+ copydir(
+ "{build_dir}/shiboken2/doc/html",
+ "{st_build_dir}/{st_package_name}/docs/shiboken2",
+ force=False, vars=vars)
+
+ # <install>/bin/*.dll -> {st_package_name}/
+ copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["shiboken*.dll"],
+ recursive=False, vars=vars)
- # <build>/shiboken2/doc/html/* ->
- # <setup>/PySide2/docs/shiboken2
- copydir(
- "{build_dir}/shiboken2/doc/html",
- "{pyside_package_dir}/PySide2/docs/shiboken2",
- force=False, vars=vars)
-
- # <install>/lib/site-packages/shiboken2.pyd ->
- # <setup>/PySide2/shiboken2.pyd
- shiboken_module_name = 'shiboken2.pyd'
- shiboken_src_path = "{site_packages_dir}".format(**vars)
- maybe_shiboken_names = [f for f in os.listdir(shiboken_src_path)
- if re.match(r'shiboken.*\.pyd', f)]
- if maybe_shiboken_names:
- shiboken_module_name = maybe_shiboken_names[0]
- vars.update({'shiboken_module_name': shiboken_module_name})
- copyfile(
- "{site_packages_dir}/{shiboken_module_name}",
- "{pyside_package_dir}/PySide2/{shiboken_module_name}",
- vars=vars)
- # @TODO: Fix this .pdb file not to overwrite release
- # {shibokengenerator}.pdb file.
- # Task-number: PYSIDE-615
- copydir(
- "{build_dir}/shiboken2/shibokenmodule",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
+ # <install>/lib/*.lib -> {st_package_name}/
+ copydir(
+ "{install_dir}/lib/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["shiboken*.lib"],
+ recursive=False, vars=vars)
- # <install>/lib/site-packages/pyside2uic/* ->
- # <setup>/pyside2uic
- copydir(
- "{site_packages_dir}/pyside2uic",
- "{pyside_package_dir}/pyside2uic",
- force=False, vars=vars)
- if sys.version_info[0] > 2:
- rmtree("{pyside_package_dir}/pyside2uic/port_v2".format(**vars))
- else:
- rmtree("{pyside_package_dir}/pyside2uic/port_v3".format(**vars))
+ # @TODO: Fix this .pdb file not to overwrite release
+ # {shibokengenerator}.pdb file.
+ # Task-number: PYSIDE-615
+ copydir(
+ "{build_dir}/shiboken2/shibokenmodule",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
- # <install>/bin/pyside2-uic -> PySide2/scripts/uic.py
- makefile(
- "{pyside_package_dir}/PySide2/scripts/__init__.py",
- vars=vars)
- copyfile(
- "{install_dir}/bin/pyside2-uic",
- "{pyside_package_dir}/PySide2/scripts/uic.py",
- force=False, vars=vars)
+ # pdb files for libshiboken and libpyside
+ copydir(
+ "{build_dir}/shiboken2/libshiboken",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
- # <install>/bin/*.exe,*.dll,*.pdb -> PySide2/
- copydir(
- "{install_dir}/bin/",
- "{pyside_package_dir}/PySide2",
- filter=["*.exe", "*.dll"],
- recursive=False, vars=vars)
- # @TODO: Fix this .pdb file not to overwrite release
- # {shibokenmodule}.pdb file.
- # Task-number: PYSIDE-615
- copydir(
- "{build_dir}/shiboken2/generator",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
+ if config.is_internal_shiboken_generator_build():
+ # <install>/bin/*.dll -> {st_package_name}/
+ copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["shiboken*.exe"],
+ recursive=False, vars=vars)
- # <install>/lib/*.lib -> PySide2/
- copydir(
- "{install_dir}/lib/",
- "{pyside_package_dir}/PySide2",
- filter=["*.lib"],
- recursive=False, vars=vars)
+ # Used to create scripts directory.
+ makefile(
+ "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py",
+ vars=vars)
- # <install>/share/PySide2/typesystems/* ->
- # <setup>/PySide2/typesystems
- copydir(
- "{install_dir}/share/PySide2/typesystems",
- "{pyside_package_dir}/PySide2/typesystems",
- vars=vars)
+ # For setting up setuptools entry points.
+ copyfile(
+ "{install_dir}/bin/shiboken_tool.py",
+ "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py",
+ force=False, vars=vars)
+
+ # @TODO: Fix this .pdb file not to overwrite release
+ # {shibokenmodule}.pdb file.
+ # Task-number: PYSIDE-615
+ copydir(
+ "{build_dir}/shiboken2/generator",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
- # <install>/include/* -> <setup>/PySide2/include
- copydir(
- "{install_dir}/include",
- "{pyside_package_dir}/PySide2/include",
- vars=vars)
+ if config.is_internal_shiboken_generator_build() or config.is_internal_pyside_build():
+ # <install>/include/* -> <setup>/{st_package_name}/include
+ copydir(
+ "{install_dir}/include/{cmake_package_name}",
+ "{st_build_dir}/{st_package_name}/include",
+ vars=vars)
- # <source>/pyside2/PySide2/support/* ->
- # <setup>/PySide2/support/*
- copydir(
- "{build_dir}/pyside2/PySide2/support",
- "{pyside_package_dir}/PySide2/support",
- vars=vars)
+ if config.is_internal_pyside_build():
+ # <build>/pyside2/{st_package_name}/*.pdb ->
+ # <setup>/{st_package_name}
+ copydir(
+ "{build_dir}/pyside2/{st_package_name}",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
+
+ # <install>/lib/site-packages/pyside2uic/* ->
+ # <setup>/pyside2uic
+ copydir(
+ "{site_packages_dir}/pyside2uic",
+ "{st_build_dir}/pyside2uic",
+ force=False, vars=vars)
+ if sys.version_info[0] > 2:
+ rmtree("{st_build_dir}/pyside2uic/port_v2".format(**vars))
+ else:
+ rmtree("{st_build_dir}/pyside2uic/port_v3".format(**vars))
+
+ # <install>/bin/pyside2-uic -> {st_package_name}/scripts/uic.py
+ makefile(
+ "{st_build_dir}/{st_package_name}/scripts/__init__.py",
+ vars=vars)
+ copyfile(
+ "{install_dir}/bin/pyside2-uic",
+ "{st_build_dir}/{st_package_name}/scripts/uic.py",
+ force=False, vars=vars)
+
+ # For setting up setuptools entry points
+ copyfile(
+ "{install_dir}/bin/pyside_tool.py",
+ "{st_build_dir}/{st_package_name}/scripts/pyside_tool.py",
+ force=False, vars=vars)
+
+ # <install>/bin/*.exe,*.dll -> {st_package_name}/
+ copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["pyside*.exe", "pyside*.dll"],
+ recursive=False, vars=vars)
- if not OPTION_NOEXAMPLES:
- # examples/* -> <setup>/PySide2/examples
- copydir(os.path.join(self.script_dir, "examples"),
- "{pyside_package_dir}/PySide2/examples",
+ # <install>/lib/*.lib -> {st_package_name}/
+ copydir(
+ "{install_dir}/lib/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["pyside*.lib"],
+ recursive=False, vars=vars)
+
+ # <install>/share/{st_package_name}/typesystems/* ->
+ # <setup>/{st_package_name}/typesystems
+ copydir(
+ "{install_dir}/share/{st_package_name}/typesystems",
+ "{st_build_dir}/{st_package_name}/typesystems",
+ vars=vars)
+
+ # <source>/pyside2/{st_package_name}/support/* ->
+ # <setup>/{st_package_name}/support/*
+ copydir(
+ "{build_dir}/pyside2/{st_package_name}/support",
+ "{st_build_dir}/{st_package_name}/support",
+ vars=vars)
+
+ copydir(
+ "{build_dir}/pyside2/libpyside",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
+
+ if not OPTION_NOEXAMPLES:
+ # examples/* -> <setup>/{st_package_name}/examples
+ copydir(os.path.join(self.script_dir, "examples"),
+ "{st_build_dir}/{st_package_name}/examples",
+ force=False, vars=vars)
+ # Re-generate examples Qt resource files for Python 3
+ # compatibility
+ if sys.version_info[0] == 3:
+ examples_path = "{st_build_dir}/{st_package_name}/examples".format(
+ **vars)
+ pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
+ **vars)
+ pyside_rcc_options = '-py3'
+ regenerate_qt_resources(examples_path, pyside_rcc_path,
+ pyside_rcc_options)
+
+ if vars['ssl_libs_dir']:
+ # <ssl_libs>/* -> <setup>/{st_package_name}/openssl
+ copydir("{ssl_libs_dir}", "{st_build_dir}/{st_package_name}/openssl",
+ filter=[
+ "libeay32.dll",
+ "ssleay32.dll"],
force=False, vars=vars)
- # Re-generate examples Qt resource files for Python 3
- # compatibility
- if sys.version_info[0] == 3:
- examples_path = "{pyside_package_dir}/PySide2/examples".format(
- **vars)
- pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
- **vars)
- pyside_rcc_options = '-py3'
- regenerate_qt_resources(examples_path, pyside_rcc_path,
- pyside_rcc_options)
-
- # <ssl_libs>/* -> <setup>/PySide2/openssl
- copydir("{ssl_libs_dir}", "{pyside_package_dir}/PySide2/openssl",
- filter=[
- "libeay32.dll",
- "ssleay32.dll"],
- force=False, vars=vars)
-
- # <qt>/bin/*.dll and Qt *.exe -> <setup>/PySide2
+
+ if config.is_internal_pyside_build() or config.is_internal_shiboken_generator_build():
+ copy_qt_artifacts(self, copy_pdbs, vars)
+
+
+def copy_qt_artifacts(self, copy_pdbs, vars):
+ built_modules = self.get_built_pyside_config(vars)['built_modules']
+
+ constrain_modules = None
+ copy_plugins = True
+ copy_qml = True
+ copy_translations = True
+ copy_qt_conf = True
+ copy_qt_permanent_artifacts = True
+ copy_msvc_redist = False
+ copy_clang = False
+
+ if config.is_internal_shiboken_generator_build():
+ constrain_modules = ["Core", "Network", "Xml", "XmlPatterns"]
+ copy_plugins = False
+ copy_qml = False
+ copy_translations = False
+ copy_qt_conf = False
+ copy_qt_permanent_artifacts = False
+ copy_msvc_redist = True
+ copy_clang = True
+
+ # <qt>/bin/*.dll and Qt *.exe -> <setup>/{st_package_name}
qt_artifacts_permanent = [
"opengl*.dll",
"d3d*.dll",
@@ -189,6 +267,7 @@ def prepare_packages_win32(self, vars):
"lconvert.exe",
"qtdiag.exe"
]
+
# MSVC redistributable
msvc_redist = [
"concrt140.dll",
@@ -212,8 +291,14 @@ def prepare_packages_win32(self, vars):
else:
egl_suffix = ''
qt_artifacts_egl = [a.format(egl_suffix) for a in qt_artifacts_egl]
- qt_artifacts_permanent += qt_artifacts_egl
- qt_artifacts_permanent += msvc_redist
+
+ artifacts = []
+ if copy_qt_permanent_artifacts:
+ artifacts += qt_artifacts_permanent
+ artifacts += qt_artifacts_egl
+
+ if copy_msvc_redist:
+ artifacts += msvc_redist
# Extract Qt dependency dll's when building on Qt CI
# There is no proper CI env variable, so using agent launch params
@@ -225,15 +310,22 @@ def prepare_packages_win32(self, vars):
zip_file = "pyside_qt_deps_32.7z"
download_and_extract_7z(redist_url + zip_file, "{qt_bin_dir}".format(**vars))
- copydir("{qt_bin_dir}", "{pyside_package_dir}/PySide2",
- filter=qt_artifacts_permanent,
- recursive=False, vars=vars)
+ if artifacts:
+ copydir("{qt_bin_dir}",
+ "{st_build_dir}/{st_package_name}",
+ filter=artifacts, recursive=False, vars=vars)
- # <qt>/bin/*.dll and Qt *.pdbs -> <setup>/PySide2 part two
+ # <qt>/bin/*.dll and Qt *.pdbs -> <setup>/{st_package_name} part two
# File filter to copy only debug or only release files.
- qt_dll_patterns = ["Qt5*{}.dll", "lib*{}.dll"]
- if copy_pdbs:
- qt_dll_patterns += ["Qt5*{}.pdb", "lib*{}.pdb"]
+ if constrain_modules:
+ qt_dll_patterns = ["Qt5" + x + "{}.dll" for x in constrain_modules]
+ if copy_pdbs:
+ qt_dll_patterns += ["Qt5" + x + "{}.pdb" for x in constrain_modules]
+ else:
+ qt_dll_patterns = ["Qt5*{}.dll", "lib*{}.dll"]
+ if copy_pdbs:
+ qt_dll_patterns += ["Qt5*{}.pdb", "lib*{}.pdb"]
+
def qt_build_config_filter(patterns, file_name, file_full_path):
release = [a.format('') for a in patterns]
debug = [a.format('d') for a in patterns]
@@ -283,56 +375,60 @@ def prepare_packages_win32(self, vars):
return False
qt_dll_filter = functools.partial(qt_build_config_filter,
- qt_dll_patterns)
- copydir("{qt_bin_dir}", "{pyside_package_dir}/PySide2",
- file_filter_function=qt_dll_filter,
- recursive=False, vars=vars)
-
- # <qt>/plugins/* -> <setup>/PySide2/plugins
- plugin_dll_patterns = ["*{}.dll"]
- pdb_pattern = "*{}.pdb"
- if copy_pdbs:
- plugin_dll_patterns += [pdb_pattern]
- plugin_dll_filter = functools.partial(qt_build_config_filter,
- plugin_dll_patterns)
- copydir("{qt_plugins_dir}", "{pyside_package_dir}/PySide2/plugins",
- file_filter_function=plugin_dll_filter,
- vars=vars)
+ qt_dll_patterns)
+ copydir("{qt_bin_dir}",
+ "{st_build_dir}/{st_package_name}",
+ file_filter_function=qt_dll_filter,
+ recursive=False, vars=vars)
- # <qt>/translations/* -> <setup>/PySide2/translations
- copydir("{qt_translations_dir}",
- "{pyside_package_dir}/PySide2/translations",
- filter=["*.qm", "*.pak"],
- force=False,
- vars=vars)
+ if copy_plugins:
+ # <qt>/plugins/* -> <setup>/{st_package_name}/plugins
+ plugin_dll_patterns = ["*{}.dll"]
+ pdb_pattern = "*{}.pdb"
+ if copy_pdbs:
+ plugin_dll_patterns += [pdb_pattern]
+ plugin_dll_filter = functools.partial(qt_build_config_filter,
+ plugin_dll_patterns)
+ copydir("{qt_plugins_dir}", "{st_build_dir}/{st_package_name}/plugins",
+ file_filter_function=plugin_dll_filter,
+ vars=vars)
- # <qt>/qml/* -> <setup>/PySide2/qml
- qml_dll_patterns = ["*{}.dll"]
- qml_ignore_patterns = qml_dll_patterns + [pdb_pattern]
- qml_ignore = [a.format('') for a in qml_ignore_patterns]
+ if copy_translations:
+ # <qt>/translations/* -> <setup>/{st_package_name}/translations
+ copydir("{qt_translations_dir}",
+ "{st_build_dir}/{st_package_name}/translations",
+ filter=["*.qm", "*.pak"],
+ force=False,
+ vars=vars)
- # Copy all files that are not dlls and pdbs (.qml, qmldir).
- copydir("{qt_qml_dir}", "{pyside_package_dir}/PySide2/qml",
- ignore=qml_ignore,
- force=False,
- recursive=True,
- vars=vars)
+ if copy_qml:
+ # <qt>/qml/* -> <setup>/{st_package_name}/qml
+ qml_dll_patterns = ["*{}.dll"]
+ qml_ignore_patterns = qml_dll_patterns + [pdb_pattern]
+ qml_ignore = [a.format('') for a in qml_ignore_patterns]
+
+ # Copy all files that are not dlls and pdbs (.qml, qmldir).
+ copydir("{qt_qml_dir}", "{st_build_dir}/{st_package_name}/qml",
+ ignore=qml_ignore,
+ force=False,
+ recursive=True,
+ vars=vars)
- if copy_pdbs:
- qml_dll_patterns += [pdb_pattern]
- qml_dll_filter = functools.partial(qt_build_config_filter,
- qml_dll_patterns)
+ if copy_pdbs:
+ qml_dll_patterns += [pdb_pattern]
+ qml_dll_filter = functools.partial(qt_build_config_filter,
+ qml_dll_patterns)
- # Copy all dlls (and possibly pdbs).
- copydir("{qt_qml_dir}", "{pyside_package_dir}/PySide2/qml",
- file_filter_function=qml_dll_filter,
- force=False,
- recursive=True,
- vars=vars)
+ # Copy all dlls (and possibly pdbs).
+ copydir("{qt_qml_dir}", "{st_build_dir}/{st_package_name}/qml",
+ file_filter_function=qml_dll_filter,
+ force=False,
+ recursive=True,
+ vars=vars)
if self.is_webengine_built(built_modules):
copydir("{qt_prefix_dir}/resources",
- "{pyside_package_dir}/PySide2/resources",
+ "{st_build_dir}/{st_package_name}/resources",
filter=None,
recursive=False,
vars=vars)
@@ -340,26 +436,16 @@ def prepare_packages_win32(self, vars):
filter = 'QtWebEngineProcess{}.exe'.format(
'd' if self.debug else '')
copydir("{qt_bin_dir}",
- "{pyside_package_dir}/PySide2",
+ "{st_build_dir}/{st_package_name}",
filter=[filter],
recursive=False, vars=vars)
- # Copy the qt.conf file to prefix dir.
- copyfile(
- "{build_dir}/pyside2/PySide2/qt.conf",
- "{pyside_package_dir}/PySide2",
- vars=vars)
-
- self.prepare_standalone_clang(is_win=True)
+ if copy_qt_conf:
+ # Copy the qt.conf file to prefix dir.
+ copyfile(
+ "{build_dir}/pyside2/{st_package_name}/qt.conf",
+ "{st_build_dir}/{st_package_name}",
+ vars=vars)
- # pdb files for libshiboken and libpyside
- copydir(
- "{build_dir}/shiboken2/libshiboken",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
- copydir(
- "{build_dir}/pyside2/libpyside",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
+ if copy_clang:
+ self.prepare_standalone_clang(is_win=True)
diff --git a/build_scripts/setup_runner.py b/build_scripts/setup_runner.py
new file mode 100644
index 000000000..709b4b25c
--- /dev/null
+++ b/build_scripts/setup_runner.py
@@ -0,0 +1,165 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import sys, os, textwrap
+
+from build_scripts.config import config
+from build_scripts.main import get_package_version, get_setuptools_extension_modules
+from build_scripts.main import cmd_class_dict
+from build_scripts.options import OPTION_BUILD_TYPE, OPTION_INTERNAL_BUILD_TYPE
+from build_scripts.utils import run_process
+
+from setuptools import setup
+
+
+class SetupRunner(object):
+ def __init__(self, orig_argv):
+ self.invocations_list = []
+
+ # Keep the original args around in case we ever need to pass
+ # modified arguments to the sub invocations.
+ self.orig_argv = orig_argv
+ self.sub_argv = list(orig_argv)
+
+ self.setup_script_dir = os.getcwd()
+
+ @staticmethod
+ def cmd_line_argument_is_in_args(argument, args):
+ """ Check if command line argument was passed in args. """
+ return any(arg for arg in list(args) if "--" + argument in arg)
+
+ @staticmethod
+ def remove_cmd_line_argument_in_args(argument, args):
+ """ Remove command line argument from args. """
+ return [arg for arg in list(args) if "--" + argument not in arg]
+
+ @staticmethod
+ def construct_cmd_line_argument(name, value=None):
+ """ Constructs a command line argument given name and value. """
+ if not value:
+ return "--{}".format(name)
+ return "--{}={}".format(name, value)
+
+ @staticmethod
+ def construct_internal_build_type_cmd_line_argument(internal_build_type):
+ return SetupRunner.construct_cmd_line_argument("internal-build-type", internal_build_type)
+
+ def add_setup_internal_invocation(self, build_type, reuse_build=False):
+ """ Enqueues a script sub-invocation to be executed later. """
+ internal_build_type_arg = self.construct_internal_build_type_cmd_line_argument(build_type)
+ setup_cmd = [sys.executable] + self.sub_argv + [internal_build_type_arg]
+
+ # Add --reuse-build option if requested and not already present.
+ if reuse_build and not self.cmd_line_argument_is_in_args("reuse-build", self.sub_argv):
+ setup_cmd.append(self.construct_cmd_line_argument("reuse-build"))
+ self.invocations_list.append(setup_cmd)
+
+ def run_setup(self):
+ """
+ Decide what kind of build is requested and then execute it.
+ In the top-level invocation case, the script
+ will spawn setup.py again (possibly multiple times).
+ In the internal invocation case, the script
+ will run setuptools.setup().
+ """
+
+ # Prepare initial config.
+ config.init_config(build_type=OPTION_BUILD_TYPE,
+ internal_build_type=OPTION_INTERNAL_BUILD_TYPE,
+ cmd_class_dict=cmd_class_dict,
+ package_version=get_package_version(),
+ ext_modules=get_setuptools_extension_modules(),
+ setup_script_dir=self.setup_script_dir)
+
+ # This is an internal invocation of setup.py, so start actual
+ # build.
+ if config.is_internal_invocation():
+ if config.internal_build_type not in config.get_allowed_internal_build_values():
+ raise RuntimeError("Invalid '{}' option given to --internal-build-type. "
+ .format(config.internal_build_type))
+ self.run_setuptools_setup()
+ return
+
+ # This is a top-level invocation of setup.py, so figure out what
+ # modules we will build and depending on that, call setup.py
+ # multiple times with different arguments.
+ if config.build_type not in config.get_allowed_top_level_build_values():
+ raise RuntimeError("Invalid '{}' option given to --build-type. "
+ .format(config.build_type))
+
+ # Build everything: shiboken2, shiboken2-generator and PySide2.
+ if config.is_top_level_build_all():
+ self.add_setup_internal_invocation(config.shiboken_module_option_name)
+
+ # Reuse the shiboken build for the generator package instead
+ # of rebuilding it again.
+ self.add_setup_internal_invocation(config.shiboken_generator_option_name,
+ reuse_build=True)
+
+ self.add_setup_internal_invocation(config.pyside_option_name)
+
+ elif config.is_top_level_build_shiboken_module():
+ self.add_setup_internal_invocation(config.shiboken_module_option_name)
+
+ elif config.is_top_level_build_shiboken_generator():
+ self.add_setup_internal_invocation(config.shiboken_generator_option_name)
+
+ elif config.is_top_level_build_pyside():
+ self.add_setup_internal_invocation(config.pyside_option_name)
+
+ for cmd in self.invocations_list:
+ cmd_as_string = " ".join(cmd)
+ print("\nRunning process: {}\n".format(cmd_as_string))
+ exit_code = run_process(cmd, redirect_stderr_to_stdout=False)
+ if exit_code != 0:
+ msg = textwrap.dedent("""
+ setup.py invocation failed with exit code: {}.\n\n
+ setup.py invocation was: {}
+ """).format(exit_code, cmd_as_string)
+ raise RuntimeError(msg)
+
+ @staticmethod
+ def run_setuptools_setup():
+ """
+ Runs setuptools.setup() once in a single setup.py
+ sub-invocation.
+ """
+
+ kwargs = config.setup_kwargs
+ setup(**kwargs)
diff --git a/build_scripts/utils.py b/build_scripts/utils.py
index 4c23a6279..5c5f4927d 100644
--- a/build_scripts/utils.py
+++ b/build_scripts/utils.py
@@ -39,17 +39,13 @@
import sys
import os
-import stat
import re
import stat
import errno
-import time
import shutil
import subprocess
import fnmatch
-import glob
import itertools
-import popenasync
import glob
# There is no urllib.request in Python2
@@ -58,11 +54,9 @@ try:
except ImportError:
import urllib
-from distutils import log
+import distutils.log as log
from distutils.errors import DistutilsOptionError
from distutils.errors import DistutilsSetupError
-from distutils.spawn import spawn
-from distutils.spawn import DistutilsExecError
try:
WindowsError
@@ -70,32 +64,6 @@ except NameError:
WindowsError = None
-def has_option(name):
- try:
- sys.argv.remove("--{}".format(name))
- return True
- except ValueError:
- pass
- return False
-
-
-def option_value(name):
- for index, option in enumerate(sys.argv):
- if option == '--' + name:
- if index+1 >= len(sys.argv):
- raise DistutilsOptionError("The option {} requires a "
- "value".format(option))
- value = sys.argv[index+1]
- sys.argv[index:index+2] = []
- return value
- if option.startswith('--' + name + '='):
- value = option[len(name)+3:]
- sys.argv[index:index+1] = []
- return value
- env_val = os.getenv(name.upper().replace('-', '_'))
- return env_val
-
-
def filter_match(name, patterns):
for pattern in patterns:
if pattern is None:
@@ -182,7 +150,6 @@ def find_vcdir(version):
"""
from distutils.msvc9compiler import VS_BASE
from distutils.msvc9compiler import Reg
- from distutils import log
vsbase = VS_BASE % version
try:
productdir = Reg.get_value(r"{}\Setup\VC".format(vsbase), "productdir")
@@ -416,13 +383,15 @@ def rmtree(dirname, ignore=False):
os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
func(path)
else:
- raise
+ raise IOError
shutil.rmtree(dirname, ignore_errors=ignore, onerror=handle_remove_readonly)
def run_process_output(args, initial_env=None):
if initial_env is None:
initial_env = os.environ
- std_out = subprocess.Popen(args, env = initial_env, universal_newlines = 1,
+ std_out = subprocess.Popen(args,
+ env = initial_env,
+ universal_newlines = 1,
stdout=subprocess.PIPE).stdout
result = []
for raw_line in std_out.readlines():
@@ -430,54 +399,27 @@ def run_process_output(args, initial_env=None):
result.append(line.rstrip())
return result
-def run_process(args, initial_env=None):
- def _log(buffer, check_new_line=False):
- ends_with_new_line = False
- if buffer.endswith('\n'):
- ends_with_new_line = True
- if check_new_line and buffer.find('\n') == -1:
- return buffer
- lines = buffer.splitlines()
- buffer = ''
- if check_new_line and not ends_with_new_line:
- buffer = lines[-1]
- lines = lines[:-1]
- for line in lines:
- log.info(line.rstrip('\r'))
- return buffer
- _log("Running process in {0}: {1}".format(os.getcwd(),
- " ".join([(" " in x and '"{0}"'.format(x) or x) for x in args])))
-
- if sys.platform != "win32":
- try:
- spawn(args)
- return 0
- except DistutilsExecError:
- return -1
-
- shell = False
- if sys.platform == "win32":
- shell = True
+def run_process(args, initial_env=None, redirect_stderr_to_stdout=True):
+ """
+ Run process until completion and return the process exit code.
+ Prints both stdout and stderr to the console.
+ No output is captured.
+ """
+ log.info("Running process in directory {0}: command {1}".format(
+ os.getcwd(),
+ " ".join([(" " in x and '"{0}"'.format(x) or x) for x in args]))
+ )
if initial_env is None:
initial_env = os.environ
- proc = popenasync.Popen(args,
- stdin = subprocess.PIPE,
- stdout = subprocess.PIPE,
- stderr = subprocess.STDOUT,
- universal_newlines = 1,
- shell = shell,
- env = initial_env)
-
- log_buffer = None;
- while proc.poll() is None:
- log_buffer = _log(proc.read_async(wait=0.1, e=0))
- if log_buffer:
- _log(log_buffer)
+ kwargs = {}
+ kwargs['env'] = initial_env
+ if redirect_stderr_to_stdout:
+ kwargs['stderr'] = subprocess.STDOUT
- proc.wait()
- return proc.returncode
+ exit_code = subprocess.call(args, **kwargs)
+ return exit_code
def get_environment_from_batch_command(env_cmd, initial=None):
@@ -607,8 +549,7 @@ def back_tick(cmd, ret_err=False):
return out, err.strip(), retcode
-MACOS_OUTNAME_RE = re.compile(r'\(compatibility version [\d.]+, current version '
- '[\d.]+\)')
+MACOS_OUTNAME_RE = re.compile(r'\(compatibility version [\d.]+, current version [\d.]+\)')
def macos_get_install_names(libpath):
"""
@@ -665,6 +606,9 @@ def macos_get_rpaths(libpath):
ctr += 3
return rpaths
+def macos_add_rpath(rpath, library_path):
+ back_tick('install_name_tool -add_rpath {rpath} {library_path}'.format(
+ rpath=rpath, library_path=library_path))
def macos_fix_rpaths_for_library(library_path, qt_lib_dir):
""" Adds required rpath load commands to given library.
@@ -703,8 +647,7 @@ def macos_fix_rpaths_for_library(library_path, qt_lib_dir):
break
if needs_loader_path and "@loader_path" not in existing_rpath_commands:
- back_tick('install_name_tool -add_rpath {rpath} {library_path}'.format(
- rpath="@loader_path", library_path=library_path))
+ macos_add_rpath("@loader_path", library_path)
# If the library depends on a Qt library, add an rpath load comment
# pointing to the Qt lib directory.
@@ -738,8 +681,7 @@ def macos_add_qt_rpath(library_path, qt_lib_dir,
break
if needs_qt_rpath:
- back_tick('install_name_tool -add_rpath {rpath} {library_path}'.format(
- rpath=qt_lib_dir, library_path=library_path))
+ macos_add_rpath(qt_lib_dir, library_path)
# Find an executable specified by a glob pattern ('foo*') in the OS path
def find_glob_in_path(pattern):
@@ -754,7 +696,7 @@ def find_glob_in_path(pattern):
# Locate the most recent version of llvm_config in the path.
def find_llvm_config():
- version_re = re.compile('(\d+)\.(\d+)\.(\d+)')
+ version_re = re.compile(r'(\d+)\.(\d+)\.(\d+)')
result = None
last_version_string = '000000'
for llvm_config in find_glob_in_path('llvm-config*'):
@@ -996,6 +938,17 @@ def copy_icu_libs(patchelf, destination_lib_dir):
new_rpaths_string = ":".join(rpaths)
linux_set_rpaths(patchelf, qt_core_library_path, new_rpaths_string)
+
+def linux_run_read_elf(executable_path):
+ cmd = "readelf -d {}".format(executable_path)
+ (out, err, code) = back_tick(cmd, True)
+ if code != 0:
+ raise RuntimeError("Running `readelf -d {}` failed with error "
+ "output:\n {}. ".format(executable_path, err))
+ lines = split_and_strip(out)
+ return lines
+
+
def linux_set_rpaths(patchelf, executable_path, rpath_string):
""" Patches the `executable_path` with a new rpath string. """
@@ -1005,18 +958,32 @@ def linux_set_rpaths(patchelf, executable_path, rpath_string):
raise RuntimeError("Error patching rpath in {}".format(
executable_path))
+
+def linux_get_dependent_libraries(executable_path):
+ """
+ Returns a list of libraries that executable_path depends on.
+ """
+
+ lines = linux_run_read_elf(executable_path)
+ pattern = re.compile(r"^.+?\(NEEDED\).+?\[(.+?)\]$")
+
+ library_lines = []
+ for line in lines:
+ match = pattern.search(line)
+ if match:
+ library_line = match.group(1)
+ library_lines.append(library_line)
+
+ return library_lines
+
+
def linux_get_rpaths(executable_path):
"""
Returns a list of run path values embedded in the executable or just
an empty list.
"""
- cmd = "readelf -d {}".format(executable_path)
- (out, err, code) = back_tick(cmd, True)
- if code != 0:
- raise RuntimeError("Running `readelf -d {}` failed with error "
- "output:\n {}. ".format(executable_path, err))
- lines = split_and_strip(out)
+ lines = linux_run_read_elf(executable_path)
pattern = re.compile(r"^.+?\(RUNPATH\).+?\[(.+?)\]$")
rpath_line = None
@@ -1033,6 +1000,7 @@ def linux_get_rpaths(executable_path):
return rpaths
+
def rpaths_has_origin(rpaths):
"""
Return True if the specified list of rpaths has an "$ORIGIN" value
@@ -1048,6 +1016,39 @@ def rpaths_has_origin(rpaths):
return True
return False
+
+def linux_needs_qt_rpath(executable_path):
+ """
+ Returns true if library_path depends on Qt libraries.
+ """
+
+ dependencies = linux_get_dependent_libraries(executable_path)
+
+ # Check if any library dependencies are Qt libraries (hacky).
+ needs_qt_rpath = False
+ for dep in dependencies:
+ if 'Qt' in dep:
+ needs_qt_rpath = True
+ break
+ return needs_qt_rpath
+
+
+def linux_fix_rpaths_for_library(patchelf, executable_path, qt_rpath, override=False):
+ """
+ Adds or overrides required rpaths in given executable / library.
+ """
+ rpaths = ['$ORIGIN/']
+ existing_rpaths = []
+ if not override:
+ existing_rpaths = linux_get_rpaths(executable_path)
+ rpaths.extend(existing_rpaths)
+
+ if linux_needs_qt_rpath(executable_path) and qt_rpath not in existing_rpaths:
+ rpaths.append(qt_rpath)
+
+ rpaths_string = ':'.join(rpaths)
+ linux_set_rpaths(patchelf, executable_path, rpaths_string)
+
def memoize(function):
"""
Decorator to wrap a function with a memoizing callable.
@@ -1076,9 +1077,27 @@ def get_python_dict(python_script_path):
"file: {}.".format(python_script_path))
raise
-def install_pip_dependencies(env_pip, packages):
+def install_pip_wheel_package(env_pip):
+ # Need to install an unreleased wheel version, due to a bug that
+ # will generate a wheel which will not be installable.
+ # See https://github.com/pypa/wheel/issues/263
+ wheel_url = "git+https://github.com/pypa/wheel.git@fbf3e3ada64d36ca7bb9c1422f5a1ccdba7e4dcf"
+ install_pip_package_from_url_specifier(env_pip, wheel_url)
+
+def install_pip_package_from_url_specifier(env_pip, url, upgrade=True):
+ args = [env_pip, "install", url]
+ if upgrade:
+ args.append("--upgrade")
+ args.append(url)
+ run_instruction(args, "Failed to install {}".format(url))
+
+def install_pip_dependencies(env_pip, packages, upgrade=True):
for p in packages:
- run_instruction([env_pip, "install", p], "Failed to install " + p)
+ args = [env_pip, "install"]
+ if upgrade:
+ args.append("--upgrade")
+ args.append(p)
+ run_instruction(args, "Failed to install " + p)
def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch):
_pExe = "python"
@@ -1105,16 +1124,18 @@ def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch):
_pExe = "python3"
return(_pExe, _env, env_pip, env_python)
-def run_instruction(instruction, error):
+def run_instruction(instruction, error, initial_env=None):
+ if initial_env is None:
+ initial_env = os.environ
print("Running Coin instruction: " + ' '.join(str(e) for e in instruction))
- result = subprocess.call(instruction)
+ result = subprocess.call(instruction, env=initial_env)
if result != 0:
print("ERROR : " + error)
exit(result)
def acceptCITestConfiguration(hostOS, hostOSVer, targetArch, compiler):
# Disable unsupported CI configs for now
- # NOTE: String must match with QT CI's storagesturct thrift
+ # NOTE: String must match with QT CI's storagestruct thrift
if hostOSVer in ["WinRT_10"]:
print("Disabled " + hostOSVer + " from Coin configuration")
return False
@@ -1124,3 +1145,13 @@ def acceptCITestConfiguration(hostOS, hostOSVer, targetArch, compiler):
print("Disabled " + compiler + " to " + targetArch + " from Coin configuration")
return False
return True
+
+
+def get_ci_qmake_path(ci_install_dir, ci_host_os):
+ qmake_path = "--qmake={}".format(ci_install_dir)
+ if ci_host_os == "MacOS":
+ return qmake_path + "/bin/qmake"
+ elif ci_host_os == "Windows":
+ return qmake_path + "\\bin\\qmake.exe"
+ else:
+ return qmake_path + "/bin/qmake"
diff --git a/coin_build_instructions.py b/coin_build_instructions.py
index aee0bf265..75f9feb66 100644
--- a/coin_build_instructions.py
+++ b/coin_build_instructions.py
@@ -36,14 +36,16 @@
## $QT_END_LICENSE$
##
#############################################################################
-from build_scripts.utils import has_option
-from build_scripts.utils import option_value
+from build_scripts.options import has_option
+from build_scripts.options import option_value
from build_scripts.utils import install_pip_dependencies
+from build_scripts.utils import install_pip_wheel_package
from build_scripts.utils import get_qtci_virtualEnv
from build_scripts.utils import run_instruction
from build_scripts.utils import rmtree
from build_scripts.utils import get_python_dict
from build_scripts.utils import acceptCITestConfiguration
+from build_scripts.utils import get_ci_qmake_path
import os
# Values must match COIN thrift
@@ -98,19 +100,17 @@ def call_setup(python_ver):
_pExe, _env, env_pip, env_python = get_qtci_virtualEnv(python_ver, CI_HOST_OS, CI_HOST_ARCH, CI_TARGET_ARCH)
rmtree(_env, True)
run_instruction(["virtualenv", "-p", _pExe, _env], "Failed to create virtualenv")
- install_pip_dependencies(env_pip, ["six", "wheel"])
- cmd = [env_python, "setup.py"]
+
+ install_pip_dependencies(env_pip, ["six", "setuptools"])
+ install_pip_wheel_package(env_pip)
+
+ cmd = [env_python, "-u", "setup.py"]
if CI_RELEASE_CONF:
cmd += ["bdist_wheel", "--standalone"]
else:
cmd += ["build"]
- if CI_HOST_OS == "MacOS":
- cmd += ["--qmake=" + CI_ENV_INSTALL_DIR + "/bin/qmake"]
- elif CI_HOST_OS == "Windows":
-
- cmd += ["--qmake=" + CI_ENV_INSTALL_DIR + "\\bin\\qmake.exe"]
- else:
- cmd += ["--qmake=" + CI_ENV_INSTALL_DIR + "/bin/qmake"]
+ qmake_path = get_ci_qmake_path(CI_ENV_INSTALL_DIR, CI_HOST_OS)
+ cmd.append(qmake_path)
cmd += ["--build-tests",
"--jobs=4",
"--verbose-build"]
@@ -121,7 +121,23 @@ def call_setup(python_ver):
cmd += ["--package-timestamp=" + CI_INTEGRATION_ID]
- run_instruction(cmd, "Failed to run setup.py")
+ env = os.environ
+ if CI_HOST_OS == "MacOS":
+ # On Python 3, setuptools.dist.handle_display_options does some
+ # weird sys.stdout.detach-ing if the stdout encoding is
+ # different from utf-8. This causes issues when running
+ # subprocess.call() because that access the original stdout
+ # object stored in sys.__stdout__ which was detached, and
+ # results in an exception being thrown.
+ # The Coin macOS locale by default is US-ASCII, and that
+ # triggers the above issue. Set the encoding to UTF-8 which
+ # makes sure to skip over the detach-ing code.
+ # Relevant links to the issue:
+ # https://bugs.python.org/issue15216
+ # https://bitbucket.org/tarek/distribute/issues/334/fix-for-311-breaks-packages-that-use
+ # https://github.com/pypa/virtualenv/issues/359
+ env['LC_CTYPE'] = 'UTF-8'
+ run_instruction(cmd, "Failed to run setup.py", initial_env=env)
def run_build_instructions():
if not acceptCITestConfiguration(CI_HOST_OS, CI_HOST_OS_VER, CI_TARGET_ARCH, CI_COMPILER):
diff --git a/coin_test_instructions.py b/coin_test_instructions.py
index bd65b5b7e..4121bb558 100644
--- a/coin_test_instructions.py
+++ b/coin_test_instructions.py
@@ -36,13 +36,15 @@
## $QT_END_LICENSE$
##
#############################################################################
-from build_scripts.utils import has_option
-from build_scripts.utils import option_value
+from build_scripts.options import has_option
+from build_scripts.options import option_value
from build_scripts.utils import install_pip_dependencies
+from build_scripts.utils import install_pip_wheel_package
from build_scripts.utils import get_qtci_virtualEnv
from build_scripts.utils import run_instruction
from build_scripts.utils import rmtree
from build_scripts.utils import acceptCITestConfiguration
+from build_scripts.utils import get_ci_qmake_path
import os
# Values must match COIN thrift
@@ -66,12 +68,21 @@ def call_testrunner(python_ver, buildnro):
_pExe, _env, env_pip, env_python = get_qtci_virtualEnv(python_ver, CI_HOST_OS, CI_HOST_ARCH, CI_TARGET_ARCH)
rmtree(_env, True)
run_instruction(["virtualenv", "-p", _pExe, _env], "Failed to create virtualenv")
- install_pip_dependencies(env_pip, ["six", "wheel"])
+ install_pip_dependencies(env_pip, ["six", "setuptools"])
+ install_pip_wheel_package(env_pip)
cmd = [env_python, "testrunner.py", "test",
"--blacklist", "build_history/blacklist.txt",
"--buildno=" + buildnro]
run_instruction(cmd, "Failed to run testrunner.py")
+ qmake_path = get_ci_qmake_path(CI_ENV_INSTALL_DIR, CI_HOST_OS)
+
+ # Try to install built wheels, and build some buildable examples.
+ if CI_RELEASE_CONF:
+ wheel_tester_path = os.path.join("testing", "wheel_tester.py")
+ cmd = [env_python, wheel_tester_path, qmake_path]
+ run_instruction(cmd, "Error while running wheel_tester.py")
+
def run_test_instructions():
if not acceptCITestConfiguration(CI_HOST_OS, CI_HOST_OS_VER, CI_TARGET_ARCH, CI_COMPILER):
exit()
diff --git a/examples/samplebinding/CMakeLists.txt b/examples/samplebinding/CMakeLists.txt
index 03ab85754..3852ed36f 100644
--- a/examples/samplebinding/CMakeLists.txt
+++ b/examples/samplebinding/CMakeLists.txt
@@ -40,7 +40,11 @@ set(generated_sources
# ================================== Shiboken detection ======================================
-
+# Use provided python interpreter if given.
+if(NOT python_interpreter)
+ find_program(python_interpreter "python")
+endif()
+message(STATUS "Using python interpreter: ${python_interpreter}")
# Macro to get various pyside / python include / link flags and paths.
# Uses the not entirely supported utils/pyside2_config.py file.
@@ -52,7 +56,8 @@ macro(pyside2_config option output_var)
endif()
execute_process(
- COMMAND python "${CMAKE_SOURCE_DIR}/../utils/pyside2_config.py" ${option}
+ COMMAND ${python_interpreter} "${CMAKE_SOURCE_DIR}/../utils/pyside2_config.py"
+ ${option}
OUTPUT_VARIABLE ${output_var}
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -64,14 +69,15 @@ macro(pyside2_config option output_var)
endif()
endmacro()
-# Query for the shiboken path, Python path, include paths and linker flags.
-pyside2_config(--pyside2 pyside2_path)
-pyside2_config(--python-include python_include_dir)
-pyside2_config(--shiboken-include shiboken_include_dir 1)
-pyside2_config(--shiboken-shared-libraries-cmake shiboken_shared_libraries 0)
-pyside2_config(--python-link-cmake python_linking_data 0)
+# Query for the shiboken generator path, Python path, include paths and linker flags.
+pyside2_config(--shiboken2-module-path shiboken2_module_path)
+pyside2_config(--shiboken2-generator-path shiboken2_generator_path)
+pyside2_config(--python-include-path python_include_dir)
+pyside2_config(--shiboken2-generator-include-path shiboken_include_dir 1)
+pyside2_config(--shiboken2-module-shared-libraries-cmake shiboken_shared_libraries 0)
+pyside2_config(--python-link-flags-cmake python_linking_data 0)
-set(shiboken_path "${pyside2_path}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}")
+set(shiboken_path "${shiboken2_generator_path}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}")
if(NOT EXISTS ${shiboken_path})
message(FATAL_ERROR "Shiboken executable not found at path: ${shiboken_path}")
endif()
@@ -87,7 +93,7 @@ endif()
# Enable rpaths so that the built shared libraries find their dependencies.
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
-set(CMAKE_INSTALL_RPATH ${pyside2_path} ${CMAKE_CURRENT_SOURCE_DIR})
+set(CMAKE_INSTALL_RPATH ${shiboken2_module_path} ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# =============================================================================================
# !!! End of dubious section.
diff --git a/examples/scriptableapplication/CMakeLists.txt b/examples/scriptableapplication/CMakeLists.txt
index 4119b6756..215d08961 100644
--- a/examples/scriptableapplication/CMakeLists.txt
+++ b/examples/scriptableapplication/CMakeLists.txt
@@ -14,6 +14,12 @@ set(CMAKE_CXX_STANDARD 11)
# Find required Qt packages.
find_package(Qt5 5.9 REQUIRED COMPONENTS Core Gui Widgets)
+# Use provided python interpreter if given.
+if(NOT python_interpreter)
+ find_program(python_interpreter "python")
+endif()
+message(STATUS "Using python interpreter: ${python_interpreter}")
+
# Macro to get various pyside / python include / link flags.
macro(pyside2_config option output_var)
if(${ARGC} GREATER 2)
@@ -23,7 +29,8 @@ macro(pyside2_config option output_var)
endif()
execute_process(
- COMMAND python "${CMAKE_SOURCE_DIR}/../utils/pyside2_config.py" ${option}
+ COMMAND ${python_interpreter} "${CMAKE_SOURCE_DIR}/../utils/pyside2_config.py"
+ ${option}
OUTPUT_VARIABLE ${output_var}
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -35,14 +42,20 @@ macro(pyside2_config option output_var)
endif()
endmacro()
-# Query for the PySide2 path, Python path, include paths and linker flags.
-pyside2_config(--pyside2 PYSIDE2_PATH)
-pyside2_config(--python-include PYTHON_INCLUDE_DIR)
-pyside2_config(--pyside2-include PYSIDE2_INCLUDE_DIR 1)
+# Query for the shiboken2-generator path, PySide2 path, Python path, include paths and linker flags.
+pyside2_config(--shiboken2-module-path SHIBOKEN2_MODULE_PATH)
+pyside2_config(--shiboken2-generator-path SHIBOKEN2_GENERATOR_PATH)
+pyside2_config(--pyside2-path PYSIDE2_PATH)
+
+pyside2_config(--python-include-path PYTHON_INCLUDE_DIR)
+pyside2_config(--shiboken2-generator-include-path SHIBOKEN2_GENERATOR_INCLUDE_DIR 1)
+pyside2_config(--pyside2-include-path PYSIDE2_INCLUDE_DIR 1)
+
+pyside2_config(--python-link-flags-cmake PYTHON_LINKING_DATA 0)
+pyside2_config(--shiboken2-module-shared-libraries-cmake SHIBOKEN2_MODULE_SHARED_LIBRARIES 0)
pyside2_config(--pyside2-shared-libraries-cmake PYSIDE2_SHARED_LIBRARIES 0)
-pyside2_config(--python-link-cmake PYTHON_LINKING_DATA 0)
-set(SHIBOKEN_PATH "${PYSIDE2_PATH}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}")
+set(SHIBOKEN_PATH "${SHIBOKEN2_GENERATOR_PATH}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}")
if(NOT EXISTS ${SHIBOKEN_PATH})
message(FATAL_ERROR "Shiboken executable not found at path: ${SHIBOKEN_PATH}")
@@ -122,7 +135,7 @@ endforeach()
# Enable rpaths so that the example can be executed from the build dir.
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
-set(CMAKE_INSTALL_RPATH ${PYSIDE2_PATH})
+set(CMAKE_INSTALL_RPATH ${PYSIDE2_PATH} ${SHIBOKEN2_MODULE_PATH})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# =============================================================================================
# !!! End of dubious section.
@@ -139,11 +152,13 @@ target_sources(${PROJECT_NAME} PUBLIC ${SOURCES})
# Apply relevant include and link flags.
target_include_directories(${PROJECT_NAME} PRIVATE ${PYTHON_INCLUDE_DIR})
+target_include_directories(${PROJECT_NAME} PRIVATE ${SHIBOKEN2_GENERATOR_INCLUDE_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${PYSIDE2_INCLUDE_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${PYSIDE2_ADDITIONAL_INCLUDES})
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)
+target_link_libraries(${PROJECT_NAME} PRIVATE ${SHIBOKEN2_MODULE_SHARED_LIBRARIES})
target_link_libraries(${PROJECT_NAME} PRIVATE ${PYSIDE2_SHARED_LIBRARIES})
# Find and link to the python library.
@@ -176,7 +191,8 @@ if(WIN32)
# Add custom target to hard link PySide2 shared libraries (just like in qmake example), so you
# don't have to set PATH manually to point to the PySide2 package.
- foreach(LIBRARY_PATH ${PYSIDE2_SHARED_LIBRARIES})
+ set(shared_libraries ${SHIBOKEN2_MODULE_SHARED_LIBRARIES} ${PYSIDE2_SHARED_LIBRARIES})
+ foreach(LIBRARY_PATH ${shared_libraries})
string(REGEX REPLACE ".lib$" ".dll" LIBRARY_PATH ${LIBRARY_PATH})
get_filename_component(BASE_NAME ${LIBRARY_PATH} NAME)
file(TO_NATIVE_PATH ${LIBRARY_PATH} SOURCE_PATH)
diff --git a/examples/scriptableapplication/pyside2.pri b/examples/scriptableapplication/pyside2.pri
index 17be4392f..2da3bc880 100644
--- a/examples/scriptableapplication/pyside2.pri
+++ b/examples/scriptableapplication/pyside2.pri
@@ -1,30 +1,52 @@
PYSIDE_CONFIG = $$PWD/../utils/pyside2_config.py
-PYSIDE2 = $$system(python $$PYSIDE_CONFIG --pyside2)
+# Use provided python interpreter if given.
+isEmpty(python_interpreter) {
+ python_interpreter = python
+}
+message(Using python interpreter: $$python_interpreter)
+
+SHIBOKEN2_GENERATOR = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-generator-path)
+isEmpty(SHIBOKEN2_GENERATOR): error(Unable to locate the shiboken2-generator package location)
+
+SHIBOKEN2_MODULE = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-module-path)
+isEmpty(SHIBOKEN2_MODULE): error(Unable to locate the shiboken2 package location)
+
+PYSIDE2 = $$system($$python_interpreter $$PYSIDE_CONFIG --pyside2-path)
isEmpty(PYSIDE2): error(Unable to locate the PySide2 package location)
-PYTHON_INCLUDE = $$system(python $$PYSIDE_CONFIG --python-include)
+PYTHON_INCLUDE = $$system($$python_interpreter $$PYSIDE_CONFIG --python-include-path)
isEmpty(PYTHON_INCLUDE): error(Unable to locate the Python include headers directory)
-PYTHON_LFLAGS = $$system(python $$PYSIDE_CONFIG --python-link)
+PYTHON_LFLAGS = $$system($$python_interpreter $$PYSIDE_CONFIG --python-link-flags-qmake)
isEmpty(PYTHON_LFLAGS): error(Unable to locate the Python library for linking)
-PYSIDE2_INCLUDE = $$system(python $$PYSIDE_CONFIG --pyside2-include)
+SHIBOKEN2_INCLUDE = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-generator-include-path)
+isEmpty(SHIBOKEN2_INCLUDE): error(Unable to locate the shiboken include headers directory)
+
+PYSIDE2_INCLUDE = $$system($$python_interpreter $$PYSIDE_CONFIG --pyside2-include-path)
isEmpty(PYSIDE2_INCLUDE): error(Unable to locate the PySide2 include headers directory)
-PYSIDE2_LFLAGS = $$system(python $$PYSIDE_CONFIG --pyside2-link)
+SHIBOKEN2_LFLAGS = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-module-qmake-lflags)
+isEmpty(SHIBOKEN2_LFLAGS): error(Unable to locate the shiboken libraries for linking)
+
+PYSIDE2_LFLAGS = $$system($$python_interpreter $$PYSIDE_CONFIG --pyside2-qmake-lflags)
isEmpty(PYSIDE2_LFLAGS): error(Unable to locate the PySide2 libraries for linking)
-PYSIDE2_SHARED_LIBRARIES = $$system(python $$PYSIDE_CONFIG --pyside2-shared-libraries)
+SHIBOKEN2_SHARED_LIBRARIES = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-module-shared-libraries-qmake)
+isEmpty(SHIBOKEN2_SHARED_LIBRARIES): error(Unable to locate the used shiboken2 module shared libraries)
+
+PYSIDE2_SHARED_LIBRARIES = $$system($$python_interpreter $$PYSIDE_CONFIG --pyside2-shared-libraries-qmake)
isEmpty(PYSIDE2_SHARED_LIBRARIES): error(Unable to locate the used PySide2 shared libraries)
-INCLUDEPATH += "$$PYTHON_INCLUDE" $$PYSIDE2_INCLUDE
-LIBS += $$PYTHON_LFLAGS $$PYSIDE2_LFLAGS
+INCLUDEPATH += "$$PYTHON_INCLUDE" $$PYSIDE2_INCLUDE $$SHIBOKEN2_INCLUDE
+LIBS += $$PYTHON_LFLAGS $$PYSIDE2_LFLAGS $$SHIBOKEN2_LFLAGS
!build_pass:message(INCLUDEPATH is $$INCLUDEPATH)
!build_pass:message(LIBS are $$LIBS)
!build_pass:message(Using $$PYSIDE2)
!win32 {
- QMAKE_RPATHDIR += $$PYSIDE2
+ !build_pass:message(RPATH will include $$PYSIDE2 and $$SHIBOKEN2_MODULE)
+ QMAKE_RPATHDIR += $$PYSIDE2 $$SHIBOKEN2_MODULE
}
diff --git a/examples/scriptableapplication/scriptableapplication.pro b/examples/scriptableapplication/scriptableapplication.pro
index 8a09b0abf..8ebab9476 100644
--- a/examples/scriptableapplication/scriptableapplication.pro
+++ b/examples/scriptableapplication/scriptableapplication.pro
@@ -23,7 +23,7 @@ SHIBOKEN_OPTIONS = --generator-set=shiboken --enable-parent-ctor-heuristic \
win32:SHIBOKEN_OPTIONS += --avoid-protected-hack
# Prepare the shiboken tool
-QT_TOOL.shiboken.binary = $$system_path($$PYSIDE2/shiboken2)
+QT_TOOL.shiboken.binary = $$system_path($$SHIBOKEN2_GENERATOR/shiboken2)
qtPrepareTool(SHIBOKEN, shiboken)
# Shiboken run that adds the module wrapper to GENERATED_SOURCES
@@ -61,7 +61,7 @@ win32 {
hard_link_libraries.CONFIG = no_link target_predeps explicit_dependencies
hard_link_libraries.output = $$out_dir/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT}
hard_link_libraries.commands = mklink /H $$shell_path($$out_dir/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT}) $$shell_path(${QMAKE_FILE_IN})
- hard_link_libraries.input = PYSIDE2_SHARED_LIBRARIES
+ hard_link_libraries.input = PYSIDE2_SHARED_LIBRARIES SHIBOKEN2_SHARED_LIBRARIES
}
QMAKE_EXTRA_COMPILERS += shiboken module_wrapper_dummy_command
diff --git a/examples/utils/pyside2_config.py b/examples/utils/pyside2_config.py
index 298d40d5b..c62b38cad 100644
--- a/examples/utils/pyside2_config.py
+++ b/examples/utils/pyside2_config.py
@@ -38,28 +38,106 @@
##
#############################################################################
-import os, glob, re, sys, imp
+import os, glob, re, sys
from distutils import sysconfig
+generic_error = (' Did you forget to activate your virtualenv? Or perhaps'
+ ' you forgot to build / install PySide2 into your currently active Python'
+ ' environment?')
+pyside2_error = 'Unable to locate PySide2.' + generic_error
+shiboken2_module_error = 'Unable to locate shiboken2-module.' + generic_error
+shiboken2_generator_error = 'Unable to locate shiboken2-generator.' + generic_error
+pyside2_libs_error = 'Unable to locate the PySide2 shared libraries.' + generic_error
+python_link_error = 'Unable to locate the Python library for linking.'
+python_include_error = 'Unable to locate the Python include headers directory.'
+
+options = []
+
+# option, function, error, description
+options.append(("--shiboken2-module-path",
+ lambda: find_shiboken2_module(),
+ shiboken2_module_error,
+ "Print shiboken2 module location"))
+options.append(("--shiboken2-generator-path",
+ lambda: find_shiboken2_generator(),
+ shiboken2_generator_error,
+ "Print shiboken2 generator location"))
+options.append(("--pyside2-path", lambda: find_pyside2(), pyside2_error,
+ "Print PySide2 location"))
+
+options.append(("--python-include-path",
+ lambda: get_python_include_path(),
+ python_include_error,
+ "Print Python include path"))
+options.append(("--shiboken2-generator-include-path",
+ lambda: get_package_include_path(Package.shiboken2_generator),
+ pyside2_error,
+ "Print shiboken2 generator include paths"))
+options.append(("--pyside2-include-path",
+ lambda: get_package_include_path(Package.pyside2),
+ pyside2_error,
+ "Print PySide2 include paths"))
+
+options.append(("--python-link-flags-qmake", lambda: python_link_flags_qmake(), python_link_error,
+ "Print python link flags for qmake"))
+options.append(("--python-link-flags-cmake", lambda: python_link_flags_cmake(), python_link_error,
+ "Print python link flags for cmake"))
+
+options.append(("--shiboken2-module-qmake-lflags",
+ lambda: get_package_qmake_lflags(Package.shiboken2_module), pyside2_error,
+ "Print shiboken2 shared library link flags for qmake"))
+options.append(("--pyside2-qmake-lflags",
+ lambda: get_package_qmake_lflags(Package.pyside2), pyside2_error,
+ "Print PySide2 shared library link flags for qmake"))
+
+options.append(("--shiboken2-module-shared-libraries-qmake",
+ lambda: get_shared_libraries_qmake(Package.shiboken2_module), pyside2_libs_error,
+ "Print paths of shiboken2 shared libraries (.so's, .dylib's, .dll's) for qmake"))
+options.append(("--shiboken2-module-shared-libraries-cmake",
+ lambda: get_shared_libraries_cmake(Package.shiboken2_module), pyside2_libs_error,
+ "Print paths of shiboken2 shared libraries (.so's, .dylib's, .dll's) for cmake"))
+
+options.append(("--pyside2-shared-libraries-qmake",
+ lambda: get_shared_libraries_qmake(Package.pyside2), pyside2_libs_error,
+ "Print paths of PySide2 shared libraries (.so's, .dylib's, .dll's) for qmake"))
+options.append(("--pyside2-shared-libraries-cmake",
+ lambda: get_shared_libraries_cmake(Package.pyside2), pyside2_libs_error,
+ "Print paths of PySide2 shared libraries (.so's, .dylib's, .dll's) for cmake"))
+
+options_usage = ''
+for i, (flag, _, _, description) in enumerate(options):
+ options_usage += ' {:<45} {}'.format(flag, description)
+ if i < len(options) - 1:
+ options_usage += '\n'
+
usage = """
-Utility to determine include/link options of PySide2 and Python for qmake
+Utility to determine include/link options of shiboken2/PySide2 and Python for qmake/CMake projects
+that would like to embed or build custom shiboken2/PySide2 bindings.
Usage: pyside2_config.py [option]
Options:
- --python-include Print Python include path
- --python-link Print Python link flags
- --pyside2 Print PySide2 location
- --pyside2-include Print PySide2 include paths
- --pyside2-link Print PySide2 link flags
- --pyside2-shared-libraries Print paths of PySide2 shared libraries (.so's, .dylib's, .dll's)
- -a Print all
- --help/-h Print this help
-"""
-
-def cleanPath(path):
+{}
+ -a Print all options and their values
+ --help/-h Print this help
+""".format(options_usage)
+
+option = sys.argv[1] if len(sys.argv) == 2 else '-a'
+if option == '-h' or option == '--help':
+ print(usage)
+ sys.exit(0)
+
+
+class Package(object):
+ shiboken2_module = 1
+ shiboken2_generator = 2
+ pyside2 = 3
+
+
+def clean_path(path):
return path if sys.platform != 'win32' else path.replace('\\', '/')
-def sharedLibrarySuffix():
+
+def shared_library_suffix():
if sys.platform == 'win32':
return 'lib'
elif sys.platform == 'darwin':
@@ -68,21 +146,41 @@ def sharedLibrarySuffix():
else:
return 'so.*'
-def sharedLibraryGlobPattern():
- glob = '*.' + sharedLibrarySuffix()
+
+def import_suffixes():
+ if (sys.version_info >= (3, 4)):
+ import importlib
+ return importlib.machinery.EXTENSION_SUFFIXES
+ else:
+ import imp
+ result = []
+ for t in imp.get_suffixes():
+ result.append(t[0])
+ return result
+
+
+def is_debug():
+ debug_suffix = '_d.pyd' if sys.platform == 'win32' else '_d.so'
+ return any([s.endswith(debug_suffix) for s in import_suffixes()])
+
+
+def shared_library_glob_pattern():
+ glob = '*.' + shared_library_suffix()
return glob if sys.platform == 'win32' else 'lib' + glob
-def filterPySide2SharedLibraries(list, only_shiboken=False):
- def predicate(item):
- basename = os.path.basename(item)
- if 'shiboken' in basename or ('pyside2' in basename and not only_shiboken):
+
+def filter_shared_libraries(libs_list):
+ def predicate(lib_name):
+ basename = os.path.basename(lib_name)
+ if 'shiboken' in basename or 'pyside2' in basename:
return True
return False
- result = [item for item in list if predicate(item)]
+ result = [lib for lib in libs_list if predicate(lib)]
return result
+
# Return qmake link option for a library file name
-def linkOption(lib):
+def link_option(lib):
# On Linux:
# Since we cannot include symlinks with wheel packages
# we are using an absolute path for the libpyside and libshiboken
@@ -97,24 +195,50 @@ def linkOption(lib):
link += os.path.splitext(baseName)[0]
return link
-# Locate PySide2 via package path
-def findPySide2():
+
+# Locate PySide2 via sys.path package path.
+def find_pyside2():
+ return find_package_path("PySide2")
+
+
+def find_shiboken2_module():
+ return find_package_path("shiboken2")
+
+
+def find_shiboken2_generator():
+ return find_package_path("shiboken2_generator")
+
+
+def find_package(which_package):
+ if which_package == Package.shiboken2_module:
+ return find_shiboken2_module()
+ if which_package == Package.shiboken2_generator:
+ return find_shiboken2_generator()
+ if which_package == Package.pyside2:
+ return find_pyside2()
+ return None
+
+
+def find_package_path(dir_name):
for p in sys.path:
if 'site-' in p:
- pyside2 = os.path.join(p, 'PySide2')
- if os.path.exists(pyside2):
- return cleanPath(os.path.realpath(pyside2))
+ package = os.path.join(p, dir_name)
+ if os.path.exists(package):
+ return clean_path(os.path.realpath(package))
return None
+
# Return version as "3.5"
-def pythonVersion():
+def python_version():
return str(sys.version_info[0]) + '.' + str(sys.version_info[1])
-def pythonInclude():
+
+def get_python_include_path():
return sysconfig.get_python_inc()
-def pythonLinkQmake():
- flags = pythonLinkData()
+
+def python_link_flags_qmake():
+ flags = python_link_data()
if sys.platform == 'win32':
libdir = flags['libdir']
# This will add the "~1" shortcut for directories that
@@ -131,25 +255,27 @@ def pythonLinkQmake():
# Linux and anything else
return '-L{} -l{}'.format(flags['libdir'], flags['lib'])
-def pythonLinkCmake():
- flags = pythonLinkData()
+
+def python_link_flags_cmake():
+ flags = python_link_data()
libdir = flags['libdir']
lib = re.sub(r'.dll$', '.lib', flags['lib'])
return '{};{}'.format(libdir, lib)
-def pythonLinkData():
+
+def python_link_data():
# @TODO Fix to work with static builds of Python
libdir = sysconfig.get_config_var('LIBDIR')
if libdir is None:
libdir = os.path.abspath(os.path.join(
sysconfig.get_config_var('LIBDEST'), "..", "libs"))
- version = pythonVersion()
+ version = python_version()
version_no_dots = version.replace('.', '')
flags = {}
flags['libdir'] = libdir
if sys.platform == 'win32':
- suffix = '_d' if any([tup[0].endswith('_d.pyd') for tup in imp.get_suffixes()]) else ''
+ suffix = '_d' if is_debug() else ''
flags['lib'] = 'python{}{}'.format(version_no_dots, suffix)
elif sys.platform == 'darwin':
@@ -158,42 +284,44 @@ def pythonLinkData():
# Linux and anything else
else:
if sys.version_info[0] < 3:
- suffix = '_d' if any([tup[0].endswith('_d.so') for tup in imp.get_suffixes()]) else ''
+ suffix = '_d' if is_debug() else ''
flags['lib'] = 'python{}{}'.format(version, suffix)
else:
flags['lib'] = 'python{}{}'.format(version, sys.abiflags)
return flags
-def pyside2Include(only_shiboken=False):
- pySide2 = findPySide2()
- if pySide2 is None:
+
+def get_package_include_path(which_package):
+ package_path = find_package(which_package)
+ if package_path is None:
return None
- includes = "{0}/include/shiboken2".format(pySide2)
- if not only_shiboken:
- includes = includes + " {0}/include/PySide2".format(pySide2)
+ includes = "{0}/include".format(package_path)
return includes
-def pyside2Link():
- pySide2 = findPySide2()
- if pySide2 is None:
+
+def get_package_qmake_lflags(which_package):
+ package_path = find_package(which_package)
+ if package_path is None:
return None
- link = "-L{}".format(pySide2)
- glob_result = glob.glob(os.path.join(pySide2, sharedLibraryGlobPattern()))
- for lib in filterPySide2SharedLibraries(glob_result):
+
+ link = "-L{}".format(package_path)
+ glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern()))
+ for lib in filter_shared_libraries(glob_result):
link += ' '
- link += linkOption(lib)
+ link += link_option(lib)
return link
-def pyside2SharedLibrariesData(only_shiboken=False):
- pySide2 = findPySide2()
- if pySide2 is None:
+
+def get_shared_libraries_data(which_package):
+ package_path = find_package(which_package)
+ if package_path is None:
return None
- glob_result = glob.glob(os.path.join(pySide2, sharedLibraryGlobPattern()))
- filtered_libs = filterPySide2SharedLibraries(glob_result, only_shiboken)
+ glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern()))
+ filtered_libs = filter_shared_libraries(glob_result)
libs = []
if sys.platform == 'win32':
for lib in filtered_libs:
@@ -203,8 +331,9 @@ def pyside2SharedLibrariesData(only_shiboken=False):
libs.append(lib)
return libs
-def pyside2SharedLibraries():
- libs = pyside2SharedLibrariesData()
+
+def get_shared_libraries_qmake(which_package):
+ libs = get_shared_libraries_data(which_package)
if libs is None:
return None
@@ -223,80 +352,21 @@ def pyside2SharedLibraries():
libs_string += lib + ' '
return libs_string
-def pyside2SharedLibrariesCmake(only_shiboken=False):
- libs = pyside2SharedLibrariesData(only_shiboken)
+
+def get_shared_libraries_cmake(which_package):
+ libs = get_shared_libraries_data(which_package)
result = ';'.join(libs)
return result
-option = sys.argv[1] if len(sys.argv) == 2 else '-a'
-if option == '-h' or option == '--help':
- print(usage)
- sys.exit(0)
-generic_error = (' Did you forget to activate your virtualenv? Or perhaps'
- ' you forgot to build / install PySide2 into your currently active Python'
- ' environment?')
-pyside2_error = 'Unable to locate PySide2.' + generic_error
-pyside2_libs_error = 'Unable to locate the PySide2 shared libraries.' + generic_error
-python_link_error = 'Unable to locate the Python library for linking.'
+print_all = option == "-a"
+for argument, handler, error, _ in options:
+ if option == argument or print_all:
+ handler_result = handler()
+ if handler_result is None:
+ sys.exit(error)
-if option == '--pyside2' or option == '-a':
- pySide2 = findPySide2()
- if pySide2 is None:
- sys.exit(pyside2_error)
- print(pySide2)
-
-if option == '--pyside2-link' or option == '-a':
- l = pyside2Link()
- if l is None:
- sys.exit(pyside2_error)
-
- print(l)
-
-if option == '--shiboken-include' or option == '-a':
- i = pyside2Include(only_shiboken=True)
- if i is None:
- sys.exit(pyside2_error)
- print(i)
-
-if option == '--pyside2-include' or option == '-a':
- i = pyside2Include()
- if i is None:
- sys.exit(pyside2_error)
- print(i)
-
-if option == '--python-include' or option == '-a':
- i = pythonInclude()
- if i is None:
- sys.exit('Unable to locate the Python include headers directory.')
- print(i)
-
-if option == '--python-link' or option == '-a':
- l = pythonLinkQmake()
- if l is None:
- sys.exit(python_link_error)
- print(l)
-
-if option == '--python-link-cmake' or option == '-a':
- l = pythonLinkCmake()
- if l is None:
- sys.exit(python_link_error)
- print(l)
-
-if option == '--pyside2-shared-libraries' or option == '-a':
- l = pyside2SharedLibraries()
- if l is None:
- sys.exit(pyside2_libs_error)
- print(l)
-
-if option == '--pyside2-shared-libraries-cmake' or option == '-a':
- l = pyside2SharedLibrariesCmake()
- if l is None:
- sys.exit(pyside2_libs_error)
- print(l)
-
-if option == '--shiboken-shared-libraries-cmake' or option == '-a':
- l = pyside2SharedLibrariesCmake(only_shiboken=True)
- if l is None:
- sys.exit(pyside2_libs_error)
- print(l)
+ line = handler_result
+ if print_all:
+ line = "{:<40}: ".format(argument) + line
+ print(line)
diff --git a/keyword-errors.lst b/keyword-errors.lst
new file mode 100644
index 000000000..af8c581a5
--- /dev/null
+++ b/keyword-errors.lst
@@ -0,0 +1,43 @@
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QAbstractItemModel.changePersistentIndex', 'arglist': 'from:PySide2.QtCore.QModelIndex,to:PySide2.QtCore.QModelIndex', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QAbstractItemModel.changePersistentIndexList', 'arglist': 'from:QModelIndexList,to:QModelIndexList', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QByteArray.indexOf', 'arglist': 'a:PySide2.QtCore.QByteArray,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QByteArray.lastIndexOf', 'arglist': 'a:PySide2.QtCore.QByteArray,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': '1', 'funcname': 'PySide2.QtCore.QByteArrayMatcher.indexIn', 'arglist': 'ba:PySide2.QtCore.QByteArray,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': '0', 'funcname': 'PySide2.QtCore.QByteArrayMatcher.indexIn', 'arglist': 'str:str,len:int,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QItemSelection.indexOf', 'arglist': 't:PySide2.QtCore.QItemSelectionRange,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QItemSelection.lastIndexOf', 'arglist': 't:PySide2.QtCore.QItemSelectionRange,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QItemSelection.move', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QTextCodec.convertToUnicode', 'arglist': 'in:str,length:int,state:PySide2.QtCore.QTextCodec.ConverterState', 'returntype': 'QString'}
+KEYWORD {'multi': '0', 'funcname': 'PySide2.QtCore.QTextCodec.toUnicode', 'arglist': 'in:str,length:int,state:PySide2.QtCore.QTextCodec.ConverterState=nullptr', 'returntype': 'QString'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QVariantAnimation.interpolated', 'arglist': 'from:QVariant,to:QVariant,progress:double', 'returntype': 'QVariant'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QXmlStreamAttributes.indexOf', 'arglist': 't:PySide2.QtCore.QXmlStreamAttribute,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QXmlStreamAttributes.lastIndexOf', 'arglist': 't:PySide2.QtCore.QXmlStreamAttribute,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QXmlStreamAttributes.move', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QAbstractTextDocumentLayout.documentChanged', 'arglist': 'from:int,charsRemoved:int,charsAdded:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QIconEngine.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'bool'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QKeySequence.__lshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygon.indexOf', 'arglist': 't:PySide2.QtCore.QPoint,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygon.lastIndexOf', 'arglist': 't:PySide2.QtCore.QPoint,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygon.move', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygonF.indexOf', 'arglist': 't:PySide2.QtCore.QPointF,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygonF.lastIndexOf', 'arglist': 't:PySide2.QtCore.QPointF,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygonF.move', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QQuaternion.rotationTo', 'arglist': 'from:PySide2.QtGui.QVector3D,to:PySide2.QtGui.QVector3D', 'returntype': 'PySide2.QtGui.QQuaternion'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QStandardItem.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QStandardItem.__rshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': '4', 'funcname': 'PySide2.QtGui.QTextDocument.find', 'arglist': 'expr:PySide2.QtCore.QRegExp,from:int=0,options:PySide2.QtGui.QTextDocument.FindFlags=QTextDocument.FindFlags()', 'returntype': 'PySide2.QtGui.QTextCursor'}
+KEYWORD {'multi': '2', 'funcname': 'PySide2.QtGui.QTextDocument.find', 'arglist': 'expr:PySide2.QtCore.QRegularExpression,from:int=0,options:PySide2.QtGui.QTextDocument.FindFlags=QTextDocument.FindFlags()', 'returntype': 'PySide2.QtGui.QTextCursor'}
+KEYWORD {'multi': '0', 'funcname': 'PySide2.QtGui.QTextDocument.find', 'arglist': 'subString:QString,from:int=0,options:PySide2.QtGui.QTextDocument.FindFlags=QTextDocument.FindFlags()', 'returntype': 'PySide2.QtGui.QTextCursor'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QTextDocument.markContentsDirty', 'arglist': 'from:int,length:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QHeaderView.moveSection', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QLayout.replaceWidget', 'arglist': 'from:PySide2.QtWidgets.QWidget,to:PySide2.QtWidgets.QWidget,options:PySide2.QtCore.Qt.FindChildOptions=Qt.FindChildrenRecursively', 'returntype': 'PySide2.QtWidgets.QLayoutItem'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QListWidgetItem.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QListWidgetItem.__rshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QPlainTextDocumentLayout.documentChanged', 'arglist': 'from:int,arg__2:int,charsAdded:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTabBar.moveTab', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTableWidgetItem.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTableWidgetItem.__rshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTreeWidgetItem.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTreeWidgetItem.__rshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtMultimedia.QAudio.convertVolume', 'arglist': 'volume:double,from:PySide2.QtMultimedia.QAudio.VolumeScale,to:PySide2.QtMultimedia.QAudio.VolumeScale', 'returntype': 'double'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtMultimedia.QMediaPlaylist.moveMedia', 'arglist': 'from:int,to:int', 'returntype': 'bool'}
diff --git a/popenasync.py b/popenasync.py
deleted file mode 100644
index 77faf9e0c..000000000
--- a/popenasync.py
+++ /dev/null
@@ -1,360 +0,0 @@
-#############################################################################
-##
-## Copyright (C) 2017 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is part of Qt for Python.
-##
-## $QT_BEGIN_LICENSE:LGPL$
-## Commercial License Usage
-## Licensees holding valid commercial Qt licenses may use this file in
-## accordance with the commercial license agreement provided with the
-## Software or, alternatively, in accordance with the terms contained in
-## a written agreement between you and The Qt Company. For licensing terms
-## and conditions see https://www.qt.io/terms-conditions. For further
-## information use the contact form at https://www.qt.io/contact-us.
-##
-## GNU Lesser General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU Lesser
-## General Public License version 3 as published by the Free Software
-## Foundation and appearing in the file LICENSE.LGPL3 included in the
-## packaging of this file. Please review the following information to
-## ensure the GNU Lesser General Public License version 3 requirements
-## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-##
-## GNU General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU
-## General Public License version 2.0 or (at your option) the GNU General
-## Public license version 3 or any later version approved by the KDE Free
-## Qt Foundation. The licenses are as published by the Free Software
-## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-## included in the packaging of this file. Please review the following
-## information to ensure the GNU General Public License requirements will
-## be met: https://www.gnu.org/licenses/gpl-2.0.html and
-## https://www.gnu.org/licenses/gpl-3.0.html.
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
-
-################################################################################
-"""
-
-Modification of http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554
-
-"""
-
-#################################### IMPORTS ###################################
-
-import os
-import subprocess
-import errno
-import time
-import sys
-import unittest
-import tempfile
-
-def geterror ():
- return sys.exc_info()[1]
-
-if sys.version_info >= (3,):
- null_byte = '\x00'.encode('ascii')
-else:
- null_byte = '\x00'
-
-mswindows = (sys.platform == "win32")
-
-if mswindows:
- if sys.version_info >= (3,):
- # Test date should be in ascii.
- def encode(s):
- return s.encode('ascii', 'ignore')
-
- def decode(b):
- return b.decode('ascii', 'ignore')
- else:
- # Strings only; do nothing
- def encode(s):
- return s
-
- def decode(b):
- return b
-
- try:
- import ctypes
- from ctypes.wintypes import DWORD
- kernel32 = ctypes.windll.kernel32
- TerminateProcess = ctypes.windll.kernel32.TerminateProcess
- def WriteFile(handle, data, ol = None):
- c_written = DWORD()
- success = ctypes.windll.kernel32.WriteFile(handle,
- ctypes.create_string_buffer(encode(data)), len(data),
- ctypes.byref(c_written), ol)
- return ctypes.windll.kernel32.GetLastError(), c_written.value
- def ReadFile(handle, desired_bytes, ol = None):
- c_read = DWORD()
- buffer = ctypes.create_string_buffer(desired_bytes+1)
- success = ctypes.windll.kernel32.ReadFile(handle, buffer,
- desired_bytes, ctypes.byref(c_read), ol)
- buffer[c_read.value] = null_byte
- return ctypes.windll.kernel32.GetLastError(), decode(buffer.value)
- def PeekNamedPipe(handle, desired_bytes):
- c_avail = DWORD()
- c_message = DWORD()
- if desired_bytes > 0:
- c_read = DWORD()
- buffer = ctypes.create_string_buffer(desired_bytes+1)
- success = ctypes.windll.kernel32.PeekNamedPipe(handle, buffer,
- desired_bytes, ctypes.byref(c_read), ctypes.byref(c_avail),
- ctypes.byref(c_message))
- buffer[c_read.value] = null_byte
- return decode(buffer.value), c_avail.value, c_message.value
- else:
- success = ctypes.windll.kernel32.PeekNamedPipe(handle, None,
- desired_bytes, None, ctypes.byref(c_avail),
- ctypes.byref(c_message))
- return "", c_avail.value, c_message.value
-
- except ImportError:
- from win32file import ReadFile, WriteFile
- from win32pipe import PeekNamedPipe
- from win32api import TerminateProcess
- import msvcrt
-
-else:
- from signal import SIGINT, SIGTERM, SIGKILL
- import select
- import fcntl
-
-################################### CONSTANTS ##################################
-
-PIPE = subprocess.PIPE
-
-################################################################################
-
-class Popen(subprocess.Popen):
- def __init__(self, *args, **kwargs):
- subprocess.Popen.__init__(self, *args, **kwargs)
-
- def recv(self, maxsize=None):
- return self._recv('stdout', maxsize)
-
- def recv_err(self, maxsize=None):
- return self._recv('stderr', maxsize)
-
- def send_recv(self, input='', maxsize=None):
- return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
-
- def read_async(self, wait=.1, e=1, tr=5, stderr=0):
- if tr < 1:
- tr = 1
- x = time.time()+ wait
- y = []
- r = ''
- pr = self.recv
- if stderr:
- pr = self.recv_err
- while time.time() < x or r:
- r = pr()
- if r is None:
- if e:
- raise Exception("Other end disconnected!")
- else:
- break
- elif r:
- y.append(r)
- else:
- time.sleep(max((x-time.time())/tr, 0))
- return ''.join(y)
-
- def send_all(self, data):
- while len(data):
- sent = self.send(data)
- if sent is None:
- raise Exception("Other end disconnected!")
- data = buffer(data, sent)
-
- def get_conn_maxsize(self, which, maxsize):
- if maxsize is None:
- maxsize = 1024
- elif maxsize < 1:
- maxsize = 1
- return getattr(self, which), maxsize
-
- def _close(self, which):
- conn = getattr(self, which)
- flags = fcntl.fcntl(conn, fcntl.F_GETFL)
- if not conn.closed:
- fcntl.fcntl(conn, fcntl.F_SETFL, flags & ~os.O_NONBLOCK)
- assert conn.read() == ''
- getattr(self, which).close()
- setattr(self, which, None)
-
- if mswindows:
- def kill(self):
- # Recipes
- #http://me.in-berlin.de/doc/python/faq/windows.html#how-do-i-emulate-os-kill-in-windows
- #http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/347462
-
- """kill function for Win32"""
- TerminateProcess(int(self._handle), 0) # returns None
-
- def send(self, input):
- if not self.stdin:
- return None
-
- try:
- x = msvcrt.get_osfhandle(self.stdin.fileno())
- (errCode, written) = WriteFile(x, input)
- except ValueError:
- return self._close('stdin')
- except (subprocess.pywintypes.error, Exception):
- if geterror()[0] in (109, errno.ESHUTDOWN):
- return self._close('stdin')
- raise
-
- return written
-
- def _recv(self, which, maxsize):
- conn, maxsize = self.get_conn_maxsize(which, maxsize)
- if conn is None:
- return None
-
- try:
- x = msvcrt.get_osfhandle(conn.fileno())
- (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
- if maxsize < nAvail:
- nAvail = maxsize
- if nAvail > 0:
- (errCode, read) = ReadFile(x, nAvail, None)
- except ValueError:
- return self._close(which)
- except (subprocess.pywintypes.error, Exception):
- if geterror()[0] in (109, errno.ESHUTDOWN):
- return self._close(which)
- raise
-
- if self.universal_newlines:
- # Translate newlines. For Python 3.x assume read is text.
- # If bytes then another solution is needed.
- read = read.replace("\r\n", "\n").replace("\r", "\n")
- return read
-
- else:
- def kill(self):
- for i, sig in enumerate([SIGTERM, SIGKILL] * 2):
- if i % 2 == 0: os.kill(self.pid, sig)
- time.sleep((i * (i % 2) / 5.0) + 0.01)
-
- killed_pid, stat = os.waitpid(self.pid, os.WNOHANG)
- if killed_pid != 0: return
-
- def send(self, input):
- if not self.stdin:
- return None
-
- if not select.select([], [self.stdin], [], 0)[1]:
- return 0
-
- try:
- written = os.write(self.stdin.fileno(), input)
- except OSError:
- if geterror()[0] == errno.EPIPE: #broken pipe
- return self._close('stdin')
- raise
-
- return written
-
- def _recv(self, which, maxsize):
- conn, maxsize = self.get_conn_maxsize(which, maxsize)
- if conn is None:
- return None
-
- flags = fcntl.fcntl(conn, fcntl.F_GETFL)
- if not conn.closed:
- fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
-
- try:
- if not select.select([conn], [], [], 0)[0]:
- return ''
-
- try:
- r = conn.read(maxsize)
- except IOError as e:
- if e.errno == errno.EAGAIN:
- return ''
- raise
- if not r:
- return self._close(which)
-
- if self.universal_newlines:
- r = r.replace("\r\n", "\n").replace("\r", "\n")
- return r
- finally:
- if not conn.closed:
- fcntl.fcntl(conn, fcntl.F_SETFL, flags)
-
-################################################################################
-
-def proc_in_time_or_kill(cmd, time_out, wd = None, env = None):
- proc = Popen (
- cmd, cwd = wd, env = env,
- stdin = subprocess.PIPE, stdout = subprocess.PIPE,
- stderr = subprocess.STDOUT, universal_newlines = 1
- )
-
- ret_code = None
- response = []
-
- t = time.time()
- while ret_code is None and ((time.time() -t) < time_out):
- ret_code = proc.poll()
- response += [proc.read_async(wait=0.1, e=0)]
-
- if ret_code is None:
- ret_code = '"Process timed out (time_out = {} secs) '.format(time_out)
- try:
- proc.kill()
- ret_code += 'and was successfully terminated"'
- except Exception:
- ret_code += ("and termination failed "
- "(exception: {})".format(geterror(),))
-
- return ret_code, ''.join(response)
-
-################################################################################
-
-class AsyncTest(unittest.TestCase):
- def test_proc_in_time_or_kill(self):
- ret_code, response = proc_in_time_or_kill(
- [sys.executable, '-c', 'while 1: pass'], time_out = 1
- )
-
- self.assert_( 'rocess timed out' in ret_code )
- self.assert_( 'successfully terminated' in ret_code )
-
-################################################################################
-
-def _example():
- if sys.platform == 'win32':
- shell, commands, tail = ('cmd', ('echo "hello"', 'echo "HELLO WORLD"'),
- '\r\n')
- else:
- shell, commands, tail = ('sh', ('ls', 'echo HELLO WORLD'), '\n')
-
- a = Popen(shell, stdin=PIPE, stdout=PIPE)
- sys.stdout.write(a.read_async())
- sys.stdout.write(" ")
- for cmd in commands:
- a.send_all(cmd + tail)
- sys.stdout.write(a.read_async())
- sys.stdout.write(" ")
- a.send_all('exit' + tail)
- print (a.read_async(e=0))
- a.wait()
-
-################################################################################
-
-if __name__ == '__main__':
- if 1: unittest.main()
- else: _example()
diff --git a/setup.py b/setup.py
index b218397c1..d27ca088f 100644
--- a/setup.py
+++ b/setup.py
@@ -42,12 +42,18 @@ from __future__ import print_function
"""
This is a distutils setup-script for the Qt for Python project
-To build PySide2 simply execute:
+To build both shiboken2 and PySide2 simply execute:
python setup.py build
or
python setup.py install
to build and install into your current Python installation.
+The same setup.py script is used to build all the components of the
+project:
+ - shiboken2 (the supporting Python module)
+ - shiboken2-generator (the bindings generation executable)
+ - PySide2
+ - pyside2-tools
Optionally, one can specify the location of qmake and cmake if it is
not on the current PATH with:
@@ -56,6 +62,23 @@ and
--cmake=/path/to/bin/cmake
respectively.
+By default, all of the above is built when no special options are
+passed to the script. You can use the --build-type parameter to specify
+which things should be built:
+ --build-type=shiboken2 - build / package only the python module
+ --build-type=shiboken2-generator - build / package the generator
+ executable
+ --build-type=pyside2 - build / package the PySide2 bindings and
+ and pyside2-tools
+ --build-type=all - the implicit default to build all of the above
+
+
+When building PySide2, optionally, one can specify the location of the
+shiboken2 cmake config path if it is not on the current PATH with:
+ --shiboken-config-dir=/path/to/shiboken/cmake/config/dir
+This is useful if you did a cmake installation of shiboken2 into
+a custom location.
+
For Windows, if OpenSSL support is required, it's necessary to specify
the directory path that contains the OpenSSL shared libraries
"libeay32.dll" and "ssleay32.dll", for example:
@@ -79,7 +102,7 @@ not specified.
You can use the option `--only-package` if you want to create more
binary packages (bdist_wheel, bdist_egg, ...) without rebuilding the
-entire PySide2 every time:
+entire project every time:
e.g.:
@@ -89,7 +112,7 @@ e.g.:
--cmake=c:\tools\cmake\bin\cmake.exe
--openssl=c:\libs\OpenSSL32bit\bin
-* Then, we create a bdist_egg reusing PySide2 build with option
+* Then, we create a bdist_egg reusing the PySide2 build with option
`--only-package`:
python setup.py bdist_egg --only-package
@@ -110,7 +133,7 @@ new environment variable called PYSIDE_DISABLE_INTERNAL_QT_CONF is
introduced.
You should assign the integer "1" to disable the internal `qt.conf`,
-or "0" (or leave empty) to keep usining the internal `qt.conf` file.
+or "0" (or leave empty) to keep using the internal `qt.conf` file.
DEVELOPMENT OPTIONS:
@@ -230,75 +253,18 @@ this_file = os.path.abspath(this_file)
if os.path.dirname(this_file):
os.chdir(os.path.dirname(this_file))
-from build_scripts.main import get_package_version, get_setuptools_extension_modules
-from build_scripts.main import pyside_package_dir_name
-from build_scripts.main import cmd_class_dict
-from build_scripts.main import README, CHANGES
-from setuptools import setup, Extension
+# Save the original command line arguments to pass them on to the setup
+# mechanism.
+original_argv = list(sys.argv)
-# The __version__ variable is just for PEP compliancy, and shouldn't be
-# used as a value source.
+from build_scripts.main import get_package_version, check_allowed_python_version
+from build_scripts.setup_runner import SetupRunner
+
+# The __version__ variable is just for PEP compliance, and shouldn't be
+# used as a value source. Use get_package_version() instead.
__version__ = get_package_version()
-extension_modules = get_setuptools_extension_modules()
-
-setup(
- name = "PySide2",
- version = get_package_version(),
- description = ("Python bindings for the Qt cross-platform application and "
- "UI framework"),
- long_description = README + "\n\n" + CHANGES,
- long_description_content_type = 'text/markdown',
- classifiers = [
- 'Development Status :: 5 - Production/Stable',
- 'Environment :: Console',
- 'Environment :: MacOS X',
- 'Environment :: X11 Applications :: Qt',
- 'Environment :: Win32 (MS Windows)',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
- 'Operating System :: MacOS :: MacOS X',
- 'Operating System :: POSIX',
- 'Operating System :: POSIX :: Linux',
- 'Operating System :: Microsoft',
- 'Operating System :: Microsoft :: Windows',
- 'Programming Language :: C++',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Topic :: Database',
- 'Topic :: Software Development',
- 'Topic :: Software Development :: Code Generators',
- 'Topic :: Software Development :: Libraries :: Application Frameworks',
- 'Topic :: Software Development :: User Interfaces',
- 'Topic :: Software Development :: Widget Sets',
- ],
- keywords = 'Qt',
- author = 'Qt for Python Team',
- author_email = 'pyside@qt-project.org',
- url = 'https://www.pyside.org',
- download_url = 'https://download.qt.io/official_releases/QtForPython/',
- license = 'LGPL',
- packages = ['PySide2', 'pyside2uic',
- 'pyside2uic.Compiler',
- 'pyside2uic.port_v{}'.format(sys.version_info[0]) ],
- package_dir = {'': pyside_package_dir_name},
- include_package_data = True,
- zip_safe = False,
- entry_points = {
- 'console_scripts': [
- 'pyside2-uic = PySide2.scripts.uic:main',
- ]
- },
- cmdclass = cmd_class_dict,
- # Add a bogus extension module (will never be built here since we
- # are overriding the build command to do it using cmake) so things
- # like bdist_egg will know that there are extension modules and
- # will name the dist with the full platform info.
- ext_modules = extension_modules,
- ext_package = 'PySide2',
-)
+check_allowed_python_version()
+
+setup_runner = SetupRunner(original_argv)
+setup_runner.run_setup()
diff --git a/sources/cmake_helpers/helpers.cmake b/sources/cmake_helpers/helpers.cmake
new file mode 100644
index 000000000..e64b8d9d3
--- /dev/null
+++ b/sources/cmake_helpers/helpers.cmake
@@ -0,0 +1,78 @@
+macro(compute_config_py_values
+ full_version_var_name
+ )
+ 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()
diff --git a/sources/pyside2-tools b/sources/pyside2-tools
-Subproject f1b775537e7fbd718516749583b2abf1cb6adbc
+Subproject e3e3caeba4aebd68dc301b23e89dc4f78d708d1
diff --git a/sources/pyside2/CMakeLists.txt b/sources/pyside2/CMakeLists.txt
index 358c119ae..25598bb5e 100644
--- a/sources/pyside2/CMakeLists.txt
+++ b/sources/pyside2/CMakeLists.txt
@@ -8,8 +8,10 @@ cmake_policy(SET CMP0046 NEW)
project(pysidebindings)
-set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Macros/
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/../cmake_helpers/
+ ${CMAKE_SOURCE_DIR}/cmake/Macros/
${CMAKE_MODULE_PATH})
+include(helpers)
option(USE_PYTHON_VERSION "Use specific python version to build pyside2." "")
@@ -244,64 +246,7 @@ else()
CACHE STRING "PySide2 version [full]" FORCE)
endif()
-string(TIMESTAMP PYSIDE_BUILD_DATE "%Y-%m-%dT%H:%M:%S+00:00" UTC)
-if (PYSIDE_BUILD_DATE)
- set(PYSIDE_BUILD_DATE "__build_date__ = '${PYSIDE_BUILD_DATE}'")
-endif()
-
-if (PYSIDE_SETUP_PY_PACKAGE_VERSION)
- set(PYSIDE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT "__setup_py_package_version__ = '${PYSIDE_SETUP_PY_PACKAGE_VERSION}'")
- set(FINAL_PACKAGE_VERSION ${PYSIDE_SETUP_PY_PACKAGE_VERSION})
-else()
- set(FINAL_PACKAGE_VERSION ${BINDING_API_VERSION_FULL})
-endif()
-
-if (PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP)
- set(PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT "__setup_py_package_timestamp__ = '${PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP}'")
-else()
- set(PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT "__setup_py_package_timestamp__ = ''")
-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 PYSIDE_SOURCE_IS_INSIDE_REPO
- ERROR_QUIET
- OUTPUT_STRIP_TRAILING_WHITESPACE)
-
- if(PYSIDE_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 PYSIDE_BUILD_COMMIT_DATE
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if(PYSIDE_BUILD_COMMIT_DATE)
- set(PYSIDE_BUILD_COMMIT_DATE "__build_commit_date__ = '${PYSIDE_BUILD_COMMIT_DATE}'")
- endif()
- unset(ENV{TZ})
-
- execute_process(
- COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
- OUTPUT_VARIABLE PYSIDE_BUILD_COMMIT_HASH
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if(PYSIDE_BUILD_COMMIT_HASH)
- set(PYSIDE_BUILD_COMMIT_HASH "__build_commit_hash__ = '${PYSIDE_BUILD_COMMIT_HASH}'")
- endif()
-
- execute_process(
- COMMAND ${GIT_EXECUTABLE} describe HEAD
- OUTPUT_VARIABLE PYSIDE_BUILD_COMMIT_HASH_DESCRIBED
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if(PYSIDE_BUILD_COMMIT_HASH_DESCRIBED)
- set(PYSIDE_BUILD_COMMIT_HASH_DESCRIBED "__build_commit_hash_described__ = '${PYSIDE_BUILD_COMMIT_HASH_DESCRIBED}'")
- endif()
-
- endif()
-endif()
+compute_config_py_values(BINDING_API_VERSION)
include(PySideModules)
diff --git a/sources/pyside2/PySide2/CMakeLists.txt b/sources/pyside2/PySide2/CMakeLists.txt
index 0263f7441..4709dd073 100644
--- a/sources/pyside2/PySide2/CMakeLists.txt
+++ b/sources/pyside2/PySide2/CMakeLists.txt
@@ -40,12 +40,18 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/__init__.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/__init__.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/__init__.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/__init__.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/layout.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/layout.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/loader.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/loader.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/mapping.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/mapping.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/parser.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/parser.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/__init__.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/__init__.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/enum_sig.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/enum_sig.py" COPYONLY)
if (PYTHON_VERSION_MAJOR EQUAL 3)
else()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/backport_inspect.py"
diff --git a/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml b/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml
index fb7a83ba7..013a49165 100644
--- a/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml
+++ b/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml
@@ -45,19 +45,41 @@
<namespace-type name="Qt3DCore">
<enum-type name="ChangeFlag" flags="ChangeFlags"/>
<object-type name="QAbstractAspect"/>
+ <object-type name="QAbstractEngine"/>
<object-type name="QAbstractSkeleton" since="5.10"/>
<object-type name="QArmature" since="5.10"/>
- <object-type name="QAspectEngine"/>
+ <object-type name="QAspectEngine">
+ <modify-function signature="registerAspect(Qt3DCore::QAbstractAspect*)">
+ <modify-argument index="this">
+ <parent index="1" action="add"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
<object-type name="QAspectJob"/>
<object-type name="QBackendNode">
<enum-type name="Mode"/>
</object-type>
+ <!-- TODO: Solve issues related to windows and a unresolved
+ external symbol
+ <object-type name="QBackendNodeMapper"/>-->
<object-type name="QComponent"/>
<object-type name="QComponentAddedChange"/>
<object-type name="QComponentRemovedChange"/>
<object-type name="QDynamicPropertyUpdatedChange"/>
- <object-type name="QEntity"/>
- <object-type name="QJoint" since="5.10"/>
+ <object-type name="QEntity">
+ <modify-function signature="addComponent(Qt3DCore::QComponent*)">
+ <modify-argument index="this">
+ <parent index="1" action="add"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
+ <object-type name="QJoint" since="5.10">
+ <modify-function signature="addChildJoint(Qt3DCore::QJoint*)">
+ <modify-argument index="this">
+ <parent index="1" action="add"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
<object-type name="QNode">
<enum-type name="PropertyTrackingMode"/>
</object-type>
@@ -88,5 +110,10 @@
<!-- Disambiguate from QtGui/qtransform.h -->
<include file-name="Qt3DCore/qtransform.h" location="global"/>
</object-type>
+ <namespace-type name="Quick">
+ <object-type name="QQmlAspectEngine">
+ <enum-type name="Status"/>
+ </object-type>
+ </namespace-type>
</namespace-type>
</typesystem>
diff --git a/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml b/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml
index dd72c5c01..ebac94f03 100644
--- a/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml
+++ b/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml
@@ -45,7 +45,9 @@
<namespace-type name="Qt3DInput">
<object-type name="QAbstractActionInput"/>
<object-type name="QAbstractAxisInput"/>
- <object-type name="QAbstractPhysicalDevice"/>
+ <object-type name="QAbstractPhysicalDevice">
+ <enum-type name="DeviceStatus"/>
+ </object-type>
<object-type name="QAction"/>
<object-type name="QActionInput"/>
<object-type name="QAnalogAxisInput"/>
@@ -57,29 +59,34 @@
<object-type name="QButtonAxisInput"/>
<object-type name="QInputAspect"/>
<object-type name="QInputChord"/>
+ <!-- On windows this raises the following error:
+ type 'Qt3DInput::QInputDeviceIntegration' is specified in typesystem, but not defined.
+ This could potentially lead to compilation errors.
+ <object-type name="QInputDeviceIntegration"/>
+ -->
<object-type name="QInputSequence"/>
<object-type name="QInputSettings"/>
+ <object-type name="QKeyboardDevice"/>
<object-type name="QKeyboardHandler"/>
- <object-type name="QKeyEvent">
- <modify-function signature="QKeyEvent(const Qt3DInput::QKeyEvent&amp;)" remove="all"/>
- </object-type>
+ <object-type name="QKeyEvent"/>
<object-type name="QLogicalDevice"/>
- <object-type name="QKeyboardDevice"/>
<object-type name="QMouseDevice">
<enum-type name="Axis"/>
</object-type>
- <!-- Fixme: shiboken2 mistakenly thinks that Qt3DInput::QMouseEvent(::QMouseEvent)
- is a copy constructor of Qt3DInput::QMouseEvent. Work around by suppressing them -->
<object-type name="QMouseEvent">
<enum-type name="Buttons"/>
<enum-type name="Modifiers"/>
- <modify-function signature="QMouseEvent(const Qt3DInput::QMouseEvent&amp;)" remove="all"/>
</object-type>
<object-type name="QWheelEvent">
<enum-type name="Buttons"/>
<enum-type name="Modifiers"/>
- <modify-function signature="QWheelEvent(const Qt3DInput::QWheelEvent&amp;)" remove="all"/>
</object-type>
<object-type name="QMouseHandler"/>
+ <!-- On windows this raise the following error:
+ qt3dinput_module_wrapper.cpp.obj : error LNK2019:
+ unresolved external symbol "void __cdecl init_Qt3DInput_QPhysicalDeviceCreatedChangeBase(struct _object *)"
+ (?init_Qt3DInput_QPhysicalDeviceCreatedChangeBase@@YAXPAU_object@@@Z) referenced in function _PyInit_Qt3DInput
+ <object-type name="QPhysicalDeviceCreatedChangeBase"/>
+ -->
</namespace-type>
</typesystem>
diff --git a/sources/pyside2/PySide2/QtCore/CMakeLists.txt b/sources/pyside2/PySide2/QtCore/CMakeLists.txt
index 1d0b7d413..e583bd0f4 100644
--- a/sources/pyside2/PySide2/QtCore/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtCore/CMakeLists.txt
@@ -16,6 +16,7 @@ ${QtCore_GEN_DIR}/qabstracteventdispatcher_timerinfo_wrapper.cpp
${QtCore_GEN_DIR}/qabstracteventdispatcher_wrapper.cpp
${QtCore_GEN_DIR}/qabstractitemmodel_wrapper.cpp
${QtCore_GEN_DIR}/qabstractlistmodel_wrapper.cpp
+${QtCore_GEN_DIR}/qabstractnativeeventfilter_wrapper.cpp
${QtCore_GEN_DIR}/qabstractproxymodel_wrapper.cpp
${QtCore_GEN_DIR}/qabstractstate_wrapper.cpp
${QtCore_GEN_DIR}/qabstracttablemodel_wrapper.cpp
@@ -28,6 +29,15 @@ ${QtCore_GEN_DIR}/qbuffer_wrapper.cpp
${QtCore_GEN_DIR}/qbytearray_wrapper.cpp
${QtCore_GEN_DIR}/qbytearraymatcher_wrapper.cpp
${QtCore_GEN_DIR}/qchildevent_wrapper.cpp
+${QtCore_GEN_DIR}/qcborarray_wrapper.cpp
+${QtCore_GEN_DIR}/qcborerror_wrapper.cpp
+${QtCore_GEN_DIR}/qcbormap_wrapper.cpp
+${QtCore_GEN_DIR}/qcborparsererror_wrapper.cpp
+${QtCore_GEN_DIR}/qcborstreamreader_wrapper.cpp
+${QtCore_GEN_DIR}/qcborstringresultstring_wrapper.cpp
+${QtCore_GEN_DIR}/qcborstringresultbytearray_wrapper.cpp
+${QtCore_GEN_DIR}/qcborstreamwriter_wrapper.cpp
+${QtCore_GEN_DIR}/qcborvalue_wrapper.cpp
${QtCore_GEN_DIR}/qcollator_wrapper.cpp
${QtCore_GEN_DIR}/qcollatorsortkey_wrapper.cpp
${QtCore_GEN_DIR}/qcommandlineoption_wrapper.cpp
diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
index 631403c3f..005fd0684 100644
--- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
+++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
@@ -180,6 +180,8 @@
<enum-type name="QtMsgType"/>
+ <enum-type name="QCborSimpleType" since="5.12"/>
+ <enum-type name="QCborKnownTags" since="5.12"/>
<primitive-type name="qint8"/>
<primitive-type name="qint16"/>
@@ -428,15 +430,15 @@
</add-conversion>
<add-conversion type="PyDict" check="PyDict_CheckExact(%in)">
QVariant ret = QVariant_convertToVariantMap(%in);
- %out = ret.isValid() ? ret : QVariant::fromValue&lt;PySide::PyObjectWrapper&gt;(%in);
+ %out = ret.isValid() ? ret : QVariant::fromValue(PySide::PyObjectWrapper(%in));
</add-conversion>
<add-conversion type="PyList" check="PyList_Check(%in)">
QVariant ret = QVariant_convertToVariantList(%in);
- %out = ret.isValid() ? ret : QVariant::fromValue&lt;PySide::PyObjectWrapper&gt;(%in);
+ %out = ret.isValid() ? ret : QVariant::fromValue(PySide::PyObjectWrapper(%in));
</add-conversion>
<add-conversion type="PyObject">
// Is a shiboken type not known by Qt
- %out = QVariant::fromValue&lt;PySide::PyObjectWrapper&gt;(%in);
+ %out = QVariant::fromValue(PySide::PyObjectWrapper(%in));
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -666,6 +668,39 @@
</conversion-rule>
</primitive-type>
+ <value-type name="QCborError" since="5.12">
+ <enum-type name="Code"/>
+ <include file-name="qcborcommon.h" location="global"/>
+ </value-type>
+
+ <value-type name="QCborParserError" since="5.12">
+ <include file-name="qcborvalue.h" location="global"/>
+ </value-type>
+
+ <value-type name="QCborValue" since="5.12">
+ <enum-type name="EncodingOption" flags="EncodingOptions"/>
+ <enum-type name="DiagnosticNotationOption" flags="DiagnosticNotationOptions"/>
+ <enum-type name="Type"/>
+ </value-type>
+ <value-type name="QCborArray" since="5.12"/>
+ <value-type name="QCborMap" since="5.12"/>
+
+ <object-type name="QCborStreamReader" since="5.12">
+ <enum-type name="StringResultCode"/>
+ <enum-type name="Type"/>
+ <include file-name="qcborstream.h" location="global"/>
+ <value-type name="StringResult" generate="no"/>
+ <!-- 64bit (qsizetype = long long) -->
+ <modify-function signature="readStringChunk(char*,long long)" remove="all"/>
+ <!-- 32bit (qsizetype = int) -->
+ <modify-function signature="readStringChunk(char*,int)" remove="all"/>
+ </object-type>
+ <typedef-type name="QCborStringResultString" source="QCborStreamReader::StringResult&lt;QString&gt;" since="5.12"/>
+ <typedef-type name="QCborStringResultByteArray" source="QCborStreamReader::StringResult&lt;QByteArray&gt;" since="5.12"/>
+ <object-type name="QCborStreamWriter" since="5.12">
+ <include file-name="qcborstream.h" location="global"/>
+ </object-type>
+
<primitive-type name="QJsonObject">
<conversion-rule>
<native-to-target>
@@ -907,9 +942,6 @@
<rejection class="" enum-name="QtValidLicenseForGuiModule"/>
<rejection class="" enum-name="QtValidLicenseForScriptModule"/>
<rejection class="" enum-name="QtValidLicenseForHelpModule"/>
- <rejection class="QAbstractEventDispatcher" function-name="filterEvent"/>
- <rejection class="QAbstractEventDispatcher" function-name="filterNativeEvent"/>
- <rejection class="QAbstractEventDispatcher" function-name="setEventFilter"/>
<!-- Internal -->
<rejection class="QAbstractFileEngine"/> <!--
<rejection class="QAbstractFileEngine" function-name="endEntryList"/>
@@ -964,7 +996,7 @@
<enum-type name="InputMethodHint" flags="InputMethodHints" since="4.6"/>
<enum-type name="InputMethodQuery" flags="InputMethodQueries" />
<enum-type name="EnterKeyType" since="5.6" />
- <enum-type name="ItemDataRole" force-integer="yes" />
+ <enum-type name="ItemDataRole"/>
<enum-type name="ItemFlag" flags="ItemFlags"/>
<enum-type name="ItemSelectionMode"/>
<enum-type name="ItemSelectionOperation" since="5.5" />
@@ -1012,11 +1044,6 @@
<enum-type name="WindowType" flags="WindowFlags"/>
<enum-type name="CursorMoveStyle" since="4.8" revision="4800"/>
- <!--### These functions are part of QtGui, not QtCore -->
- <modify-function signature="codecForHtml(const QByteArray&amp;)" remove="all"/>
- <modify-function signature="mightBeRichText(const QString&amp;)" remove="all"/>
- <modify-function signature="convertFromPlainText(const QString&amp;,Qt::WhiteSpaceMode)" remove="all"/>
- <!--### -->
</namespace-type>
<add-function signature="qAbs(double)" return-type="double">
@@ -1075,7 +1102,7 @@
qWarning() &lt;&lt; "Module atexit not found for registering __moduleShutdown";
PyErr_Clear();
}else{
- regFunc = PyObject_GetAttrString(atexit, "register");
+ regFunc.reset(PyObject_GetAttrString(atexit, "register"));
if (regFunc.isNull()) {
qWarning() &lt;&lt; "Function atexit.register not found for registering __moduleShutdown";
PyErr_Clear();
@@ -2072,7 +2099,7 @@
</object-type>
<object-type name="QAbstractItemModel">
- <enum-type name="CheckIndexOption" flags="CheckIndexOptions" class="yes" since="5.11"/>
+ <enum-type name="CheckIndexOption" flags="CheckIndexOptions" since="5.11"/>
<enum-type name="LayoutChangeHint" />
<!-- This function was replaced by a added function -->
<modify-function signature="createIndex(int,int,void*)const" remove="all"/>
@@ -2132,7 +2159,6 @@
<value-type name="QItemSelectionRange" hash-function="qHash">
</value-type>
- <primitive-type name="QModelIndexList"/>
<object-type name="QAbstractProxyModel" polymorphic-id-expression="qobject_cast&lt;QAbstractProxyModel*&gt;(%1)">
<extra-includes>
<include file-name="QItemSelection" location="global"/>
@@ -2141,9 +2167,6 @@
</extra-includes>
</object-type>
<object-type name="QSortFilterProxyModel">
- <!-- ### This reimplementation of "QObject::parent()" is used in C++ only
- when "using QObject::parent;" is not available. It's useless in Python. -->
- <modify-function signature="parent()const" remove="all"/>
<extra-includes>
<include file-name="QItemSelection" location="global"/>
<include file-name="QStringList" location="global"/>
@@ -2734,12 +2757,12 @@
}
</inject-code>
</modify-function>
- <add-function signature="QByteArray(PyByteArray)" allow-thread="yes">>
+ <add-function signature="QByteArray(PyByteArray)">
<inject-code class="target" position="beginning">
%0 = new QByteArray(PyByteArray_AsString(%PYARG_1), PyByteArray_Size(%PYARG_1));
</inject-code>
</add-function>
- <add-function signature="QByteArray(PyBytes)" allow-thread="yes">
+ <add-function signature="QByteArray(PyBytes)">
<inject-code class="target" position="beginning">
%0 = new QByteArray(PyBytes_AS_STRING(%PYARG_1), PyBytes_GET_SIZE(%PYARG_1));
</inject-code>
@@ -2956,6 +2979,26 @@
<object-type name="QXmlStreamEntityResolver"/>
<!-- Qt5: had to move QAbstractEventDispatcher into os-specific files because of Windows -->
+ <object-type name="QAbstractNativeEventFilter">
+ <!-- see QWidget::nativeEvent(), QWindow::nativeEvent() -->
+ <modify-function signature="nativeEventFilter(const QByteArray&amp;,void*,long*)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion_variables"/>
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject"/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion"/>
+ </conversion-rule>
+ </modify-argument>
+ <inject-code position="end">
+ <insert-template name="return_native_eventfilter"/>
+ </inject-code>
+ </modify-function>
+ </object-type>
<object-type name="QEventLoop">
<enum-type name="ProcessEventsFlag" flags="ProcessEventsFlags"/>
@@ -3445,31 +3488,6 @@
<define-ownership owner="c++"/>
</modify-argument>
</modify-function>
- <modify-function signature="winEventFilter(MSG*,long*)">
- <modify-argument index="2">
- <remove-argument />
- <conversion-rule class="native">
- long *%out = new long;
- %out = 0;
- </conversion-rule>
- </modify-argument>
- <modify-argument index="return">
- <replace-type modified-type="PyObject"/>
- <conversion-rule class="native">
- %RETURN_TYPE %out = false;
- if (PySequence_Check(%PYARG_0) &amp;&amp; (PySequence_Size(%PYARG_0) == 2)) {
- Shiboken::AutoDecRef pyResult(PySequence_GetItem(%PYARG_0, 0));
- %out = %CONVERTTOCPP[bool](pyResult);
- }
- </conversion-rule>
- </modify-argument>
- <inject-code position="end">
- %PYARG_0 = PyTuple_New(2);
- PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%RETURN_TYPE](%0));
- PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[long](*result_out));
- delete result_out;
- </inject-code>
- </modify-function>
</object-type>
<object-type name="QSettings">
<enum-type name="Format"/>
@@ -3494,10 +3512,9 @@
</modify-function>
</object-type>
<object-type name="QEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::None">
- <enum-type name="Type" extensible="yes" />
+ <enum-type name="Type"/>
</object-type>
<object-type name="QChildEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::ChildAdded || %1-&gt;type() == QEvent::ChildPolished || %1-&gt;type() == QEvent::ChildRemoved">
- <modify-field name="c" read="false" write="false"/>
<modify-function signature="child()const">
<modify-argument index="return">
<define-ownership class="target" owner="default"/>
@@ -3949,9 +3966,6 @@
</modify-function>
<!-- This isn't part of Qt public API -->
<modify-function signature="enclosingMetaObject()const" remove="all" />
- <!-- Qt5.5: "template<typename T> static QMetaEnum fromType()" is not understood by the compiler.
- We therefore ignore this 5.5 addition for now: -->
- <modify-function signature="fromType()" since="5.5" remove="all" />
</value-type>
<!-- From Qt4.6 -->
@@ -4392,28 +4406,30 @@ s1.addTransition(button.clicked, s1h)&lt;/code>
<suppress-warning text="unhandled enum value: (sizeof(void*)&lt;&lt;3) in QSysInfo::Sizes"/>
<suppress-warning text="unmatched enum ~0u"/>
<suppress-warning text="unmatched enum (sizeof(void*)&lt;&lt;3)"/>
- <suppress-warning text="signature 'setCustomType(float)' for function modification in 'QEasingCurve' not found. Possible candidates: setCustomType(double) in QEasingCurve"/>
+ <suppress-warning text="^signature 'setCustomType(float)' for function modification in 'QEasingCurve' not found.*$"/>
<suppress-warning text="enum 'enum_4' does not have a type entry or is not an enum" />
<suppress-warning text="enum 'enum_5' does not have a type entry or is not an enum" />
<suppress-warning text="enum 'FP_NORMAL' does not have a type entry or is not an enum" />
<suppress-warning text="Shadowing: *" />
+ <!-- QCborStreamReader: Suppress warnings about 32/64bit signatures not found depending on qsizetype -->
+ <suppress-warning text="^signature 'readStringChunk\(char.*in 'QCborStreamReader' not found.*$"/>
<!-- this enum is defined on Qt global header but only used in QtGui module -->
<suppress-warning text="enum 'PM_MessageBoxHeight' does not have a type entry or is not an enum" />
<!-- this function only exists on Windows -->
- <suppress-warning text="signature 'winEventFilter(MSG*,long*)' for function modification in 'QCoreApplication' not found. Possible candidates:*"/>
+ <suppress-warning text="^signature 'winEventFilter(MSG*,long*)' for function modification in 'QCoreApplication' not found.*"/>
<!-- this is necessary to avoid warning on other modules -->
- <suppress-warning text="signature 'operator*(QByteArray,const char*)' for function modification in 'QByteArray' not found. Possible candidates:*"/>
- <suppress-warning text="signature 'operator+(QByteArray,QString)' for function modification in 'QByteArray' not found. Possible candidates:*"/>
+ <suppress-warning text="^signature 'operator*(QByteArray,const char*)' for function modification in 'QByteArray' not found.*"/>
+ <suppress-warning text="^signature 'operator+(QByteArray,QString)' for function modification in 'QByteArray' not found.*"/>
<!-- This enum is intenaly used -->
<suppress-warning text="enum 'PM_CbaIconHeight' does not have a type entry or is not an enum" />
<!-- TODO: this need be removed -->
- <suppress-warning text="skipping function '*', unmatched return type '*'"/>
- <suppress-warning text="skipping function '*', unmatched type '*"/>
+ <suppress-warning text="^skipping function '.*', unmatched return type '.*$"/>
+ <suppress-warning text="^skipping function '.*', unmatched type '.*$"/>
<suppress-warning text="enum 'q_static_assert_result39' does not have a type entry or is not an enum"/>
<suppress-warning text="horribly broken type ''"/>
@@ -4432,7 +4448,7 @@ s1.addTransition(button.clicked, s1h)&lt;/code>
<suppress-warning text="enum 'Role' does not have a type entry or is not an enum" />
<!-- Anonymous enum in qtbase/src/corelib/global/qtypeinfo.h -->
- <suppress-warning text="enum 'Q_RELOCATABLE_TYPE' does not have a type entry or is not an enum" />
+ <suppress-warning text="Anonymous enum (Q_COMPLEX_TYPE, ... , Q_RELOCATABLE_TYPE) does not have a type entry"/>
<!-- Another anonymous enum / value pair in in qtbase/src/corelib/kernel/qcoreapplication.h -->
<suppress-warning text="no matching enum 'QT_VERSION'" />
diff --git a/sources/pyside2/PySide2/QtGui/CMakeLists.txt b/sources/pyside2/PySide2/QtGui/CMakeLists.txt
index 1fe743c01..b330a63bf 100644
--- a/sources/pyside2/PySide2/QtGui/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtGui/CMakeLists.txt
@@ -2,11 +2,9 @@ project(QtGui)
qt5_wrap_cpp(QPYTEXTOBJECT_MOC "${pyside2_SOURCE_DIR}/qpytextobject.h")
-set(QtGui_OPTIONAL_SRC)
set(QtGui_DROPPED_ENTRIES)
-check_qt_class(QtGui QOpenGLTimeMonitor QtGui_OPTIONAL_SRC QtGui_DROPPED_ENTRIES)
-check_qt_class(QtGui QOpenGLTimerQuery QtGui_OPTIONAL_SRC QtGui_DROPPED_ENTRIES)
+get_property(QtGui_enabled_features TARGET Qt5::Gui PROPERTY INTERFACE_QT_ENABLED_FEATURES)
set(QtGui_SRC
${QtGui_GEN_DIR}/qabstractopenglfunctions_wrapper.cpp
@@ -207,11 +205,23 @@ ${QtGui_GEN_DIR}/qwhatsthisclickedevent_wrapper.cpp
${QtGui_GEN_DIR}/qwheelevent_wrapper.cpp
${QtGui_GEN_DIR}/qwindow_wrapper.cpp
${QtGui_GEN_DIR}/qwindowstatechangeevent_wrapper.cpp
-${QtGui_OPTIONAL_SRC}
# module is always needed
${QtGui_GEN_DIR}/qtgui_module_wrapper.cpp
)
+# cf qtbase/src/gui/opengl/opengl.pri
+list(FIND QtGui_enabled_features "opengles2" _opengles2Index)
+# ### fixme: For cmake >= 3.3: if(opengles2 IN_LIST QtGui_enabled_features)
+if(_opengles2Index GREATER -1)
+ list(APPEND QtGui_DROPPED_ENTRIES QOpenGLTimeMonitor QOpenGLTimerQuery)
+ message(STATUS "Qt5Gui: Dropping Desktop OpenGL classes (GLES2)")
+else()
+ list(APPEND QtGui_SRC
+ ${QtGui_GEN_DIR}/qopengltimemonitor_wrapper.cpp
+ ${QtGui_GEN_DIR}/qopengltimerquery_wrapper.cpp)
+ message(STATUS "Qt5Gui: Adding Desktop OpenGL classes")
+endif()
+
configure_file("${QtGui_SOURCE_DIR}/typesystem_gui.xml.in"
"${QtGui_BINARY_DIR}/typesystem_gui.xml" @ONLY)
diff --git a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
index 70fd1692a..e2e3b2335 100644
--- a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
+++ b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
@@ -97,21 +97,21 @@
<rejection class="*" function-name="d_func"/>
<rejection class="*" field-name="d_ptr"/>
<rejection class="*" field-name="d"/>
- <rejection class="^QOpenGL.*$" argument-type="^GLboolean( const)?\*$"/>
+ <rejection class="^QOpenGL.*$" argument-type="^(const )?GLboolean ?\*$"/>
<rejection class="^QOpenGL.*$" argument-type="^GLchar\*$"/>
- <rejection class="^QOpenGL.*$" argument-type="GLchar *const const*"/>
+ <rejection class="^QOpenGL.*$" argument-type="^(const )?GLchar ?\*(const)?\*$"/>
<rejection class="^QOpenGL.*$" argument-type="^char\*$"/>
- <rejection class="^QOpenGL.*$" argument-type="^char( const)?\*\*$"/>
+ <rejection class="^QOpenGL.*$" argument-type="^(const )?char ?\*\*$"/>
<rejection class="^QOpenGL.*$" argument-type="GLintptr"/>
<rejection class="^QOpenGL.*$" argument-type="GLsizeiptr"/>
<rejection class="^QOpenGL.*$" argument-type="GLsync"/>
<rejection class="^QOpenGL.*$" argument-type="^GLubyte( const)?\*$"/>
- <rejection class="^QOpenGL.*$" argument-type="^QMatrix.x.( const)?\*$"/>
+ <rejection class="^QOpenGL.*$" argument-type="^(const )?QMatrix.x. ?\*$"/>
<rejection class="^QOpenGL.*$" argument-type="qopengl_GLintptr"/>
<rejection class="^QOpenGL.*$" argument-type="qopengl_GLsizeiptr"/>
<rejection class="^QOpenGL.*$" argument-type="QOpenGLTextureHelper*"/>
- <rejection class="^QOpenGL.*$" argument-type="^QVector.D( const)?\*$"/>
- <rejection class="^QOpenGL.*$" argument-type="^void( const)?\*\*$"/>
+ <rejection class="^QOpenGL.*$" argument-type="^(const )?QVector.D ?\*$"/>
+ <rejection class="^QOpenGL.*$" argument-type="^(const )?void ?\*\*$"/>
<!--
Event classes have a lot of non-documented protected fields, those fields
@@ -395,7 +395,6 @@
<value-type name="QTextFrameFormat" >
<enum-type name="BorderStyle"/>
<enum-type name="Position"/>
- <modify-function signature="isValid()const" access="non-final"/>
</value-type>
<value-type name="QTextLength">
<enum-type name="Type"/>
@@ -403,9 +402,6 @@
<value-type name="QPainterPath">
<enum-type name="ElementType"/>
<value-type name="Element">
- <modify-field name="x" write="false"/>
- <modify-field name="y" write="false"/>
- <modify-field name="type" write="false"/>
<include file-name="QPainterPath" location="global"/>
</value-type>
</value-type>
@@ -554,14 +550,12 @@
<enum-type name="FontPropertiesInheritanceBehavior"/>
<enum-type name="UnderlineStyle"/>
<enum-type name="VerticalAlignment"/>
- <modify-function signature="isValid()const" access="non-final"/>
</value-type>
<value-type name="QTextFormat" >
<enum-type name="FormatType"/>
<enum-type name="ObjectTypes"/>
<enum-type name="PageBreakFlag" flags="PageBreakFlags"/>
<enum-type name="Property" />
- <modify-function signature="isValid()const" access="non-final"/>
</value-type>
<value-type name="QTextListFormat">
<enum-type name="Style"/>
@@ -668,7 +662,7 @@
%0 = new %TYPE(QPixmap::fromImage(%1));
</inject-code>
</add-function>
- <modify-function signature="QPixmap(const char*[])">
+ <modify-function signature="QPixmap(const char*const[])">
<modify-argument index="1">
<replace-type modified-type="PySequence" />
</modify-argument>
@@ -897,7 +891,7 @@
<modify-function signature="QImage(const uchar*,int,int,QImage::Format,QImageCleanupFunction,void*)" remove="all" />
<!-- ### -->
- <modify-function signature="QImage(const char*[])">
+ <modify-function signature="QImage(const char*const[])">
<modify-argument index="1">
<replace-type modified-type="PySequence" />
</modify-argument>
@@ -1507,10 +1501,11 @@
</inject-code>
</modify-function>
</value-type>
- <value-type name="QGradient" force-abstract="yes" polymorphic-id-expression="%1-&gt;type() == QGradient::NoGradient">
+ <value-type name="QGradient" polymorphic-id-expression="%1-&gt;type() == QGradient::NoGradient">
<enum-type name="CoordinateMode"/>
<enum-type name="InterpolationMode"/>
- <enum-type name="Spread" lower-bound="QGradient.PadSpread" upper-bound="QGradient.RepeatSpread"/>
+ <enum-type name="Preset" since="5.12"/>
+ <enum-type name="Spread"/>
<enum-type name="Type"/>
</value-type>
<value-type name="QLinearGradient" polymorphic-id-expression="%1-&gt;type() == QGradient::LinearGradient" />
@@ -1741,7 +1736,7 @@
else
qWarning("%TYPE::%FUNCTION_NAME: Second tuple element is not convertible to int.");
}
- %PYARG_0 = PySequence_Fast_GET_ITEM(seq.object(), 0);
+ %PYARG_0.reset(PySequence_Fast_GET_ITEM(seq.object(), 0));
Py_INCREF(%PYARG_0); // we need to incref, because "%PYARG_0 = ..." will decref the tuple and the tuple will be decrefed again at the end of this scope.
}
@@ -1835,9 +1830,7 @@
<suppress-warning text="enum 'QWheelEvent::DefaultDeltasPerStep' does not have a type entry or is not an enum" />
<object-type name="QWindowStateChangeEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::WindowStateChange"/>
- <object-type name="QInputEvent" copyable="false">
- <modify-function signature="modifiers()const" access="non-final"/>
- </object-type>
+ <object-type name="QInputEvent" copyable="false"/>
<object-type name="QKeyEvent" copyable= "false" polymorphic-id-expression="%1-&gt;type() == QEvent::KeyPress || %1-&gt;type() == QEvent::KeyRelease || %1-&gt;type() == QEvent::ShortcutOverride">
<add-function signature="operator!=(QKeySequence::StandardKey)">
<inject-code class="target">
@@ -2237,7 +2230,6 @@
</extra-includes>
<!-- ### "setPaintDevice(QPaintDevice*)" is an internal method. -->
<modify-function signature="setPaintDevice(QPaintDevice*)" remove="all"/>
- <modify-field name="state" read="false" write="false"/>
</object-type>
<object-type name="QPainter">
<extra-includes>
@@ -2388,7 +2380,12 @@
</modify-function>
</object-type>
+ <value-type name="QGenericMatrix" generate="no"/>
<value-type name="QMatrix2x2" since="4.6">
+ <modify-function signature="QMatrix2x2(const float*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
+ <modify-function signature="copyDataTo(float*) const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2420,63 +2417,13 @@
</insert-template>
</inject-code>
</add-function>
- <add-function signature="fill(PyObject*)">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_fill_function">
- <replace from="%MATRIX_SIZE" to="4" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="transposed()" return-type="PyObject">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_transposed_function">
- <replace from="%TRANSPOSED_TYPE" to="QMatrix2x2" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="operator!=(const QMatrix2x2&amp;)" return-type="bool" />
-
- <template name="inplace_add">
- *%CPPSELF += %1;
- return %CONVERTTOPYTHON[%RETURN_TYPE](*%CPPSELF);
- </template>
- <template name="inplace_sub">
- *%CPPSELF -= %1;
- return %CONVERTTOPYTHON[%RETURN_TYPE](*%CPPSELF);
- </template>
- <template name="inplace_mult">
- *%CPPSELF *= %1;
- return %CONVERTTOPYTHON[%RETURN_TYPE](*%CPPSELF);
- </template>
- <template name="inplace_div">
- *%CPPSELF /= %1;
- return %CONVERTTOPYTHON[%RETURN_TYPE](*%CPPSELF);
- </template>
-
- <add-function signature="operator*=(float)" return-type="QMatrix2x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_mult"/>
- </inject-code>
- </add-function>
- <add-function signature="operator+=(const QMatrix2x2&amp;)" return-type="QMatrix2x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_add"/>
- </inject-code>
- </add-function>
- <add-function signature="operator-=(const QMatrix2x2&amp;)" return-type="QMatrix2x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_sub"/>
- </inject-code>
- </add-function>
- <add-function signature="operator/=(float)" return-type="QMatrix2x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_div"/>
- </inject-code>
- </add-function>
- <add-function signature="operator==(const QMatrix2x2&amp;)" return-type="bool" />
</value-type>
<value-type name="QMatrix2x3" since="4.6">
+ <modify-function signature="QMatrix2x3(const float*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
+ <modify-function signature="copyDataTo(float*) const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2508,45 +2455,13 @@
</insert-template>
</inject-code>
</add-function>
- <add-function signature="fill(PyObject*)">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_fill_function">
- <replace from="%MATRIX_SIZE" to="6" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="transposed()" return-type="PyObject">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_transposed_function">
- <replace from="%TRANSPOSED_TYPE" to="QMatrix3x2" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="operator!=(const QMatrix2x3&amp;)" return-type="bool" />
- <add-function signature="operator*=(float)" return-type="QMatrix2x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_mult"/>
- </inject-code>
- </add-function>
- <add-function signature="operator+=(const QMatrix2x3&amp;)" return-type="QMatrix2x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_add"/>
- </inject-code>
- </add-function>
- <add-function signature="operator-=(const QMatrix2x3&amp;)" return-type="QMatrix2x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_sub"/>
- </inject-code>
- </add-function>
- <add-function signature="operator/=(float)" return-type="QMatrix2x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_div"/>
- </inject-code>
- </add-function>
- <add-function signature="operator==(const QMatrix2x3&amp;)" return-type="bool" />
</value-type>
<value-type name="QMatrix2x4" since="4.6">
+ <modify-function signature="QMatrix2x4(const float*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
+ <modify-function signature="copyDataTo(float*) const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2578,45 +2493,13 @@
</insert-template>
</inject-code>
</add-function>
- <add-function signature="fill(PyObject*)">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_fill_function">
- <replace from="%MATRIX_SIZE" to="8" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="transposed()" return-type="PyObject">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_transposed_function">
- <replace from="%TRANSPOSED_TYPE" to="QMatrix4x2" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="operator!=(const QMatrix2x4&amp;)" return-type="bool" />
- <add-function signature="operator*=(float)" return-type="QMatrix2x4" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_mult"/>
- </inject-code>
- </add-function>
- <add-function signature="operator+=(const QMatrix2x4&amp;)" return-type="QMatrix2x4" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_add"/>
- </inject-code>
- </add-function>
- <add-function signature="operator-=(const QMatrix2x4&amp;)" return-type="QMatrix2x4" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_sub"/>
- </inject-code>
- </add-function>
- <add-function signature="operator/=(float)" return-type="QMatrix2x4" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_div"/>
- </inject-code>
- </add-function>
- <add-function signature="operator==(const QMatrix2x4&amp;)" return-type="bool" />
</value-type>
<value-type name="QMatrix3x2" since="4.6">
+ <modify-function signature="QMatrix3x2(const float*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
+ <modify-function signature="copyDataTo(float*) const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2648,45 +2531,13 @@
</insert-template>
</inject-code>
</add-function>
- <add-function signature="fill(PyObject*)">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_fill_function">
- <replace from="%MATRIX_SIZE" to="6" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="transposed()" return-type="PyObject">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_transposed_function">
- <replace from="%TRANSPOSED_TYPE" to="QMatrix2x3" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="operator!=(const QMatrix3x2&amp;)" return-type="bool" />
- <add-function signature="operator*=(float)" return-type="QMatrix3x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_mult"/>
- </inject-code>
- </add-function>
- <add-function signature="operator+=(const QMatrix3x2&amp;)" return-type="QMatrix3x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_add"/>
- </inject-code>
- </add-function>
- <add-function signature="operator-=(const QMatrix3x2&amp;)" return-type="QMatrix3x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_sub"/>
- </inject-code>
- </add-function>
- <add-function signature="operator/=(float)" return-type="QMatrix3x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_div"/>
- </inject-code>
- </add-function>
- <add-function signature="operator==(const QMatrix3x2&amp;)" return-type="bool" />
</value-type>
<value-type name="QMatrix3x3" since="4.6">
+ <modify-function signature="QMatrix3x3(const float*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
+ <modify-function signature="copyDataTo(float*) const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2718,45 +2569,13 @@
</insert-template>
</inject-code>
</add-function>
- <add-function signature="fill(PyObject*)">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_fill_function">
- <replace from="%MATRIX_SIZE" to="9" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="transposed()" return-type="PyObject">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_transposed_function">
- <replace from="%TRANSPOSED_TYPE" to="QMatrix3x3" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="operator!=(const QMatrix3x3&amp;)" return-type="bool" />
- <add-function signature="operator*=(float)" return-type="QMatrix3x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_mult"/>
- </inject-code>
- </add-function>
- <add-function signature="operator+=(const QMatrix3x3&amp;)" return-type="QMatrix3x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_add"/>
- </inject-code>
- </add-function>
- <add-function signature="operator-=(const QMatrix3x3&amp;)" return-type="QMatrix3x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_sub"/>
- </inject-code>
- </add-function>
- <add-function signature="operator/=(float)" return-type="QMatrix3x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_div"/>
- </inject-code>
- </add-function>
- <add-function signature="operator==(const QMatrix3x3&amp;)" return-type="bool" />
</value-type>
<value-type name="QMatrix3x4" since="4.6">
+ <modify-function signature="QMatrix3x4(const float*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
+ <modify-function signature="copyDataTo(float*) const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2788,45 +2607,12 @@
</insert-template>
</inject-code>
</add-function>
- <add-function signature="fill(PyObject*)">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_fill_function">
- <replace from="%MATRIX_SIZE" to="12" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="transposed()" return-type="PyObject">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_transposed_function">
- <replace from="%TRANSPOSED_TYPE" to="QMatrix4x3" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="operator!=(const QMatrix3x4&amp;)" return-type="bool" />
- <add-function signature="operator*=(float)" return-type="QMatrix3x4" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_mult"/>
- </inject-code>
- </add-function>
- <add-function signature="operator+=(const QMatrix3x4&amp;)" return-type="QMatrix3x4" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_add"/>
- </inject-code>
- </add-function>
- <add-function signature="operator-=(const QMatrix3x4&amp;)" return-type="QMatrix3x4" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_sub"/>
- </inject-code>
- </add-function>
- <add-function signature="operator/=(float)" return-type="QMatrix3x4" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_div"/>
- </inject-code>
- </add-function>
- <add-function signature="operator==(const QMatrix3x4&amp;)" return-type="bool" />
</value-type>
<value-type name="QMatrix4x2" since="4.6">
+ <modify-function signature="QMatrix4x2(const float*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2858,45 +2644,13 @@
</insert-template>
</inject-code>
</add-function>
- <add-function signature="fill(PyObject*)">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_fill_function">
- <replace from="%MATRIX_SIZE" to="8" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="transposed()" return-type="PyObject">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_transposed_function">
- <replace from="%TRANSPOSED_TYPE" to="QMatrix2x4" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="operator!=(const QMatrix4x2&amp;)" return-type="bool" />
- <add-function signature="operator*=(float)" return-type="QMatrix4x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_mult"/>
- </inject-code>
- </add-function>
- <add-function signature="operator+=(const QMatrix4x2&amp;)" return-type="QMatrix4x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_add"/>
- </inject-code>
- </add-function>
- <add-function signature="operator-=(const QMatrix4x2&amp;)" return-type="QMatrix4x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_sub"/>
- </inject-code>
- </add-function>
- <add-function signature="operator/=(float)" return-type="QMatrix4x2" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_div"/>
- </inject-code>
- </add-function>
- <add-function signature="operator==(const QMatrix4x2&amp;)" return-type="bool" />
</value-type>
<value-type name="QMatrix4x3" since="4.6">
+ <modify-function signature="QMatrix4x3(const float*)">
+ <modify-argument index="1"><array/></modify-argument>
+ </modify-function>
+ <modify-function signature="copyDataTo(float*) const" remove="all"/>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code_matrix">
@@ -2928,47 +2682,10 @@
</insert-template>
</inject-code>
</add-function>
- <add-function signature="fill(PyObject*)">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_fill_function">
- <replace from="%MATRIX_SIZE" to="12" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="transposed()" return-type="PyObject">
- <inject-code class="target" position="beginning">
- <insert-template name="matrix_transposed_function">
- <replace from="%TRANSPOSED_TYPE" to="QMatrix3x4" />
- </insert-template>
- </inject-code>
- </add-function>
- <add-function signature="operator!=(const QMatrix4x3&amp;)" return-type="bool" />
- <add-function signature="operator*=(float)" return-type="QMatrix4x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_mult"/>
- </inject-code>
- </add-function>
- <add-function signature="operator+=(const QMatrix4x3&amp;)" return-type="QMatrix4x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_add"/>
- </inject-code>
- </add-function>
- <add-function signature="operator-=(const QMatrix4x3&amp;)" return-type="QMatrix4x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_sub"/>
- </inject-code>
- </add-function>
- <add-function signature="operator/=(float)" return-type="QMatrix4x3" >
- <inject-code class="target" position="beginning">
- <insert-template name="inplace_div"/>
- </inject-code>
- </add-function>
- <add-function signature="operator==(const QMatrix4x3&amp;)" return-type="bool" />
</value-type>
<value-type name="QMatrix4x4" since="4.6">
-
<!-- Qt5: HAIRY TRICK ALERT ahead!
Qt5 partially replaced 'qreal' by float.
That had the side effect that all matrix types did not work any longer.
@@ -2977,10 +2694,10 @@
The signature "QList<qreal>" is needed by the __reduce__ methods,
but created by some other object used elsewhere.
- After the matrix type was changed, "QList<float>" was nowhere created.
+ After the matrix type was changed, "QList<float>" was created nowhere.
I don't know an explicit way to produce the right conversion function, so what I did
- was to create a dummy function and immediately dele it again.
+ was to create a dummy function and immediately delete it again.
This has the desired effect of creating the implicitly needed "QList<float>"
conversion, although the dummy function goes away.
@@ -3266,12 +2983,29 @@
</extra-includes>
</primitive-type>
- <object-type name="QWindow">
+ <object-type name="QWindow" delete-in-main-thread="true">
<enum-type name="AncestorMode"/>
<enum-type name="Visibility"/>
+ <modify-function signature="raise()" rename="raise_" />
+ <!-- see QWidget::nativeEvent(), QAbstractNativeEventFilter::nativeEventFilter() -->
+ <modify-function signature="nativeEvent(const QByteArray &amp;,void*,long*)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion_variables"/>
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject"/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion"/>
+ </conversion-rule>
+ </modify-argument>
+ <inject-code position="end">
+ <insert-template name="return_native_eventfilter"/>
+ </inject-code>
+ </modify-function>
</object-type>
- <!-- Qt5: not sure if this needs support, skipped for now -->
- <rejection class="QWindow" function-name="nativeEvent"/>"
<object-type name="QGuiApplication">
<extra-includes>
@@ -3296,7 +3030,6 @@
}
</inject-code>
</add-function>
- <modify-function signature="exec()" rename="exec_" allow-thread="yes"/>
<inject-code class="native" file="glue/qguiapplication_init.cpp" position="beginning" />
</object-type>
diff --git a/sources/pyside2/PySide2/QtNetwork/CMakeLists.txt b/sources/pyside2/PySide2/QtNetwork/CMakeLists.txt
index 0267bfae3..a7c8dd8f6 100644
--- a/sources/pyside2/PySide2/QtNetwork/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtNetwork/CMakeLists.txt
@@ -1,23 +1,7 @@
project(QtNetwork)
-set(QtNetwork_OPTIONAL_SRC )
set(QtNetwork_DROPPED_ENTRIES )
-check_qt_class(QtNetwork QSslCertificate QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-check_qt_class(QtNetwork QSslCertificateExtension QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-check_qt_class(QtNetwork QSslCipher QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-check_qt_class(QtNetwork QSslConfiguration QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-check_qt_class(QtNetwork QSslDiffieHellmanParameters QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-# Problems with operator==(QSslEllipticCurve,QSslEllipticCurve)
-# check_qt_class(QtNetwork QSslEllipticCurve QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-check_qt_class(QtNetwork QSslError QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-check_qt_class(QtNetwork QSslKey QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-check_qt_class(QtNetwork QSslPreSharedKeyAuthenticator QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-check_qt_class(QtNetwork QSslSocket QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-
-check_qt_class(QtNetwork QSctpServer QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-check_qt_class(QtNetwork QSctpSocket QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
-
set(QtNetwork_SRC
${QtNetwork_GEN_DIR}/qabstractnetworkcache_wrapper.cpp
${QtNetwork_GEN_DIR}/qabstractsocket_wrapper.cpp
@@ -52,15 +36,63 @@ ${QtNetwork_GEN_DIR}/qnetworkproxyquery_wrapper.cpp
${QtNetwork_GEN_DIR}/qnetworkreply_wrapper.cpp
${QtNetwork_GEN_DIR}/qnetworkrequest_wrapper.cpp
${QtNetwork_GEN_DIR}/qnetworksession_wrapper.cpp
+${QtNetwork_GEN_DIR}/qpassworddigestor_wrapper.cpp
${QtNetwork_GEN_DIR}/qssl_wrapper.cpp
${QtNetwork_GEN_DIR}/qtcpserver_wrapper.cpp
${QtNetwork_GEN_DIR}/qtcpsocket_wrapper.cpp
${QtNetwork_GEN_DIR}/qudpsocket_wrapper.cpp
-${QtNetwork_OPTIONAL_SRC}
# module is always needed
${QtNetwork_GEN_DIR}/qtnetwork_module_wrapper.cpp
)
+get_property(QtNetwork_enabled_features TARGET Qt5::Network PROPERTY INTERFACE_QT_ENABLED_FEATURES)
+get_property(QtNetwork_disabled_features TARGET Qt5::Network PROPERTY INTERFACE_QT_DISABLED_FEATURES)
+
+# ### fixme: For cmake >= 3.3, use if( needle IN_LIST list)
+list(FIND QtNetwork_enabled_features "ssl" _sslEnabledIndex)
+list(FIND QtNetwork_disabled_features "dtls" _dtlsDisabledIndex)
+list(FIND QtNetwork_disabled_features "sctp" _sctpDisabledIndex)
+
+if(_sslEnabledIndex EQUAL -1)
+ list(APPEND QtNetwork_DROPPED_ENTRIES QSslCertificate QSslCertificateExtension
+ QSslCipher QSslConfiguration QSslDiffieHellmanParameters QSslError
+ QSslKey QSslPreSharedKeyAuthenticator QSslSocket)
+ message(STATUS "Qt5Network: Dropping SSL classes")
+else()
+ # Problems with operator==(QSslEllipticCurve,QSslEllipticCurve)
+ # check_qt_class(QtNetwork QSslEllipticCurve QtNetwork_OPTIONAL_SRC QtNetwork_DROPPED_ENTRIES)
+ list(APPEND QtNetwork_SRC
+ ${QtNetwork_GEN_DIR}/qsslcertificate_wrapper.cpp
+ ${QtNetwork_GEN_DIR}/qsslcertificateextension_wrapper.cpp
+ ${QtNetwork_GEN_DIR}/qsslcipher_wrapper.cpp
+ ${QtNetwork_GEN_DIR}/qsslconfiguration_wrapper.cpp
+ ${QtNetwork_GEN_DIR}/qssldiffiehellmanparameters_wrapper.cpp
+ ${QtNetwork_GEN_DIR}/qsslerror_wrapper.cpp
+ ${QtNetwork_GEN_DIR}/qsslkey_wrapper.cpp
+ ${QtNetwork_GEN_DIR}/qsslpresharedkeyauthenticator_wrapper.cpp
+ ${QtNetwork_GEN_DIR}/qsslsocket_wrapper.cpp)
+ message(STATUS "Qt5Network: Adding SSL classes")
+endif()
+
+if(_dtlsDisabledIndex GREATER -1)
+ list(APPEND QtNetwork_DROPPED_ENTRIES QDtls)
+ message(STATUS "Qt5Network: Dropping DTLS classes")
+else()
+ list(APPEND QtNetwork_SRC
+ ${QtNetwork_GEN_DIR}/qdtls_wrapper.cpp)
+ message(STATUS "Qt5Network: Adding DTLS classes")
+endif()
+
+if(_sctpDisabledIndex GREATER -1)
+ list(APPEND QtNetwork_DROPPED_ENTRIES QSctpServer QSctpSocket)
+ message(STATUS "Qt5Network: Dropping SCTP classes")
+else()
+ list(APPEND QtNetwork_SRC
+ ${QtNetwork_GEN_DIR}/qsctpserver_wrapper.cpp
+ ${QtNetwork_GEN_DIR}/qsctpsocket_wrapper.cpp)
+ message(STATUS "Qt5Network: Adding SCTP classes")
+endif()
+
set(QtNetwork_include_dirs ${QtNetwork_SOURCE_DIR}
${QtNetwork_BINARY_DIR}
${Qt5Core_INCLUDE_DIRS}
diff --git a/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml b/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml
index e4235e070..d277b3228 100644
--- a/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml
+++ b/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml
@@ -42,6 +42,14 @@
<typesystem package="PySide2.QtNetwork">
<load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
+ <enum-type name="QDtlsError" since="5.12"/>
+
+ <namespace-type name="QPasswordDigestor" since="5.12">
+ <extra-includes>
+ <include file-name="qpassworddigestor.h" location="global"/>
+ </extra-includes>
+ </namespace-type>
+
<namespace-type name="QSsl">
<enum-type name="AlternativeNameEntryType"/>
<enum-type name="EncodingFormat"/>
@@ -80,6 +88,11 @@
<value-type name="QDnsMailExchangeRecord"/>
<value-type name="QDnsServiceRecord"/>
<value-type name="QDnsTextRecord"/>
+
+ <object-type name="QDtls" since="5.12">
+ <enum-type name="HandshakeState"/>
+ </object-type>
+
<value-type name="QHstsPolicy" since="5.9">
<enum-type name="PolicyFlag" flags="PolicyFlags"/>
</value-type>
@@ -275,7 +288,7 @@
</extra-includes>
</value-type>
<value-type name="QNetworkRequest">
- <enum-type name="Attribute" extensible="yes"/>
+ <enum-type name="Attribute"/>
<enum-type name="LoadControl" since="4.7"/>
<enum-type name="Priority" since="4.7"/>
<enum-type name="CacheLoadControl"/>
diff --git a/sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml b/sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml
index ea5c24cd3..c332eea0d 100644
--- a/sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml
+++ b/sources/pyside2/PySide2/QtOpenGL/typesystem_opengl.xml
@@ -59,19 +59,19 @@
<rejection class="QGLColormap::QGLColormapData"/>
<rejection class="QGLContext" field-name="currentCtx"/>
- <rejection class="^QGL.*$" argument-type="^GLboolean( const)?\*$"/>
- <rejection class="^QGL.*$" argument-type="^GLchar( const)?\*$"/>
- <rejection class="^QGL.*$" argument-type="GLchar *const const*"/>
- <rejection class="^QGL.*$" argument-type="^GLenum( const)?\*$"/>
- <rejection class="^QGL.*$" argument-type="^GLfloat( const)?\*$"/>
- <rejection class="^QGL.*$" argument-type="^GLfloat( const)?\[.*$"/>
- <rejection class="^QGL.*$" argument-type="^GLdouble( const)?\*$"/>
+ <rejection class="^QGL.*$" argument-type="^(const )?GLboolean ?\*$"/>
+ <rejection class="^QGL.*$" argument-type="^(const )?GLchar ?\*$"/>
+ <rejection class="^QGL.*$" argument-type="^(const )?GLchar ?\*const"/>
+ <rejection class="^QGL.*$" argument-type="^(const )?GLenum ?\*$"/>
+ <rejection class="^QGL.*$" argument-type="^(const )?GLfloat ?\*$"/>
+ <rejection class="^QGL.*$" argument-type="^(const )?GLfloat ?\[.*$"/>
+ <rejection class="^QGL.*$" argument-type="^(const )?GLdouble ?\*$"/>
<rejection class="^QGL.*$" argument-type="GLintptr"/>
- <rejection class="^QGL.*$" argument-type="^GLint64( const)?\*$"/>
- <rejection class="^QGL.*$" argument-type="^GLsizei( const)?\*$"/>
+ <rejection class="^QGL.*$" argument-type="^(const )?GLint64 ?\*$"/>
+ <rejection class="^QGL.*$" argument-type="^(const )?GLsizei ?\*$"/>
<namespace-type name="QGL">
- <enum-type name="FormatOption" flags="FormatOptions" force-integer="yes"/>
+ <enum-type name="FormatOption" flags="FormatOptions"/>
<extra-includes>
<include file-name="qgl.h" location="global"/>
</extra-includes>
@@ -683,16 +683,7 @@
</inject-code>
</modify-function>
- <!-- ### TODO: must evaluate if anything other than removal should be done. -->
- <modify-function signature="setAttributeArray(int,const GLfloat*,int,int)" remove="all" />
- <modify-function signature="setAttributeArray(const char*,const GLfloat*,int,int)" remove="all" />
- <modify-function signature="setUniformValueArray(int,const GLfloat*,int,int)" remove="all" />
- <modify-function signature="setUniformValueArray(const char*,const GLfloat*,int,int)" remove="all" />
- <!-- ### -->
-
<!-- ### Use QMatrixZxY overloads -->
- <modify-function signature="setAttributeValue(int,const GLfloat*,int,int)" remove="all" />
- <modify-function signature="setAttributeValue(const char*,const GLfloat*,int,int)" remove="all" />
<modify-function signature="setAttributeArray(int,GLenum,const void*,int,int)" remove="all" since="4.7" />
<modify-function signature="setAttributeArray(const char*,GLenum,const void*,int,int)" remove="all" since="4.7" />
<!-- ### -->
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
index 1a1f09511..9d9ddc799 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
@@ -44,6 +44,7 @@
// pyside
#include <pyside.h>
+#include <pyside_p.h>
#include <pysideproperty.h>
// auto generated headers
@@ -126,8 +127,7 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
return -1;
}
- QMetaObject *metaObject = reinterpret_cast<QMetaObject *>(
- ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType *>(pyObj)));
+ const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType);
Q_ASSERT(metaObject);
QQmlPrivate::RegisterType type;
@@ -172,13 +172,13 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
type.versionMajor = versionMajor;
type.versionMinor = versionMinor;
type.elementName = qmlName;
- type.metaObject = metaObject;
type.extensionObjectCreate = 0;
type.extensionMetaObject = 0;
type.customParser = 0;
++nextType;
}
+ type.metaObject = metaObject; // Snapshot may have changed.
int qmlTypeId = QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
if (qmlTypeId == -1) {
diff --git a/sources/pyside2/PySide2/QtQml/typesystem_qml.xml b/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
index 9a0d1e0ae..f5e3d36fc 100644
--- a/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
+++ b/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
@@ -157,7 +157,7 @@
<enum-type name="Status" />
</object-type>
<object-type name="QQmlIncubationController">
- <modify-function signature="incubateWhile(bool volatile*,int)" allow-thread="yes">
+ <modify-function signature="incubateWhile(volatile bool*,int)" allow-thread="yes">
<modify-argument index="1">
<!-- The replace type is needed to use the VolatileBool_Check macro instead of
a template conversion function with "volatile bool" as argument. -->
@@ -216,5 +216,5 @@
</modify-function>
</object-type>
<!-- Suppress anonymous enum warning -->
- <suppress-warning text="enum 'QmlCurrentSingletonTypeRegistrationVersion' does not have a type entry or is not an enum" />
+ <suppress-warning text="Anonymous enum (QmlCurrentSingletonTypeRegistrationVersion) does not have a type entry"/>
</typesystem>
diff --git a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp
index bf3ff06a2..93a8f281e 100644
--- a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp
+++ b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp
@@ -40,6 +40,7 @@
#include "pysidequickregistertype.h"
#include <pyside.h>
+#include <shiboken.h>
// Auto generated headers.
#include "qquickitem_wrapper.h"
diff --git a/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml b/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml
index 7e6b450c9..dde90166f 100644
--- a/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml
+++ b/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml
@@ -65,7 +65,7 @@
<object-type name="QQuickImageResponse" since="5.6" />
<object-type name="QQuickTransform" />
- <object-type name="QQuickItem">
+ <object-type name="QQuickItem" delete-in-main-thread="true">
<value-type name="UpdatePaintNodeData" />
<enum-type name="Flag" flags="Flags" />
<enum-type name="ItemChange" />
diff --git a/sources/pyside2/PySide2/QtSql/typesystem_sql.xml b/sources/pyside2/PySide2/QtSql/typesystem_sql.xml
index 1b6baa15f..3eab73307 100644
--- a/sources/pyside2/PySide2/QtSql/typesystem_sql.xml
+++ b/sources/pyside2/PySide2/QtSql/typesystem_sql.xml
@@ -101,7 +101,6 @@
<extra-includes>
<include file-name="QSqlField" location="global"/>
</extra-includes>
- <modify-function signature="append(QSqlField)" access="non-final"/>
</value-type>
<value-type name="QSqlError">
@@ -142,8 +141,6 @@
</object-type>
<object-type name="QSqlQueryModel">
- <modify-function signature="indexInQuery(QModelIndex)const" access="non-final"/>
- <modify-function signature="setQuery(QSqlQuery)" access="non-final"/>
<extra-includes>
<include file-name="QSqlError" location="global"/>
<include file-name="QSqlQuery" location="global"/>
diff --git a/sources/pyside2/PySide2/QtWidgets/CMakeLists.txt b/sources/pyside2/PySide2/QtWidgets/CMakeLists.txt
index dee79744f..6b8830a41 100644
--- a/sources/pyside2/PySide2/QtWidgets/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtWidgets/CMakeLists.txt
@@ -1,12 +1,5 @@
project(QtWidgets)
-
-set(QtWidgets_OPTIONAL_SRC )
-set(QtWidgets_DROPPED_ENTRIES )
-## XXX check if these conditionals need to be done elsewhere
-check_qt_class(QtWidgets QGtkStyle QtWidgets_OPTIONAL_SRC QtWidgets_DROPPED_ENTRIES)
-check_qt_class(QtWidgets QMacStyle QtWidgets_OPTIONAL_SRC QtWidgets_DROPPED_ENTRIES)
-
set(QtWidgets_SRC
${QtWidgets_GEN_DIR}/qaccessiblewidget_wrapper.cpp
${QtWidgets_GEN_DIR}/qabstractbutton_wrapper.cpp
diff --git a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
index 76b3dd1f1..d92540d85 100644
--- a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
+++ b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
@@ -74,7 +74,7 @@
-->
<object-type name="QStyleOption" polymorphic-id-expression="%1-&gt;type == QStyleOption::SO_Default">
- <enum-type name="OptionType" extensible="yes"/>
+ <enum-type name="OptionType"/>
<enum-type name="StyleOptionType"/>
<enum-type name="StyleOptionVersion"/>
</object-type>
@@ -1272,17 +1272,17 @@
</object-type>
<object-type name="QAbstractButton"/>
<object-type name="QStyle">
- <enum-type name="ComplexControl" extensible="yes"/>
- <enum-type name="ContentsType" extensible="yes"/>
- <enum-type name="ControlElement" extensible="yes"/>
- <enum-type name="PixelMetric" extensible="yes" />
- <enum-type name="PrimitiveElement" extensible="yes" />
+ <enum-type name="ComplexControl"/>
+ <enum-type name="ContentsType"/>
+ <enum-type name="ControlElement"/>
+ <enum-type name="PixelMetric"/>
+ <enum-type name="PrimitiveElement"/>
<enum-type name="RequestSoftwareInputPanel" since="4.6"/>
- <enum-type name="StandardPixmap" extensible="yes"/>
+ <enum-type name="StandardPixmap"/>
<enum-type name="StateFlag" flags="State"/>
- <enum-type name="StyleHint" extensible="yes" />
- <enum-type name="SubControl" flags="SubControls" extensible="yes" force-integer="yes"/>
- <enum-type name="SubElement" extensible="yes" />
+ <enum-type name="StyleHint"/>
+ <enum-type name="SubControl" flags="SubControls"/>
+ <enum-type name="SubElement"/>
<modify-function signature="drawComplexControl(QStyle::ComplexControl,const QStyleOptionComplex*,QPainter*,const QWidget*)const">
<modify-argument index="3" invalidate-after-use="yes"/>
<modify-argument index="4">
@@ -1579,7 +1579,6 @@
<enum-type name="OptimizationFlag" flags="OptimizationFlags"/>
<enum-type name="ViewportAnchor"/>
<enum-type name="ViewportUpdateMode"/>
- <modify-function signature="setupViewport(QWidget*)" access="non-final"/>
<modify-function signature="setScene(QGraphicsScene*)">
<modify-argument index="1">
<reference-count action="set"/>
@@ -1876,13 +1875,6 @@
</inject-code>
</modify-function>
- <!-- use glue code -->
- <modify-function signature="drawItems(QPainter*,int,QGraphicsItem**,const QStyleOptionGraphicsItem*,QWidget*)">
- <modify-argument index="2">
- <remove-argument/>
- </modify-argument>
- </modify-function>
-
<modify-function signature="clear()">
<inject-code>
const QList&lt;QGraphicsItem*> items = %CPPSELF.items();
@@ -2204,9 +2196,25 @@
</modify-function>
</object-type>
- <object-type name="QWidget">
- <!-- Qt5: remove native event for now -->
- <modify-function signature="nativeEvent(const QByteArray &amp;,void*,long*)" remove="all" />
+ <object-type name="QWidget" delete-in-main-thread="true">
+ <!-- see QWindow::nativeEvent(), QAbstractNativeEventFilter::nativeEventFilter() -->
+ <modify-function signature="nativeEvent(const QByteArray &amp;,void*,long*)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion_variables"/>
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject"/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion"/>
+ </conversion-rule>
+ </modify-argument>
+ <inject-code position="end">
+ <insert-template name="return_native_eventfilter"/>
+ </inject-code>
+ </modify-function>
<extra-includes>
<include file-name="QIcon" location="global"/>
@@ -2491,6 +2499,7 @@
<enum-type name="ButtonSymbols"/>
<enum-type name="CorrectionMode"/>
<enum-type name="StepEnabledFlag" flags="StepEnabled"/>
+ <enum-type name="StepType" since="5.12"/>
<modify-function signature="setLineEdit(QLineEdit*)">
<modify-argument index="1">
<parent index="this" action="add"/>
@@ -2968,7 +2977,7 @@
</object-type>
<object-type name="QDesktopWidget"/>
<object-type name="QFrame">
- <enum-type name="Shadow" extensible="yes"/>
+ <enum-type name="Shadow"/>
<enum-type name="Shape"/>
<enum-type name="StyleMask"/>
</object-type>
diff --git a/sources/pyside2/PySide2/QtXmlPatterns/typesystem_xmlpatterns.xml b/sources/pyside2/PySide2/QtXmlPatterns/typesystem_xmlpatterns.xml
index f4e690874..2ac150807 100644
--- a/sources/pyside2/PySide2/QtXmlPatterns/typesystem_xmlpatterns.xml
+++ b/sources/pyside2/PySide2/QtXmlPatterns/typesystem_xmlpatterns.xml
@@ -101,7 +101,7 @@
<modify-function signature="kind()const" remove="all" />
<modify-function signature="isDeepEqual(const QXmlNodeModelIndex&amp;)const" remove="all" />
<modify-function signature="compareOrder(const QXmlNodeModelIndex &amp;)const" remove="all" />
- <modify-function signature="sendNamespaces(QAbstractXmlReceiver*)const" remove="all" />
+ <modify-function signature="sendNamespaces(QAbstractXmlReceiver*const)const" remove="all" />
<modify-function signature="namespaceBindings()const" remove="all" />
<modify-function signature="namespaceForPrefix(QXmlName::PrefixCode)const" remove="all" />
<modify-function signature="stringValue()const" remove="all" />
diff --git a/sources/pyside2/PySide2/__init__.py.in b/sources/pyside2/PySide2/__init__.py.in
index ab50ef776..631f5f13a 100644
--- a/sources/pyside2/PySide2/__init__.py.in
+++ b/sources/pyside2/PySide2/__init__.py.in
@@ -4,18 +4,22 @@ __all__ = list("Qt" + body for body in
__version__ = "@FINAL_PACKAGE_VERSION@"
__version_info__ = (@BINDING_API_MAJOR_VERSION@, @BINDING_API_MINOR_VERSION@, @BINDING_API_MICRO_VERSION@, "@BINDING_API_PRE_RELEASE_VERSION_TYPE@", "@BINDING_API_PRE_RELEASE_VERSION@")
-@PYSIDE_BUILD_DATE@
-@PYSIDE_BUILD_COMMIT_DATE@
-@PYSIDE_BUILD_COMMIT_HASH@
-@PYSIDE_BUILD_COMMIT_HASH_DESCRIBED@
-
-# Timestamp used for snapshot build, which is part of snapshot package version.
-@PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
-
def _setupQtDirectories():
import sys
import os
+ # On Windows we need to explicitly import the shiboken2 module so
+ # that the libshiboken.dll dependency is loaded by the time a
+ # Qt module is imported. Otherwise due to PATH not containing
+ # the shiboken2 module path, the Qt module import would fail
+ # due to the missing libshiboken dll.
+ # We need to do the same on Linux and macOS, because we do not
+ # embed rpaths into the PySide2 libraries that would point to
+ # the libshiboken library location. Importing the module
+ # loads the libraries into the process memory beforehand, and
+ # thus takes care of it for us.
+ import shiboken2
+
pyside_package_dir = os.path.abspath(os.path.dirname(__file__))
# Used by signature module.
os.environ["PYSIDE_PACKAGE_DIR"] = pyside_package_dir
diff --git a/sources/pyside2/PySide2/_config.py.in b/sources/pyside2/PySide2/_config.py.in
index 31a2f7a50..740e9a001 100644
--- a/sources/pyside2/PySide2/_config.py.in
+++ b/sources/pyside2/PySide2/_config.py.in
@@ -8,10 +8,9 @@ pyside_library_soversion = str(@PYSIDE_SO_VERSION@)
version = "@FINAL_PACKAGE_VERSION@"
version_info = (@BINDING_API_MAJOR_VERSION@, @BINDING_API_MINOR_VERSION@, @BINDING_API_MICRO_VERSION@, "@BINDING_API_PRE_RELEASE_VERSION_TYPE@", "@BINDING_API_PRE_RELEASE_VERSION@")
-@PYSIDE_BUILD_DATE@
-@PYSIDE_BUILD_COMMIT_DATE@
-@PYSIDE_BUILD_COMMIT_HASH@
-@PYSIDE_BUILD_COMMIT_HASH_DESCRIBED@
-
-# Timestamp used for snapshot build, which is part of snapshot package version.
-@PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
+@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@
diff --git a/sources/pyside2/PySide2/support/signature/__init__.py b/sources/pyside2/PySide2/support/signature/__init__.py
index 0ff9ec7e9..14e63a5fb 100644
--- a/sources/pyside2/PySide2/support/signature/__init__.py
+++ b/sources/pyside2/PySide2/support/signature/__init__.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -40,3 +40,7 @@
from __future__ import print_function, absolute_import
from .loader import inspect
+from PySide2 import QtCore
+if QtCore.QProcess.__signature__:
+ pass # trigger initialization
+from signature_loader import get_signature
diff --git a/sources/pyside2/PySide2/support/signature/fix-complaints.py b/sources/pyside2/PySide2/support/signature/fix-complaints.py
index fa2b44420..e078ef1ab 100644
--- a/sources/pyside2/PySide2/support/signature/fix-complaints.py
+++ b/sources/pyside2/PySide2/support/signature/fix-complaints.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
diff --git a/sources/pyside2/PySide2/support/signature/layout.py b/sources/pyside2/PySide2/support/signature/layout.py
new file mode 100644
index 000000000..ac7833f03
--- /dev/null
+++ b/sources/pyside2/PySide2/support/signature/layout.py
@@ -0,0 +1,237 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+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.
+"""
+
+from textwrap import dedent
+from .loader import inspect
+
+class SimpleNamespace(object):
+ # From types.rst, because the builtin is implemented in Python 3, only.
+ def __init__(self, **kwargs):
+ self.__dict__.update(kwargs)
+
+ def __repr__(self):
+ keys = sorted(self.__dict__)
+ items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
+ return "{}({})".format(type(self).__name__, ", ".join(items))
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+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("""\
+ Not allowed: '{err_keys}'.
+ The only allowed keywords are '{allowed_keys}'.
+ """.format(**locals())))
+
+ def _valueerror(self, err_values):
+ err_values = ", ".join(map(str, err_values))
+ allowed_values = ", ".join(map(str, self.allowed_values))
+ raise ValueError(dedent("""\
+ Not allowed: '{err_values}'.
+ The only allowed values are '{allowed_values}'.
+ """.format(**locals())))
+
+# 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()
+
+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
+
+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:
+ sig_kind, modifier = key
+ else:
+ sig_kind, modifier = key, "signature"
+
+ layout = globals()[modifier] # lookup of the modifier, here
+ 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:
+ if sig_kind == "method":
+ varnames = ("self",) + varnames
+ elif sig_kind == "staticmethod":
+ pass
+ elif sig_kind == "classmethod":
+ varnames = ("klass",) + varnames
+ else:
+ raise SystemError("Methods must be normal, staticmethod or "
+ "classmethod")
+ # calculate the modifications
+ defaults = props["defaults"][:]
+ if not layout.defaults:
+ defaults = ()
+ if layout.ellipsis:
+ defaults = ("...",) * len(defaults)
+ annotations = props["annotations"].copy()
+ if not layout.return_annotation and "return" in annotations:
+ del annotations["return"]
+
+ # attach parameters to a fake function and build a signature
+ argstr = ", ".join(varnames)
+ fakefunc = eval("lambda {}: None".format(argstr))
+ fakefunc.__name__ = props["name"]
+ fakefunc.__defaults__ = defaults
+ fakefunc.__kwdefaults__ = props["kwdefaults"]
+ fakefunc.__annotations__ = annotations
+ sig = inspect._signature_from_function(inspect.Signature, fakefunc)
+
+ # the special case of nameless parameters
+ if not layout.parameter_names:
+ make_signature_nameless(sig)
+ return sig
+
+# end of file
diff --git a/sources/pyside2/PySide2/support/signature/lib/__init__.py b/sources/pyside2/PySide2/support/signature/lib/__init__.py
new file mode 100644
index 000000000..2d640cb89
--- /dev/null
+++ b/sources/pyside2/PySide2/support/signature/lib/__init__.py
@@ -0,0 +1,40 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+# this file intentionally left blank
diff --git a/sources/pyside2/PySide2/support/signature/lib/enum_sig.py b/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
new file mode 100644
index 000000000..702ee7ebd
--- /dev/null
+++ b/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
@@ -0,0 +1,113 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import sys
+from PySide2.support.signature import inspect, get_signature
+
+
+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):
+ self.fmt = formatter
+ self.result_type = result_type
+
+ def module(self, mod_name):
+ __import__(mod_name)
+ with self.fmt.module(mod_name):
+ module = sys.modules[mod_name]
+ members = inspect.getmembers(module, inspect.isclass)
+ ret = self.result_type()
+ for class_name, klass in members:
+ ret.update(self.klass(class_name, klass))
+ return ret
+
+ def klass(self, class_name, klass):
+ bases_list = []
+ for base in klass.__bases__:
+ name = base.__name__
+ if name == "object":
+ pass
+ else:
+ modname = base.__module__
+ name = modname + "." + base.__name__
+ bases_list.append(name)
+ class_str = "{}({})".format(class_name, ", ".join(bases_list))
+ with self.fmt.klass(class_name, class_str):
+ ret = self.function("__init__", klass)
+ # class_members = inspect.getmembers(klass)
+ # gives us also the inherited things.
+ class_members = sorted(list(klass.__dict__.items()))
+ for func_name, func in class_members:
+ ret.update(self.function(func_name, func))
+ return ret
+
+ def function(self, func_name, func):
+ ret = self.result_type()
+ signature = getattr(func, '__signature__', None)
+ if signature is not None:
+ with self.fmt.function(func_name, signature) as key:
+ ret[key] = signature
+ return ret
+
+
+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_signature(func, 'existence')
+ if signature is not None and func_name not in ("next", "__next__"):
+ with self.fmt.function(func_name, signature) as key:
+ ret[key] = signature
+ return ret
diff --git a/sources/pyside2/PySide2/support/signature/loader.py b/sources/pyside2/PySide2/support/signature/loader.py
index f51bafe79..21ecebcc8 100644
--- a/sources/pyside2/PySide2/support/signature/loader.py
+++ b/sources/pyside2/PySide2/support/signature/loader.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -80,31 +80,10 @@ from PySide2.support.signature.parser import pyside_type_init
sys.path.pop(0)
# Note also that during the tests we have a different encoding that would
# break the Python license decorated files without an encoding line.
+from PySide2.support.signature import layout
# name used in signature.cpp
-def create_signature(props, sig_kind):
- if not props:
- # empty signatures string
- return
- if isinstance(props["multi"], list):
- return list(create_signature(elem, sig_kind)
- for elem in props["multi"])
- varnames = props["varnames"]
- if sig_kind == "method":
- varnames = ("self",) + varnames
- elif sig_kind == "staticmethod":
- pass
- elif sig_kind == "classmethod":
- varnames = ("klass",) + varnames
- else:
- raise SystemError("Methods must be normal, staticmethod or "
- "classmethod")
- argstr = ", ".join(varnames)
- fakefunc = eval("lambda {}: None".format(argstr))
- fakefunc.__name__ = props["name"]
- fakefunc.__defaults__ = props["defaults"]
- fakefunc.__kwdefaults__ = props["kwdefaults"]
- fakefunc.__annotations__ = props["annotations"]
- return inspect._signature_from_function(inspect.Signature, fakefunc)
+def create_signature(props, key):
+ return layout.create_signature(props, key)
# end of file
diff --git a/sources/pyside2/PySide2/support/signature/mapping.py b/sources/pyside2/PySide2/support/signature/mapping.py
index dd3df0988..6b7d1ad01 100644
--- a/sources/pyside2/PySide2/support/signature/mapping.py
+++ b/sources/pyside2/PySide2/support/signature/mapping.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -46,7 +46,7 @@ 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 minimises the loading overhead.
+in sys.modules. This minimizes the loading overhead.
In principle, we need to re-load the module, when the imports change.
But it is much easier to do it on demand, when we get an exception.
See _resolve_value() in singature.py
@@ -71,7 +71,6 @@ FloatMatrix = typing.List[typing.List[float]]
# Pair could be more specific, but we loose the info in the generator.
Pair = typing.Tuple[typing.Any, typing.Any]
MultiMap = typing.DefaultDict[str, typing.List[str]]
-Text = typing.Text
# ulong_max is only 32 bit on windows.
ulong_max = 2*sys.maxsize+1 if len(struct.pack("L", 1)) != 4 else 0xffffffff
@@ -153,7 +152,7 @@ type_map = {}
def init_QtCore():
import PySide2.QtCore
- from PySide2.QtCore import Qt, QUrl, QDir, QGenericArgument
+ from PySide2.QtCore import Qt, QUrl, QDir
from PySide2.QtCore import QRect, QSize, QPoint, QLocale, QByteArray
from PySide2.QtCore import QMarginsF # 5.9
try:
@@ -201,9 +200,8 @@ def init_QtCore():
"ULONG_MAX": ulong_max,
"quintptr": int,
"PyCallable": typing.Callable,
- "...": ellipsis, # no idea how this should be translated... maybe so?
"PyTypeObject": type,
- "PySequence": typing.Sequence,
+ "PySequence": typing.Iterable, # important for numpy
"qptrdiff": int,
"true": True,
"Qt.HANDLE": int, # be more explicit with some consts?
@@ -242,7 +240,7 @@ def init_QtCore():
"QDir.SortFlags(QDir.Name | QDir.IgnoreCase)"),
"PyBytes": bytes,
"PyByteArray": bytearray,
- "PyUnicode": Text,
+ "PyUnicode": typing.Text,
"signed long": int,
"PySide2.QtCore.int": int,
"PySide2.QtCore.char": StringList, # A 'char **' is a list of strings.
@@ -259,13 +257,13 @@ def init_QtCore():
"float[][]": FloatMatrix, # 5.9
"PySide2.QtCore.unsigned int": int, # 5.9 Ubuntu
"PySide2.QtCore.long long": int, # 5.9, MSVC 15
- "QGenericArgument(nullptr)": QGenericArgument(None), # 5.10
+ "QGenericArgument(nullptr)": ellipsis, # 5.10
"QModelIndex()": Invalid("PySide2.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?!
- "QGenericArgument((0))": None, # 5.6, RHEL 6.6. Is that ok?
- "QGenericArgument()": None,
- "QGenericArgument(0)": None,
- "QGenericArgument(NULL)": None, # 5.6, MSVC
- "QGenericArgument(Q_NULLPTR)": None,
+ "QGenericArgument((0))": ellipsis, # 5.6, RHEL 6.6. Is that ok?
+ "QGenericArgument()": ellipsis,
+ "QGenericArgument(0)": ellipsis,
+ "QGenericArgument(NULL)": ellipsis, # 5.6, MSVC
+ "QGenericArgument(Q_NULLPTR)": ellipsis,
"zero(PySide2.QtCore.QObject)": None,
"zero(PySide2.QtCore.QThread)": None,
"zero(quintptr)": 0,
@@ -289,6 +287,8 @@ def init_QtCore():
"zero(PySide2.QtCore.QEvent.Type)": None,
"CheckIndexOption.NoOption": Instance(
"PySide2.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11
+ "QVariantMap": dict,
+ "PySide2.QtCore.QCborStreamReader.StringResult": typing.AnyStr,
})
try:
type_map.update({
@@ -301,7 +301,6 @@ def init_QtCore():
def init_QtGui():
import PySide2.QtGui
- from PySide2.QtGui import QPageLayout, QPageSize # 5.9
type_map.update({
"QVector< QTextLayout.FormatRange >()": [], # do we need more structure?
"USHRT_MAX": ushort_max,
@@ -313,7 +312,7 @@ def init_QtGui():
"GL_COLOR_BUFFER_BIT": GL_COLOR_BUFFER_BIT,
"GL_NEAREST": GL_NEAREST,
"WId": WId,
- "PySide2.QtGui.QPlatformSurface": Virtual("PySide2.QtGui.QPlatformSurface"), # hmm...
+ "PySide2.QtGui.QPlatformSurface": int, # a handle
"QList< QTouchEvent.TouchPoint >()": [], # XXX improve?
"QPixmap()": Default("PySide2.QtGui.QPixmap"), # can't create without qApp
"PySide2.QtCore.uint8_t": int, # macOS 5.9
@@ -325,6 +324,7 @@ def init_QtGui():
"zero(PySide2.QtGui.QTextLayout.FormatRange)": None,
"zero(PySide2.QtGui.QTouchDevice)": None,
"zero(PySide2.QtGui.QScreen)": None,
+ "PySide2.QtGui.QGenericMatrix": Missing("PySide2.QtGui.QGenericMatrix"),
})
return locals()
@@ -396,7 +396,6 @@ def init_QtMultimedia():
import PySide2.QtMultimedia
import PySide2.QtMultimediaWidgets
type_map.update({
- "QVariantMap": dict,
"QGraphicsVideoItem": PySide2.QtMultimediaWidgets.QGraphicsVideoItem,
"QVideoWidget": PySide2.QtMultimediaWidgets.QVideoWidget,
})
diff --git a/sources/pyside2/PySide2/support/signature/parser.py b/sources/pyside2/PySide2/support/signature/parser.py
index 9313fb540..dd6640fde 100644
--- a/sources/pyside2/PySide2/support/signature/parser.py
+++ b/sources/pyside2/PySide2/support/signature/parser.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -48,6 +48,7 @@ import functools
from .mapping import type_map, update_mapping, __dict__ as namespace
_DEBUG = False
+LIST_KEYWORDS = False
"""
parser.py
@@ -119,6 +120,8 @@ def _parse_line(line):
for arg in arglist:
name, ann = arg.split(":")
if name in keyword.kwlist:
+ if LIST_KEYWORDS:
+ print("KEYWORD", ret)
name = name + "_"
if "=" in ann:
ann, default = ann.split("=")
@@ -130,6 +133,10 @@ def _parse_line(line):
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 ret
def make_good_value(thing, valtype):
@@ -192,8 +199,14 @@ def calculate_props(line):
arglist = res["arglist"]
annotations = {}
_defaults = []
- for tup in arglist:
+ for idx, tup in enumerate(arglist):
name, ann = tup[:2]
+ if ann == "...":
+ name = "*args"
+ # copy the fields back :()
+ ann = 'NULL' # maps to None
+ tup = name, ann
+ arglist[idx] = tup
annotations[name] = _resolve_type(ann, line)
if len(tup) == 3:
default = _resolve_value(tup[2], ann, line)
@@ -214,6 +227,31 @@ def calculate_props(line):
props["multi"] = res["multi"]
return props
+def fixup_multilines(sig_str):
+ lines = list(line.strip() for line in sig_str.strip().splitlines())
+ 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 = list(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("{}:{}".format(nmulti-idx-1, line))
+ else:
+ res.append(multi_lines[0])
+ multi_lines = []
+ else:
+ res.append(line)
+ return res
+
def pyside_type_init(typemod, sig_str):
dprint()
if type(typemod) is types.ModuleType:
@@ -222,9 +260,10 @@ def pyside_type_init(typemod, sig_str):
dprint("Initialization of type '{}.{}'".format(typemod.__module__,
typemod.__name__))
update_mapping()
+ lines = fixup_multilines(sig_str)
ret = {}
multi_props = []
- for line in sig_str.strip().splitlines():
+ for line in lines:
props = calculate_props(line)
shortname = props["name"]
multi = props["multi"]
@@ -232,10 +271,10 @@ def pyside_type_init(typemod, sig_str):
ret[shortname] = props
dprint(props)
else:
- fullname = props.pop("fullname")
multi_props.append(props)
if multi > 0:
continue
+ fullname = props.pop("fullname")
multi_props = {"multi": multi_props, "fullname": fullname}
ret[shortname] = multi_props
dprint(multi_props)
diff --git a/sources/pyside2/PySide2/typesystem_templates.xml b/sources/pyside2/PySide2/typesystem_templates.xml
index a17337258..a7a7bfc9d 100644
--- a/sources/pyside2/PySide2/typesystem_templates.xml
+++ b/sources/pyside2/PySide2/typesystem_templates.xml
@@ -361,6 +361,26 @@
Py_INCREF(%PYARG_0);
</template>
+ <!-- Helpers for modifying "bool nativeEventFilter(QByteArray, void*, long *result)"
+ to return a tuple of bool,long -->
+ <template name="return_native_eventfilter_conversion_variables">
+ long resultVar{0};
+ long *%out = &amp;resultVar;
+ </template>
+ <template name="return_native_eventfilter_conversion">
+ %RETURN_TYPE %out = false;
+ if (PySequence_Check(%PYARG_0) &amp;&amp; (PySequence_Size(%PYARG_0) == 2)) {
+ Shiboken::AutoDecRef pyItem(PySequence_GetItem(%PYARG_0, 0));
+ %out = %CONVERTTOCPP[bool](pyItem);
+ }
+ </template>
+
+ <template name="return_native_eventfilter">
+ %PYARG_0 = PyTuple_New(2);
+ PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%RETURN_TYPE](%0));
+ PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[long](*result_out));
+ </template>
+
<!-- templates for __reduce__ -->
<template name="reduce_code">
%PYARG_0 = Py_BuildValue("(N(%REDUCE_FORMAT))", PyObject_Type(%PYSELF), %REDUCE_ARGS);
@@ -401,16 +421,6 @@
return pyData;
</template>
- <template name="matrix_fill_function">
- float value = %CONVERTTOCPP[float](%PYARG_1);
- %CPPSELF.fill(value);
- </template>
-
- <template name="matrix_transposed_function">
- %TRANSPOSED_TYPE transp = %CPPSELF.transposed();
- return %CONVERTTOPYTHON[%TRANSPOSED_TYPE](transp);
- </template>
-
<!-- Replace '#' for the argument number you want. -->
<template name="return_argument">
Py_INCREF(%PYARG_#);
diff --git a/sources/pyside2/cmake/Macros/PySideModules.cmake b/sources/pyside2/cmake/Macros/PySideModules.cmake
index 36488912d..0f8b500ac 100644
--- a/sources/pyside2/cmake/Macros/PySideModules.cmake
+++ b/sources/pyside2/cmake/Macros/PySideModules.cmake
@@ -80,7 +80,8 @@ macro(create_pyside_module
get_filename_component(pyside_binary_dir ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY)
- add_custom_command(OUTPUT ${${module_sources}}
+ add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+ BYPRODUCTS ${${module_sources}}
COMMAND "${SHIBOKEN_BINARY}" ${GENERATOR_EXTRA_FLAGS}
"${pyside2_BINARY_DIR}/${module_name}_global.h"
--include-paths=${shiboken_include_dirs}
@@ -112,6 +113,7 @@ macro(create_pyside_module
if(${module_deps})
add_dependencies(${module_name} ${${module_deps}})
endif()
+ create_generator_target(${module_name})
# install
install(TARGETS ${module_name} LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}/PySide2)
@@ -134,77 +136,6 @@ macro(create_pyside_module
endforeach()
endmacro()
-#macro(check_qt_class_with_namespace module namespace class optional_source_files dropped_entries [namespace] [module])
-macro(check_qt_class module class optional_source_files dropped_entries)
- if (${ARGC} GREATER 4)
- set (namespace ${ARGV4})
- string(TOLOWER ${namespace} _namespace)
- else ()
- set (namespace "")
- endif ()
- if (${ARGC} GREATER 5)
- set (include_file ${ARGV5})
- else ()
- set (include_file ${class})
- endif ()
- string(TOLOWER ${class} _class)
- # Remove the "Qt" prefix.
- string(SUBSTRING ${module} 2 -1 _module_no_qt_prefix)
- if (_namespace)
- set(_cppfile ${CMAKE_CURRENT_BINARY_DIR}/PySide2/${module}/${_namespace}_${_class}_wrapper.cpp)
- else ()
- set(_cppfile ${CMAKE_CURRENT_BINARY_DIR}/PySide2/${module}/${_class}_wrapper.cpp)
- endif ()
- if (DEFINED PYSIDE_${class})
- if (PYSIDE_${class})
- list(APPEND ${optional_source_files} ${_cppfile})
- else()
- list(APPEND ${dropped_entries} PySide2.${module}.${class})
- endif()
- else()
- if (NOT ${namespace} STREQUAL "" )
- set (NAMESPACE_USE "using namespace ${namespace};")
- else ()
- set (NAMESPACE_USE "")
- endif ()
- set(SRC_FILE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test${class}.cxx)
- file(WRITE ${SRC_FILE}
- "#include <${include_file}>\n"
- "${NAMESPACE_USE}\n"
- "int main() { sizeof(${class}); }\n"
- )
-
- # Because Qt is built with -fPIC (by default), the compile tests also have to have that.
- get_property(ADDITIONAL_FLAGS TARGET Qt5::Core PROPERTY INTERFACE_COMPILE_OPTIONS)
-
- # Don't add version tagging, because for some reason linker fails with:
- # (.qtversion[qt_version_tag]+0x0): undefined reference to `qt_version_tag'
- # Force usage of the C++11 standard. CMAKE_CXX_STANDARD does not work with try_compile
- # but the issue has a fix in CMake 3.9. Thus we use a terrible workaround, we pass the C++
- # standard flag the way CheckCXXSourceCompiles.cmake does it.
-
- set(ADDITIONAL_FLAGS "${ADDITIONAL_FLAGS} -DQT_NO_VERSION_TAGGING ${CMAKE_CXX11_EXTENSION_COMPILE_OPTION}")
-
- try_compile(Q_WORKS ${CMAKE_BINARY_DIR}
- ${SRC_FILE}
- CMAKE_FLAGS
- "-DINCLUDE_DIRECTORIES=${QT_INCLUDE_DIR};${Qt5${_module_no_qt_prefix}_INCLUDE_DIRS}"
- "-DCOMPILE_DEFINITIONS:STRING=${ADDITIONAL_FLAGS}"
- OUTPUT_VARIABLE OUTPUT)
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeCheckQtClassTest.log ${OUTPUT})
-
- set("PYSIDE_${class}" ${Q_WORKS} CACHE STRING "Has ${class} class been found?")
- if(Q_WORKS)
- message(STATUS "Checking for ${class} in ${module} -- found")
- list(APPEND ${optional_source_files} ${_cppfile})
- else()
- message(STATUS "Checking for ${class} in ${module} -- not found")
- list(APPEND ${dropped_entries} PySide2.${module}.${class})
- endif()
- endif()
-endmacro()
-
-
# Only add subdirectory if the associated Qt module is found.
# As a side effect, this macro now also defines the variable ${name}_GEN_DIR
# and must be called for every subproject.
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtcore.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtcore.py
index 4696bd38b..4696bd38b 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtcore.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtcore.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtnetwork.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtnetwork.py
index 84e7e9189..84e7e9189 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtnetwork.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtnetwork.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtopengl.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtopengl.py
index 63c5665cd..63c5665cd 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtopengl.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtopengl.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtprintsupport.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtprintsupport.py
index fb5541603..fb5541603 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtprintsupport.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtprintsupport.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtqml.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtqml.py
index 3eeb024db..3eeb024db 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtqml.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtqml.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtquick.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtquick.py
index bf55f0c7e..bf55f0c7e 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtquick.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtquick.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtsql.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtsql.py
index 31849e785..31849e785 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtsql.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtsql.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qttest.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qttest.py
index 34dd7bb5a..34dd7bb5a 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qttest.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qttest.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtwidgets.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtwidgets.py
index a0deee957..a0deee957 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtwidgets.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtwidgets.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtxml.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtxml.py
index 077be436d..077be436d 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtxml.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/code/doc_src_qtxml.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtcharts.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtcharts.py
index bfc35e1ee..bfc35e1ee 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtcharts.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtcharts.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtgui.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtgui.py
index 11c3cf5e9..11c3cf5e9 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtgui.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtgui.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtmultimedia.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtmultimedia.py
index 494145357..494145357 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtmultimedia.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtmultimedia.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtxmlpatterns.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtxmlpatterns.py
index c3363e97e..c3363e97e 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtxmlpatterns.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/doc_src_qtxmlpatterns.py
diff --git a/sources/pyside2/doc/codesnippets/doc/src/snippets/quiloader/doc_src_qtuiloader.cpp b/sources/pyside2/doc/codesnippets/doc/src/snippets/quiloader/doc_src_qtuiloader.py
index 141189ad8..141189ad8 100644
--- a/sources/pyside2/doc/codesnippets/doc/src/snippets/quiloader/doc_src_qtuiloader.cpp
+++ b/sources/pyside2/doc/codesnippets/doc/src/snippets/quiloader/doc_src_qtuiloader.py
diff --git a/sources/pyside2/doc/gettingstarted.rst b/sources/pyside2/doc/gettingstarted.rst
index f24051c18..0a58226a7 100644
--- a/sources/pyside2/doc/gettingstarted.rst
+++ b/sources/pyside2/doc/gettingstarted.rst
@@ -4,15 +4,19 @@ Getting Started
To get started with |project|, install the following prerequisites:
-* Python v3.5 or later
-* libclang v3.9 or later
-* Optional: a virtual environment, such as `venv <https://docs.python.org/3/library/venv.html>`_ or `virtualenv <https://virtualenv.pypa.io/en/stable/installation>`_
+* Python 3.5+ or 2.7
+* libclang 5.0+ (for Qt 5.11) or 6.0+ (for Qt 5.12)
+* Recommended: a virtual environment, such as `venv <https://docs.python.org/3/library/venv.html>`_ or `virtualenv <https://virtualenv.pypa.io/en/stable/installation>`_
With these installed, you are ready to install the |project|
packages using the pip wheel. Run the following command from your command
prompt to install::
- python -m pip install --index-url=http://download.qt.io/snapshots/ci/pyside/5.11/latest pyside2 --trusted-host download.qt.io
+ pip install PySide2 # For the latest version on PyPi
+
+or::
+
+ pip install --index-url=http://download.qt.io/snapshots/ci/pyside/5.12/latest pyside2 --trusted-host download.qt.io
Now that you have |project| installed, you can test your setup by running the following Python
constructs to print version information:
@@ -44,16 +48,12 @@ guide you through the development process:
def __init__(self):
super().__init__()
- self.hello = ["Hallo Welt", "你好,世界", "Hei maailma",\
- "Hola Mundo", "Привет мир"]
+ self.hello = ["Hallo Welt", "Hei maailma", "Hola Mundo", "Привет мир"]
self.button = QtWidgets.QPushButton("Click me!")
self.text = QtWidgets.QLabel("Hello World")
self.text.setAlignment(QtCore.Qt.AlignCenter)
- self.text.setFont(QtGui.QFont("Titillium", 30))
- self.button.setFont(QtGui.QFont("Titillium", 20))
-
self.layout = QtWidgets.QVBoxLayout()
self.layout.addWidget(self.text)
self.layout.addWidget(self.button)
diff --git a/sources/pyside2/doc/pysideapi2.rst b/sources/pyside2/doc/pysideapi2.rst
index f1cc13391..e552bf21d 100644
--- a/sources/pyside2/doc/pysideapi2.rst
+++ b/sources/pyside2/doc/pysideapi2.rst
@@ -1,12 +1,15 @@
.. _pysideapi2:
-|pymodname| API
-***************
+Qt for Python API
+*******************
One of the goals of |pymodname| is to be API compatible with PyQt5,
with certain exceptions. For example, |pymodname| will not export C++ components
that are marked as deprecated by Qt.
+The latest considerations and known issues will be also reported
+in the `wiki <https://wiki.qt.io/Qt_for_Python/Considerations>`_.
+
__hash__() function return value
================================
diff --git a/sources/pyside2/doc/pysideversion.rst b/sources/pyside2/doc/pysideversion.rst
index 24afba12d..bde48b39e 100644
--- a/sources/pyside2/doc/pysideversion.rst
+++ b/sources/pyside2/doc/pysideversion.rst
@@ -8,20 +8,20 @@ numbers using the following python constructs:
import PySide2.QtCore
- # Prints PySide version
- # e.g. 1.0.2
+ # Prints PySide2 version
+ # e.g. 5.11.1a1
print(PySide2.__version__)
# Gets a tuple with each version component
- # e.g. (1, 0, 2, 'final', 1)
+ # e.g. (5, 11, 1, 'a', 1)
print(PySide2.__version_info__)
- # Prints the Qt version used to compile PySide
- # e.g. "5.11.0"
+ # Prints the Qt version used to compile PySide2
+ # e.g. "5.11.2"
print(PySide2.QtCore.__version__)
- # Gets a tuple with each version components of Qt used to compile PySide
- # e.g. (5, 11, 0)
+ # Gets a tuple with each version components of Qt used to compile PySide2
+ # e.g. (5, 11, 2)
print(PySide2.QtCore.__version_info__)
diff --git a/sources/pyside2/doc/tutorials/index.rst b/sources/pyside2/doc/tutorials/index.rst
index 18bac57fd..c09b48ab5 100644
--- a/sources/pyside2/doc/tutorials/index.rst
+++ b/sources/pyside2/doc/tutorials/index.rst
@@ -1,5 +1,5 @@
-PySide examples and tutorials
-*****************************
+Qt for Python examples and tutorials
+*************************************
A collection of examples and tutorials with "walkthrough" guides are
provided with |project| to help new users get started. These
diff --git a/sources/pyside2/libpyside/CMakeLists.txt b/sources/pyside2/libpyside/CMakeLists.txt
index 3069b1ca2..ec6713b62 100644
--- a/sources/pyside2/libpyside/CMakeLists.txt
+++ b/sources/pyside2/libpyside/CMakeLists.txt
@@ -17,6 +17,7 @@ if(${Qt5Quick_FOUND})
endif()
endif()
+set(QML_PRIVATE_API_SUPPORT 0)
if(Qt5Qml_FOUND)
# Used for registering custom QQuickItem classes defined in Python code.
set(QML_SUPPORT 1)
@@ -28,7 +29,6 @@ if(Qt5Qml_FOUND)
set(QML_PRIVATE_API_SUPPORT 1)
set(QML_INCLUDES ${QML_INCLUDES} ${Qt5Qml_PRIVATE_INCLUDE_DIRS})
else()
- set(QML_PRIVATE_API_SUPPORT 0)
message(WARNING "QML private API include files could not be found, support for catching QML exceptions inside Python code will not work.")
endif()
else()
@@ -40,14 +40,10 @@ endif()
qt5_wrap_cpp(DESTROYLISTENER_MOC "destroylistener.h")
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/signalmanager.cpp.in"
- "${CMAKE_CURRENT_BINARY_DIR}/signalmanager.cpp" @ONLY)
-
set(libpyside_SRC
dynamicqmetaobject.cpp
destroylistener.cpp
- ${CMAKE_CURRENT_BINARY_DIR}/signalmanager.cpp
- globalreceiver.cpp
+ signalmanager.cpp
globalreceiverv2.cpp
pysideclassinfo.cpp
pysidemetafunction.cpp
@@ -86,7 +82,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${SHIBOKEN_INCLUDE_DIR}
${SHIBOKEN_PYTHON_INCLUDE_DIR}
${QML_INCLUDES}
- ${Qt5Core_INCLUDE_DIRS})
+ ${Qt5Core_INCLUDE_DIRS}
+ ${Qt5Core_PRIVATE_INCLUDE_DIRS})
add_library(pyside2 SHARED ${libpyside_SRC} ${other_files})
target_link_libraries(pyside2
${SHIBOKEN_PYTHON_LIBRARIES}
@@ -107,6 +104,7 @@ endif()
if(QML_SUPPORT)
target_compile_definitions(pyside2 PUBLIC PYSIDE_QML_SUPPORT=1)
endif()
+target_compile_definitions(pyside2 PRIVATE PYSIDE_QML_PRIVATE_API_SUPPORT=${QML_PRIVATE_API_SUPPORT})
if(PYSIDE_QT_CONF_PREFIX)
set_property(SOURCE pyside.cpp
@@ -122,7 +120,6 @@ endif()
set(libpyside_HEADERS
destroylistener.h
dynamicqmetaobject.h
- globalreceiver.h
pysideclassinfo.h
pysidemacros.h
signalmanager.h
diff --git a/sources/pyside2/libpyside/destroylistener.cpp b/sources/pyside2/libpyside/destroylistener.cpp
index 95e53f709..c6dc54713 100644
--- a/sources/pyside2/libpyside/destroylistener.cpp
+++ b/sources/pyside2/libpyside/destroylistener.cpp
@@ -40,10 +40,7 @@
#include <sbkpython.h>
#include "destroylistener.h"
-#include <QObject>
#include <shiboken.h>
-#include <QDebug>
-#include <QMutex>
PySide::DestroyListener* PySide::DestroyListener::m_instance = 0;
diff --git a/sources/pyside2/libpyside/destroylistener.h b/sources/pyside2/libpyside/destroylistener.h
index 0a800451a..b1a0597c5 100644
--- a/sources/pyside2/libpyside/destroylistener.h
+++ b/sources/pyside2/libpyside/destroylistener.h
@@ -40,10 +40,10 @@
#ifndef PYSIDE_DESTROY_LISTENER
#define PYSIDE_DESTROY_LISTENER
-
-#include <QObject>
#include "pysidemacros.h"
+#include <QtCore/QObject>
+
namespace PySide
{
struct DestroyListenerPrivate;
@@ -63,7 +63,7 @@ class PYSIDE_API DestroyListener : public QObject
static DestroyListener* m_instance;
DestroyListenerPrivate* m_d;
DestroyListener(QObject *parent);
- ~DestroyListener();
+ ~DestroyListener() override;
};
}//namespace
diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp
index af2f416c6..5cbfa70f9 100644
--- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp
+++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp
@@ -45,546 +45,376 @@
#include "pysideproperty_p.h"
#include "pysideslot_p.h"
-#include <QByteArray>
-#include <QString>
-#include <QStringList>
-#include <QList>
-#include <QLinkedList>
-#include <QObject>
-#include <cstring>
-#include <QDebug>
-#include <QMetaMethod>
#include <shiboken.h>
+#include <QtCore/QByteArray>
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QTextStream>
+#include <QtCore/QVector>
+#include <private/qmetaobjectbuilder_p.h>
-#define EMPTY_META_METHOD "0()"
+#include <cstring>
+#include <vector>
using namespace PySide;
-enum PropertyFlags {
- Invalid = 0x00000000,
- Readable = 0x00000001,
- Writable = 0x00000002,
- Resettable = 0x00000004,
- EnumOrFlag = 0x00000008,
- StdCppSet = 0x00000100,
-// Override = 0x00000200,
- Constant = 0x00000400,
- Final = 0x00000800,
- Designable = 0x00001000,
- ResolveDesignable = 0x00002000,
- Scriptable = 0x00004000,
- ResolveScriptable = 0x00008000,
- Stored = 0x00010000,
- ResolveStored = 0x00020000,
- Editable = 0x00040000,
- ResolveEditable = 0x00080000,
- User = 0x00100000,
- ResolveUser = 0x00200000,
- Notify = 0x00400000
-};
-
-// these values are from moc source code, generator.cpp:66
-enum MethodFlags {
- AccessPrivate = 0x00,
- AccessProtected = 0x01,
- AccessPublic = 0x02,
- MethodMethod = 0x00,
- MethodSignal = 0x04,
- MethodSlot = 0x08,
- MethodConstructor = 0x0c,
- MethodCompatibility = 0x10,
- MethodCloned = 0x20,
- MethodScriptable = 0x40
-};
-
-enum MetaDataFlags {
- IsUnresolvedType = 0x80000000,
- TypeNameIndexMask = 0x7FFFFFFF
-};
-
-class DynamicQMetaObject::DynamicQMetaObjectPrivate
+// MetaObjectBuilder: Provides the QMetaObject's returned by
+// QObject::metaObject() for PySide2 objects. There are several
+// scenarios to consider:
+// 1) A plain Qt class (say QTimer) is instantiated. In that case,
+// return the base meta object until a modification is made by
+// adding methods, properties or class info (cf qmetaobject_test.py).
+// In that case, instantiate a QMetaObjectBuilder inheriting the
+// base meta meta object, add the method and return the result
+// of QMetaObjectBuilder::toMetaObject() (with dirty handling should
+// further modifications be made).
+// 2) A Python class inheriting a Qt class is instantiated. For this,
+// instantiate a QMetaObjectBuilder and add the methods/properties
+// found by inspecting the Python class.
+
+class MetaObjectBuilderPrivate
{
public:
- QList<MethodData> m_methods;
- QList<PropertyData> m_properties;
-
- QMap<QByteArray, QByteArray> m_info;
- QByteArray m_className;
- bool m_updated; // when the meta data is not update
- int m_methodOffset;
- int m_propertyOffset;
- int m_dataSize;
- int m_emptyMethod;
- int m_nullIndex;
-
- DynamicQMetaObjectPrivate()
- : m_updated(false), m_methodOffset(0), m_propertyOffset(0),
- m_dataSize(0), m_emptyMethod(-1), m_nullIndex(0) {}
-
- int createMetaData(QMetaObject* metaObj, QLinkedList<QByteArray> &strings);
- void updateMetaObject(QMetaObject* metaObj);
- void writeMethodsData(const QList<MethodData>& methods, unsigned int** data, QLinkedList<QByteArray>& strings, int* prtIndex, int nullIndex, int flags);
- void writeStringData(char *, QLinkedList<QByteArray> &strings);
+ using MetaObjects = std::vector<const QMetaObject *>;
+
+ QMetaObjectBuilder *ensureBuilder();
+ void parsePythonType(PyTypeObject *type);
+ int indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const;
+ int indexOfProperty(const QByteArray &name) const;
+ int addSlot(const QByteArray &signature);
+ int addSlot(const QByteArray &signature, const QByteArray &type);
+ int addSignal(const QByteArray &signature);
+ void removeMethod(QMetaMethod::MethodType mtype, int index);
int getPropertyNotifyId(PySideProperty *property) const;
-};
+ int addProperty(const QByteArray &property, PyObject *data);
+ void addInfo(const QByteArray &key, const QByteArray &value);
+ void addInfo(const QMap<QByteArray, QByteArray> &info);
+ void removeProperty(int index);
+ const QMetaObject *update();
-bool sortMethodSignalSlot(const MethodData &m1, const MethodData &m2)
-{
- if (m1.methodType() == QMetaMethod::Signal)
- return m2.methodType() == QMetaMethod::Slot;
- return false;
-}
+ QMetaObjectBuilder *m_builder = nullptr;
+
+ const QMetaObject *m_baseObject = nullptr;
+ MetaObjects m_cachedMetaObjects;
+ bool m_dirty = true;
+};
-static int registerString(const QByteArray& s, QLinkedList<QByteArray>& strings)
+QMetaObjectBuilder *MetaObjectBuilderPrivate::ensureBuilder()
{
- int idx = 0;
- QLinkedList<QByteArray>::const_iterator it = strings.begin();
- QLinkedList<QByteArray>::const_iterator itEnd = strings.end();
- while (it != itEnd) {
- if (strcmp(*it, s) == 0)
- return idx;
- ++idx;
- ++it;
+ if (!m_builder) {
+ m_builder = new QMetaObjectBuilder();
+ m_builder->setClassName(m_baseObject->className());
+ m_builder->setSuperClass(m_baseObject);
}
- strings.append(s);
- return idx;
+ return m_builder;
}
-static int blobSize(QLinkedList<QByteArray> &strings)
+MetaObjectBuilder::MetaObjectBuilder(const char *className, const QMetaObject *metaObject) :
+ m_d(new MetaObjectBuilderPrivate)
{
- int size = strings.size() * sizeof(QByteArrayData);
-
- QByteArray str;
- QByteArray debug_str;
- foreach (const QByteArray &field, strings) {
- str.append(field);
- str.append(char(0));
-
- debug_str.append(field);
- debug_str.append('|');
- }
- //qDebug()<<debug_str;
- size += str.size();
- return size;
+ m_d->m_baseObject = metaObject;
+ m_d->m_builder = new QMetaObjectBuilder();
+ m_d->m_builder->setClassName(className);
+ m_d->m_builder->setSuperClass(metaObject);
+ m_d->m_builder->setClassName(className);
}
-static int aggregateParameterCount(const QList<MethodData> &methods)
+MetaObjectBuilder::MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject)
+ : m_d(new MetaObjectBuilderPrivate)
{
- int sum = 0;
- for (int i = 0; i < methods.size(); ++i)
- sum += methods.at(i).parameterCount() * 2 + 1; // nb_param*2 (type and names) +1 for return type
- return sum;
+ m_d->m_baseObject = metaObject;
+ const char *className = type->tp_name;
+ if (const char *lastDot = strrchr(type->tp_name, '.'))
+ className = lastDot + 1;
+ // Different names indicate a Python class inheriting a Qt class.
+ // Parse the type.
+ if (strcmp(className, metaObject->className()) != 0) {
+ m_d->m_builder = new QMetaObjectBuilder();
+ m_d->m_builder->setClassName(className);
+ m_d->m_builder->setSuperClass(metaObject);
+ m_d->parsePythonType(type);
+ }
}
-static void writeString(char *out, int i, const QByteArray &str,
- const int offsetOfStringdataMember, int &stringdataOffset)
+MetaObjectBuilder::~MetaObjectBuilder()
{
- int size = str.size();
- qptrdiff offset = offsetOfStringdataMember + stringdataOffset
- - i * sizeof(QByteArrayData);
- const QByteArrayData data =
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset);
-
- memcpy(out + i * sizeof(QByteArrayData), &data, sizeof(QByteArrayData));
-
- memcpy(out + offsetOfStringdataMember + stringdataOffset, str.constData(), size);
- out[offsetOfStringdataMember + stringdataOffset + size] = '\0';
-
- stringdataOffset += size + 1;
+ qDeleteAll(m_d->m_cachedMetaObjects);
+ delete m_d->m_builder;
+ delete m_d;
}
-static int qvariant_nameToType(const char* name)
+int MetaObjectBuilderPrivate::indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const
{
- if (!name)
- return 0;
-
- if (strcmp(name, "QVariant") == 0)
- return 0xffffffff;
- if (strcmp(name, "QCString") == 0)
- return QMetaType::QByteArray;
- if (strcmp(name, "Q_LLONG") == 0)
- return QMetaType::LongLong;
- if (strcmp(name, "Q_ULLONG") == 0)
- return QMetaType::ULongLong;
- if (strcmp(name, "QIconSet") == 0)
- return QMetaType::QIcon;
-
- uint tp = QMetaType::type(name);
- return tp < QMetaType::User ? tp : 0;
+ int result = -1;
+ if (m_builder) {
+ switch (mtype) {
+ case QMetaMethod::Signal:
+ result = m_builder->indexOfSignal(signature);
+ break;
+ case QMetaMethod::Slot:
+ result = m_builder->indexOfSlot(signature);
+ break;
+ case QMetaMethod::Constructor:
+ result = m_builder->indexOfConstructor(signature);
+ break;
+ case QMetaMethod::Method:
+ result = m_builder->indexOfMethod(signature);
+ break;
+ }
+ if (result >= 0)
+ return result + m_baseObject->methodCount();
+ }
+ switch (mtype) {
+ case QMetaMethod::Signal:
+ result = m_baseObject->indexOfSignal(signature);
+ break;
+ case QMetaMethod::Slot:
+ result = m_baseObject->indexOfSlot(signature);
+ break;
+ case QMetaMethod::Constructor:
+ result = m_baseObject->indexOfConstructor(signature);
+ break;
+ case QMetaMethod::Method:
+ result = m_baseObject->indexOfMethod(signature);
+ break;
+ }
+ return result;
}
-/*
- Returns true if the type is a QVariant types.
-*/
-static bool isVariantType(const char* type)
+int MetaObjectBuilder::indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const
{
- return qvariant_nameToType(type) != 0;
+ return m_d->indexOfMethod(mtype, signature);
}
-/*!
- Returns true if the type is qreal.
-*/
-static bool isQRealType(const char *type)
+int MetaObjectBuilderPrivate::indexOfProperty(const QByteArray &name) const
{
- return strcmp(type, "qreal") == 0;
+ if (m_builder) {
+ const int result = m_builder->indexOfProperty(name);
+ if (result >= 0)
+ return m_baseObject->propertyCount() + result;
+ }
+ return m_baseObject->indexOfProperty(name);
}
-uint PropertyData::flags() const
+int MetaObjectBuilder::indexOfProperty(const QByteArray &name) const
{
- const QByteArray btype(type());
- const char* typeName = btype.data();
- uint flags = Invalid;
- if (!isVariantType(typeName))
- flags |= EnumOrFlag;
- else if (!isQRealType(typeName))
- flags |= qvariant_nameToType(typeName) << 24;
-
- if (PySide::Property::isReadable(m_data))
- flags |= Readable;
-
- if (PySide::Property::isWritable(m_data))
- flags |= Writable;
-
- if (PySide::Property::hasReset(m_data))
- flags |= Resettable;
-
- if (PySide::Property::isDesignable(m_data))
- flags |= Designable;
- else
- flags |= ResolveDesignable;
-
- if (PySide::Property::isScriptable(m_data))
- flags |= Scriptable;
- else
- flags |= ResolveScriptable;
-
- if (PySide::Property::isStored(m_data))
- flags |= Stored;
- else
- flags |= ResolveStored;
-
- //EDITABLE
- flags |= ResolveEditable;
-
- if (PySide::Property::isUser(m_data))
- flags |= User;
- else
- flags |= ResolveUser;
-
- if (m_cachedNotifyId != -1)
- flags |= Notify;
-
- if (PySide::Property::isConstant(m_data))
- flags |= Constant;
-
- if (PySide::Property::isFinal(m_data))
- flags |= Final;
-
- return flags;
+ return m_d->indexOfProperty(name);
}
-// const QByteArray with EMPTY_META_METHOD, used to save some memory
-const QByteArray MethodData::m_emptySig(EMPTY_META_METHOD);
-
-MethodData::MethodData()
- : m_signature(m_emptySig)
+static bool checkMethodSignature(const QByteArray &signature)
{
+ // Common mistake not to add parentheses to the signature.
+ const int openParen = signature.indexOf('(');
+ const int closingParen = signature.lastIndexOf(')');
+ const bool ok = openParen != -1 && closingParen != -1 && openParen < closingParen;
+ if (!ok) {
+ const QByteArray message =
+ "MetaObjectBuilder::addMethod: Invalid method signature provided for \""
+ + signature + '"';
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.constData(), 0);
+ }
+ return ok;
}
-MethodData::MethodData(QMetaMethod::MethodType mtype, const QByteArray& signature, const QByteArray& rtype)
- : m_signature(QMetaObject::normalizedSignature(signature.constData()))
- , m_rtype(QMetaObject::normalizedSignature(rtype.constData()))
- , m_mtype(mtype)
+int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature)
{
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ return m_baseObject->methodCount()
+ + ensureBuilder()->addSlot(signature).index();
}
-void MethodData::clear()
+int MetaObjectBuilder::addSlot(const char *signature)
{
- m_signature = m_emptySig;
- m_rtype.clear();
+ return m_d->addSlot(signature);
}
-bool MethodData::isValid() const
+int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature,
+ const QByteArray &type)
{
- return m_signature != m_emptySig;
-}
-
-QList<QByteArray> MethodData::parameterTypes() const
-{
- const char *signature = m_signature.constData();
- QList<QByteArray> list;
- while (*signature && *signature != '(')
- ++signature;
- while (*signature && *signature != ')' && *++signature != ')') {
- const char *begin = signature;
- int level = 0;
- while (*signature && (level > 0 || *signature != ',') && *signature != ')') {
- if (*signature == '<')
- ++level;
- else if (*signature == '>')
- --level;
- ++signature;
- }
- list += QByteArray(begin, signature - begin);
- }
- return list;
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ QMetaMethodBuilder methodBuilder = ensureBuilder()->addSlot(signature);
+ methodBuilder.setReturnType(type);
+ return m_baseObject->methodCount() + methodBuilder.index();
}
-int MethodData::parameterCount() const
+int MetaObjectBuilder::addSlot(const char *signature, const char *type)
{
- return parameterTypes().size();
+ return m_d->addSlot(signature, type);
}
-QByteArray MethodData::name() const
+int MetaObjectBuilderPrivate::addSignal(const QByteArray &signature)
{
- return m_signature.left(qMax(m_signature.indexOf('('), 0));
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ return m_baseObject->methodCount()
+ + ensureBuilder()->addSignal(signature).index();
}
-PropertyData::PropertyData()
- : m_cachedNotifyId(0), m_data(0)
+int MetaObjectBuilder::addSignal(const char *signature)
{
+ return m_d->addSignal(signature);
}
-PropertyData::PropertyData(const char* name, int notifyId, PySideProperty* data)
- : m_name(name), m_cachedNotifyId(notifyId), m_data(data)
+void MetaObjectBuilderPrivate::removeMethod(QMetaMethod::MethodType mtype,
+ int index)
{
+ index -= m_baseObject->methodCount();
+ auto builder = ensureBuilder();
+ Q_ASSERT(index >= 0 && index < builder->methodCount());
+ switch (mtype) {
+ case QMetaMethod::Constructor:
+ builder->removeConstructor(index);
+ break;
+ default:
+ builder->removeMethod(index);
+ break;
+ }
+ m_dirty = true;
}
-QByteArray PropertyData::type() const
+void MetaObjectBuilder::removeMethod(QMetaMethod::MethodType mtype, int index)
{
- return QByteArray(PySide::Property::getTypeName(m_data));
+ m_d->removeMethod(mtype, index);
}
-
-bool PropertyData::isValid() const
+int MetaObjectBuilderPrivate::getPropertyNotifyId(PySideProperty *property) const
{
- return !m_name.isEmpty();
+ int notifyId = -1;
+ if (property->d->notify) {
+ if (const char *signalNotify = PySide::Property::getNotifyName(property))
+ notifyId = indexOfMethod(QMetaMethod::Signal, signalNotify);
+ }
+ return notifyId;
}
-int PropertyData::cachedNotifyId() const
+int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName,
+ PyObject *data)
{
- return m_cachedNotifyId;
-}
+ int index = indexOfProperty(propertyName);
+ if (index != -1)
+ return index;
-bool PropertyData::operator==(const PropertyData& other) const
-{
- return m_data == other.m_data;
+ PySideProperty *property = reinterpret_cast<PySideProperty *>(data);
+ int propertyNotifyId = getPropertyNotifyId(property);
+ if (propertyNotifyId >= 0)
+ propertyNotifyId -= m_baseObject->methodCount();
+ auto newProperty =
+ ensureBuilder()->addProperty(propertyName, property->d->typeName,
+ propertyNotifyId);
+ index = newProperty.index() + m_baseObject->propertyCount();
+ m_dirty = true;
+ return index;
}
-bool PropertyData::operator==(const char* name) const
+int MetaObjectBuilder::addProperty(const char *property, PyObject *data)
{
- return m_name == name;
+ return m_d->addProperty(property, data);
}
-
-DynamicQMetaObject::DynamicQMetaObject(PyTypeObject* type, const QMetaObject* base)
- : m_d(new DynamicQMetaObjectPrivate)
+void MetaObjectBuilderPrivate::addInfo(const QByteArray &key,
+ const QByteArray &value)
{
- d.superdata = base;
- d.stringdata = NULL;
- d.data = NULL;
- d.extradata = NULL;
- d.relatedMetaObjects = NULL;
- d.static_metacall = NULL;
-
- m_d->m_className = QByteArray(type->tp_name).split('.').last();
- m_d->m_methodOffset = base->methodCount() - 1;
- m_d->m_propertyOffset = base->propertyCount() - 1;
- parsePythonType(type);
+ ensureBuilder()->addClassInfo(key, value);
+ m_dirty = true;
}
-DynamicQMetaObject::DynamicQMetaObject(const char* className, const QMetaObject* metaObject)
- : m_d(new DynamicQMetaObjectPrivate)
+void MetaObjectBuilder::addInfo(const char *key, const char *value)
{
- d.superdata = metaObject;
- d.stringdata = 0;
- d.data = 0;
- d.extradata = 0;
- d.relatedMetaObjects = NULL;
- d.static_metacall = NULL;
-
- m_d->m_className = className;
- m_d->m_methodOffset = metaObject->methodCount() - 1;
- m_d->m_propertyOffset = metaObject->propertyCount() - 1;
+ m_d->addInfo(key, value);
}
-DynamicQMetaObject::~DynamicQMetaObject()
+void MetaObjectBuilderPrivate::addInfo(const QMap<QByteArray, QByteArray> &info)
{
- free(reinterpret_cast<char *>(const_cast<QByteArrayData *>(d.stringdata)));
- free(const_cast<uint*>(d.data));
- delete m_d;
+ auto builder = ensureBuilder();
+ for (auto i = info.constBegin(), end = info.constEnd(); i != end; ++i)
+ builder->addClassInfo(i.key(), i.value());
+ m_dirty = true;
}
-int DynamicQMetaObject::addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type)
+void MetaObjectBuilder::addInfo(const QMap<QByteArray, QByteArray> &info)
{
- int index = -1;
- int counter = 0;
-
- QList<MethodData>::iterator it = m_d->m_methods.begin();
- for (; it != m_d->m_methods.end(); ++it) {
- if ((it->signature() == signature) && (it->methodType() == mtype))
- return m_d->m_methodOffset + counter;
- else if (!it->isValid()) {
- index = counter;
- }
- counter++;
- }
-
- // Common mistake not to add parentheses to the signature.
- if ((strchr(signature, ')') == 0) || ((strchr(signature, '(') == 0))) {
- const QString message =
- QLatin1String("DynamicQMetaObject::addMethod: Invalid method signature "
- "provided for ") + QLatin1String(signature);
- const QByteArray messageLatin = message.toLatin1();
- PyErr_WarnEx(PyExc_RuntimeWarning, messageLatin.constData(), 0);
- return -1;
- }
-
- //has blank method
- if (index != -1) {
- m_d->m_methods[index] = MethodData(mtype, signature, type);
- index++;
- } else {
- m_d->m_methods << MethodData(mtype, signature, type);
- index = m_d->m_methods.size();
- }
-
- m_d->m_updated = false;
- return m_d->m_methodOffset + index;
+ m_d->addInfo(info);
}
-void DynamicQMetaObject::removeMethod(QMetaMethod::MethodType mtype, uint index)
+void MetaObjectBuilderPrivate::removeProperty(int index)
{
- const char* methodSig = method(index).methodSignature();
- QList<MethodData>::iterator it = m_d->m_methods.begin();
- for (; it != m_d->m_methods.end(); ++it) {
- if ((it->signature() == methodSig) && (it->methodType() == mtype)){
- it->clear();
- m_d->m_updated = false;
- break;
- }
- }
-}
-
-int DynamicQMetaObject::addSignal(const char* signal, const char* type)
-{
- return addMethod(QMetaMethod::Signal, signal, type);
+ index -= m_baseObject->propertyCount();
+ auto builder = ensureBuilder();
+ Q_ASSERT(index >= 0 && index < builder->propertyCount());
+ builder->removeProperty(index);
+ m_dirty = true;
}
-int DynamicQMetaObject::addSlot(const char* slot, const char* type)
+void MetaObjectBuilder::removeProperty(int index)
{
- return addMethod(QMetaMethod::Slot, slot, type);
+ m_d->removeProperty(index);
}
-void DynamicQMetaObject::removeSlot(uint index)
-{
- removeMethod(QMetaMethod::Slot, index);
-}
-
-void DynamicQMetaObject::removeSignal(uint index)
-{
- removeMethod(QMetaMethod::Signal, index);
-}
+// PYSIDE-315: Instead of sorting the items and maybe breaking indices, we
+// ensure that the signals and slots are sorted by the improved
+// parsePythonType() (signals must go before slots). The order can only
+// become distorted if the class is modified after creation. In that
+// case, we give a warning.
-int DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data)
+static QString msgMethodSortOrder(const QMetaObject *mo, int offendingIndex)
{
- int index = m_d->m_properties.indexOf(propertyName);
- if (index != -1)
- return m_d->m_propertyOffset + index;
-
- // retrieve notifyId
- PySideProperty *property = reinterpret_cast<PySideProperty *>(data);
- const int notifyId = m_d->getPropertyNotifyId(property);
-
- //search for a empty space
- PropertyData blank;
- index = m_d->m_properties.indexOf(blank);
- if (index != -1) {
- m_d->m_properties[index] = PropertyData(propertyName, notifyId, property);
- } else {
- m_d->m_properties << PropertyData(propertyName, notifyId, property);
- index = m_d->m_properties.size();
+ QString result;
+ QTextStream str(&result);
+ str << "\n\n*** Sort Warning ***\nSignals and slots in QMetaObject '"
+ << mo->className()
+ << "' are not ordered correctly, this may lead to issues.\n";
+ const int methodOffset = mo->methodOffset();
+ for (int m = methodOffset, methodCount = mo->methodCount(); m < methodCount; ++m) {
+ const auto method = mo->method(m);
+ str << (m - methodOffset + 1) << (m > offendingIndex ? '!' : ' ')
+ << (method.methodType() == QMetaMethod::Signal ? " Signal " : " Slot ")
+ << method.methodSignature() << '\n';
}
- m_d->m_updated = false;
- return m_d->m_propertyOffset + index;
+ return result;
}
-int DynamicQMetaObject::DynamicQMetaObjectPrivate::getPropertyNotifyId(PySideProperty *property) const
+static void checkMethodOrder(const QMetaObject *metaObject)
{
- int notifyId = -1;
- if (property->d->notify) {
- const char *signalNotify = PySide::Property::getNotifyName(property);
- if (signalNotify) {
- const MethodData signalObject(QMetaMethod::Signal, signalNotify, "");
- notifyId = m_methods.indexOf(signalObject);
+ const int lastMethod = metaObject->methodCount() - 1;
+ for (int m = metaObject->methodOffset(); m < lastMethod; ++m) {
+ if (metaObject->method(m).methodType() == QMetaMethod::Slot
+ && metaObject->method(m + 1).methodType() == QMetaMethod::Signal) {
+ const auto message = msgMethodSortOrder(metaObject, m);
+ PyErr_WarnEx(PyExc_RuntimeWarning, qPrintable(message), 0);
+ // Prevent a warning from being turned into an error. We cannot easily unwind.
+ PyErr_Clear();
+ break;
}
}
- return notifyId;
}
-void DynamicQMetaObject::addInfo(const char* key, const char* value)
+const QMetaObject *MetaObjectBuilderPrivate::update()
{
- m_d->m_info[key] = value;
-}
-
-void DynamicQMetaObject::addInfo(QMap<QByteArray, QByteArray> info)
-{
- QMap<QByteArray, QByteArray>::const_iterator i = info.constBegin();
- while (i != info.constEnd()) {
- m_d->m_info[i.key()] = i.value();
- ++i;
- }
- m_d->m_updated = false;
-}
-
-const QMetaObject* DynamicQMetaObject::update() const
-{
- if (!m_d->m_updated) {
- m_d->updateMetaObject(const_cast<DynamicQMetaObject*>(this));
- m_d->m_updated = true;
+ if (!m_builder)
+ return m_baseObject;
+ if (m_cachedMetaObjects.empty() || m_dirty) {
+ m_cachedMetaObjects.push_back(m_builder->toMetaObject());
+ checkMethodOrder(m_cachedMetaObjects.back());
+ m_dirty = false;
}
- return this;
+ return m_cachedMetaObjects.back();
}
-void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList<MethodData>& methods,
- unsigned int** data,
- QLinkedList<QByteArray>& strings,
- int* prtIndex,
- int nullIndex,
- int flags)
+const QMetaObject *MetaObjectBuilder::update()
{
- int index = *prtIndex;
- int paramsIndex = index + methods.count() * 5;
-
- QList<MethodData>::const_iterator it = methods.begin();
-
- if (m_emptyMethod == -1)
- m_emptyMethod = registerString(EMPTY_META_METHOD, strings);
-
- for (; it != methods.end(); ++it) {
- int name_idx = 0;
- int argc = it->parameterCount();
- if (it->signature() != EMPTY_META_METHOD)
- name_idx = registerString(it->name(), strings);
- else
- name_idx = m_emptyMethod; // func name
-
- (*data)[index++] = name_idx;
- (*data)[index++] = argc; // argc (previously: arg name)
- (*data)[index++] = paramsIndex; //parameter index
- (*data)[index++] = nullIndex; // tags
- (*data)[index++] = flags | (it->methodType() == QMetaMethod::Signal ? MethodSignal : MethodSlot);
-
- if (it->methodType() == QMetaMethod::Signal)
- (*data)[13] += 1; //signal count
-
- paramsIndex += 1 + argc * 2;
- }
- *prtIndex = index;
+ return m_d->update();
}
-void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
+void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
{
// Get all non-QObject-derived base types in method resolution order, filtering out the types
// that can't have signals, slots or properties.
@@ -601,9 +431,8 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
|| baseType == reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())
|| baseType == reinterpret_cast<PyTypeObject *>(&PyBaseObject_Type)) {
continue;
- } else {
- basesToCheck.append(baseType);
}
+ basesToCheck.append(baseType);
}
// Prepend the actual type that we are parsing.
@@ -630,8 +459,8 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
if (data->signatures[i])
sig += data->signatures[i];
sig += ')';
- if (d.superdata->indexOfSignal(sig) == -1)
- addSignal(sig, "void");
+ if (m_baseObject->indexOfSignal(sig) == -1)
+ m_builder->addSignal(sig);
}
}
}
@@ -655,7 +484,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
if (Property::checkType(value)) {
// Leave the properties to be registered after signals because they may depend on
// notify signals.
- int index = d.superdata->indexOfProperty(Shiboken::String::toCString(key));
+ int index = m_baseObject->indexOfProperty(Shiboken::String::toCString(key));
if (index == -1)
properties << PropPair(Shiboken::String::toCString(key), value);
} else if (PyFunction_Check(value)) {
@@ -663,239 +492,30 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
if (PyObject_HasAttr(value, slotAttrName)) {
PyObject *signatureList = PyObject_GetAttr(value, slotAttrName);
for (Py_ssize_t i = 0, i_max = PyList_Size(signatureList); i < i_max; ++i) {
- PyObject *signature = PyList_GET_ITEM(signatureList, i);
- QByteArray sig(Shiboken::String::toCString(signature));
+ PyObject *pySignature = PyList_GET_ITEM(signatureList, i);
+ QByteArray signature(Shiboken::String::toCString(pySignature));
// Split the slot type and its signature.
- QList<QByteArray> slotInfo = sig.split(' ');
- int index = d.superdata->indexOfSlot(slotInfo[1]);
- if (index == -1)
- addSlot(slotInfo[1], slotInfo[0]);
+ QByteArray type;
+ const int spacePos = signature.indexOf(' ');
+ if (spacePos != -1) {
+ type = signature.left(spacePos);
+ signature.remove(0, spacePos + 1);
+ }
+ int index = m_baseObject->indexOfSlot(signature);
+ if (index == -1) {
+ if (type.isEmpty() || type == "void") {
+ addSlot(signature);
+ } else {
+ addSlot(signature, type);
+ }
+ }
}
}
}
}
// Register properties
- foreach (const PropPair &propPair, properties)
+ for (const PropPair &propPair : qAsConst(properties))
addProperty(propPair.first, propPair.second);
}
}
-
-/*!
- Allocate the meta data table.
- Returns the index in the table corresponding to the header fields count.
-*/
-int DynamicQMetaObject::DynamicQMetaObjectPrivate::createMetaData(QMetaObject* metaObj, QLinkedList<QByteArray> &strings)
-{
- const int n_methods = m_methods.size();
- const int n_properties = m_properties.size();
- const int n_info = m_info.size();
-
- int header[] = {7, // revision (Used by moc, qmetaobjectbuilder and qdbus)
- 0, // class name index in m_metadata
- n_info, 0, // classinfo and classinfo index
- n_methods, 0, // method count and method list index
- n_properties, 0, // prop count and prop indexes
- 0, 0, // enum count and enum index
- 0, 0, // constructors (since revision 2)
- 0, // flags (since revision 3)
- 0}; // signal count (since revision 4)
-
- const int HEADER_LENGHT = sizeof(header)/sizeof(int);
-
- m_dataSize = HEADER_LENGHT;
- m_dataSize += n_info*2; //class info: name, value
- m_dataSize += n_methods*5; //method: name, argc, parameters, tag, flags
- m_dataSize += n_properties*4; //property: name, type, flags
- m_dataSize += 1; //eod
-
- m_dataSize += aggregateParameterCount(m_methods); // types and parameter names
-
- uint* data = reinterpret_cast<uint*>(realloc(const_cast<uint*>(metaObj->d.data), m_dataSize * sizeof(uint)));
-
- Q_ASSERT(data);
- std::memcpy(data, header, sizeof(header));
-
- metaObj->d.data = data;
-
- return HEADER_LENGHT;
-}
-
-// Writes strings to string data struct.
-// The struct consists of an array of QByteArrayData, followed by a char array
-// containing the actual strings. This format must match the one produced by
-// moc (see generator.cpp).
-void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeStringData(char *out, QLinkedList<QByteArray> &strings)
-{
- Q_ASSERT(!(reinterpret_cast<quintptr>(out) & (Q_ALIGNOF(QByteArrayData)-1)));
-
- int offsetOfStringdataMember = strings.size() * sizeof(QByteArrayData);
- int stringdataOffset = 0;
- int i = 0;
- foreach(const QByteArray& str, strings) {
- writeString(out, i, str, offsetOfStringdataMember, stringdataOffset);
- i++;
- }
-}
-
-QList<MethodData>::iterator is_sorted_until(QList<MethodData>::iterator first,
- QList<MethodData>::iterator last,
- bool comp(const MethodData &m1, const MethodData &m2))
-{
- if (first != last) {
- QList<MethodData>::iterator next = first;
- while (++next != last) {
- if (comp(*next, *first))
- return next;
- ++first;
- }
- }
- return last;
-}
-
-bool is_sorted(QList<MethodData>::iterator first, QList<MethodData>::iterator last,
- bool comp(const MethodData &m1, const MethodData &m2))
-{
- return is_sorted_until(first, last, comp) == last;
-}
-
-void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject* metaObj)
-{
- Q_ASSERT(!m_updated);
- uint *data = const_cast<uint*>(metaObj->d.data);
- int index = 0;
- QLinkedList<QByteArray> strings;
- m_dataSize = 0;
-
- // Recompute the size and reallocate memory
- // index is set after the last header field.
- index = createMetaData(metaObj, strings);
- data = const_cast<uint*>(metaObj->d.data);
-
- registerString(m_className, strings); // register class string
- m_nullIndex = registerString("", strings); // register a null string
-
- // Write class info.
- if (m_info.size()) {
- if (data[3] == 0)
- data[3] = index;
-
- QMap<QByteArray, QByteArray>::const_iterator i = m_info.constBegin(); //TODO: info is a hash this can fail
- while (i != m_info.constEnd()) {
- int valueIndex = registerString(i.value(), strings);
- int keyIndex = registerString(i.key(), strings);
- data[index++] = keyIndex;
- data[index++] = valueIndex;
- i++;
- }
- }
-
- // Write methods first, then properties, to be consistent with moc.
- // Write signals/slots (signals must be written first, see indexOfMethodRelative in
- // qmetaobject.cpp).
-
- QList<MethodData>::iterator it;
- // PYSIDE-315: Instead of sorting the items and maybe breaking indices,
- // we ensure that the signals and slots are sorted by the improved parsePythonType().
- // The order can only become distorted if the class is modified after creation.
- // In that case, we give a warning.
- if (!is_sorted(m_methods.begin(), m_methods.end(), sortMethodSignalSlot)) {
- const char *metaObjectName = this->m_className.data();
- PyObject *txt = PyBytes_FromFormat("\n\n*** Sort Warning ***\n"
- "Signals and slots in QMetaObject '%s' are not ordered correctly, "
- "this may lead to issues.\n", metaObjectName);
- it = m_methods.begin();
- QList<MethodData>::iterator end = m_methods.end();
- QList<MethodData>::iterator until = is_sorted_until(m_methods.begin(), m_methods.end(),
- sortMethodSignalSlot);
- for (; it != end; ++it) {
- PyObject *atxt = PyBytes_FromFormat("%d%s %s %s\n", it - m_methods.begin() + 1,
- until >= it + 1 ? " " : "!",
- it->methodType() == QMetaMethod::Signal ? "Signal" : "Slot ",
- it->signature().data() );
- PyBytes_ConcatAndDel(&txt, atxt);
- }
- PyErr_WarnEx(PyExc_RuntimeWarning, PyBytes_AsString(txt), 0);
- Py_DECREF(txt);
- // Prevent a warning from being turned into an error. We cannot easily unwind.
- PyErr_Clear();
- }
-
- if (m_methods.size()) {
- if (data[5] == 0)
- data[5] = index;
-
- writeMethodsData(m_methods, &data, strings, &index, m_nullIndex, AccessPublic);
- }
-
- // Write signal/slots parameters.
- if (m_methods.size()) {
- for (it = m_methods.begin(); it != m_methods.end(); ++it) {
- QList<QByteArray> paramTypeNames = it->parameterTypes();
- int paramCount = paramTypeNames.size();
- for (int i = -1; i < paramCount; ++i) {
- const QByteArray &typeName = (i < 0) ? it->returnType() : paramTypeNames.at(i);
- int typeInfo;
- if (QtPrivate::isBuiltinType(typeName))
- typeInfo = QMetaType::type(typeName);
- else
- typeInfo = IsUnresolvedType | registerString(typeName, strings);
- data[index++] = typeInfo;
- }
-
- // Parameter names (use a null string)
- for (int i = 0; i < paramCount; ++i) {
- data[index++] = m_nullIndex;
- }
- }
- }
-
- // Write properties.
- if (m_properties.size()) {
- if (data[7] == 0)
- data[7] = index;
-
- QList<PropertyData>::const_iterator i = m_properties.constBegin();
- while (i != m_properties.constEnd()) {
- if (i->isValid()) {
- data[index++] = registerString(i->name(), strings); // name
- } else
- data[index++] = m_nullIndex;
-
- // Find out the property type index.
- int typeInfo = m_nullIndex;
- if (i->isValid()) {
- const QByteArray &typeName = i->type();
- if (QtPrivate::isBuiltinType(typeName))
- typeInfo = QMetaType::type(typeName);
- else
- typeInfo = IsUnresolvedType | registerString(typeName, strings);
- }
- data[index++] = typeInfo; // normalized type
-
- data[index++] = i->flags();
- i++;
- }
-
- // Write properties notify.
- i = m_properties.constBegin();
- while (i != m_properties.constEnd()) {
- // Recompute notifyId, because sorting the methods might have changed the relative
- // index.
- const int notifyId = getPropertyNotifyId(i->data());
- data[index++] = notifyId >= 0 ? static_cast<uint>(notifyId) : 0; //signal notify index
- i++;
- }
- }
-
- data[index++] = 0; // the end
-
- // Create the m_metadata string.
- int size = blobSize(strings);
- char *blob =
- reinterpret_cast<char *>(realloc(reinterpret_cast<char *>(const_cast<QByteArrayData *>(metaObj->d.stringdata)), size));
- writeStringData(blob, strings);
-
- metaObj->d.stringdata = reinterpret_cast<const QByteArrayData *>(blob);
- metaObj->d.data = data;
-}
diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.h b/sources/pyside2/libpyside/dynamicqmetaobject.h
index 5ecce50c9..1fbe73ea4 100644
--- a/sources/pyside2/libpyside/dynamicqmetaobject.h
+++ b/sources/pyside2/libpyside/dynamicqmetaobject.h
@@ -40,43 +40,42 @@
#ifndef DYNAMICQMETAOBJECT_H
#define DYNAMICQMETAOBJECT_H
-#include "pysidemacros.h"
#include <sbkpython.h>
-#include <QMetaObject>
-#include <QMetaMethod>
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QMetaMethod>
+
+class MetaObjectBuilderPrivate;
namespace PySide
{
-class DynamicQMetaObject : public QMetaObject
+class MetaObjectBuilder
{
+ Q_DISABLE_COPY(MetaObjectBuilder)
public:
- DynamicQMetaObject(const char* className, const QMetaObject* metaObject);
- DynamicQMetaObject(PyTypeObject* type, const QMetaObject* metaobject);
- ~DynamicQMetaObject();
+ MetaObjectBuilder(const char *className, const QMetaObject *metaObject);
+ MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject);
+ ~MetaObjectBuilder();
- int addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type);
- void removeMethod(QMetaMethod::MethodType mtype, uint index);
- int addSignal(const char* signal, const char* type = 0);
- int addSlot(const char* slot, const char* type = 0);
- int addProperty(const char* property, PyObject* data);
- void addInfo(const char* key, const char* value);
- void addInfo(QMap<QByteArray, QByteArray> info);
+ int indexOfMethod(QMetaMethod::MethodType mtype, const QByteArray &signature) const;
+ int indexOfProperty(const QByteArray &name) const;
+ int addSlot(const char *signature);
+ int addSlot(const char *signature, const char *type);
+ int addSignal(const char *signature);
+ void removeMethod(QMetaMethod::MethodType mtype, int index);
+ int addProperty(const char *property, PyObject *data);
+ void addInfo(const char *key, const char *value);
+ void addInfo(const QMap<QByteArray, QByteArray> &info);
- void removeSignal(uint idex);
- void removeSlot(uint index);
- void removeProperty(uint index);
+ void removeProperty(int index);
- const QMetaObject* update() const;
+ const QMetaObject *update();
private:
- class DynamicQMetaObjectPrivate;
- DynamicQMetaObjectPrivate* m_d;
-
- void parsePythonType(PyTypeObject *type);
+ MetaObjectBuilderPrivate *m_d;
};
-
}
#endif
diff --git a/sources/pyside2/libpyside/dynamicqmetaobject_p.h b/sources/pyside2/libpyside/dynamicqmetaobject_p.h
index 219ffc4e3..738b950ba 100644
--- a/sources/pyside2/libpyside/dynamicqmetaobject_p.h
+++ b/sources/pyside2/libpyside/dynamicqmetaobject_p.h
@@ -41,8 +41,9 @@
#define DYNAMICMETAPROPERTY_P_H
#include <sbkpython.h>
-#include <QByteArray>
-#include <QMetaMethod>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QMetaMethod>
#define GLOBAL_RECEIVER_CLASS_NAME "__GlobalReceiver__"
diff --git a/sources/pyside2/libpyside/globalreceiver.cpp b/sources/pyside2/libpyside/globalreceiver.cpp
deleted file mode 100644
index ee1f6354a..000000000
--- a/sources/pyside2/libpyside/globalreceiver.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "globalreceiver.h"
-#include "dynamicqmetaobject_p.h"
-#include "pysideweakref.h"
-
-#include <QMetaMethod>
-#include <QDebug>
-#include <QEvent>
-#include <QLinkedList>
-#include <autodecref.h>
-#include <sbkconverter.h>
-#include <gilstate.h>
-
-#include "signalmanager.h"
-
-#define RECEIVER_DESTROYED_SLOT_NAME "__receiverDestroyed__(QObject*)"
-
-namespace PySide
-{
-class DynamicSlotData
-{
- public:
- DynamicSlotData(int id, PyObject* callback, GlobalReceiver* parent);
- void addRef(const QObject* o);
- void decRef(const QObject* o);
- void clear();
- int hasRefTo(const QObject* o) const;
- int refCount() const;
- int id() const;
- PyObject* call(PyObject* args);
- ~DynamicSlotData();
- static void onCallbackDestroyed(void* data);
-
- private:
- int m_id;
- bool m_isMethod;
- PyObject* m_callback;
- PyObject* m_pythonSelf;
- PyObject* m_pyClass;
- PyObject* m_weakRef;
- GlobalReceiver* m_parent;
- QLinkedList<const QObject*> m_refs;
-};
-
-}
-
-using namespace PySide;
-
-DynamicSlotData::DynamicSlotData(int id, PyObject* callback, GlobalReceiver* parent)
- : m_id(id), m_pythonSelf(0), m_pyClass(0), m_weakRef(0), m_parent(parent)
-{
- Shiboken::GilState gil;
-
- m_isMethod = PyMethod_Check(callback);
- if (m_isMethod) {
- //Can not store calback pointe because this will be destroyed at the end of the scope
- //To avoid increment intance reference keep the callback information
- m_callback = PyMethod_GET_FUNCTION(callback);
-#ifdef IS_PY3K
- m_pyClass = 0;
-#else
- m_pyClass = PyMethod_GET_CLASS(callback);
-#endif
-
- m_pythonSelf = PyMethod_GET_SELF(callback);
-
- //monitor class from method lifetime
- m_weakRef = WeakRef::create(m_pythonSelf, DynamicSlotData::onCallbackDestroyed, this);
- } else {
- m_callback = callback;
- Py_INCREF(m_callback);
- }
-}
-
-PyObject* DynamicSlotData::call(PyObject* args)
-{
- PyObject* callback = m_callback;
-
- //create a callback based on method data
- Shiboken::GilState gil;
- if (m_isMethod)
-#ifdef IS_PY3K
- callback = PyMethod_New(callback, m_pythonSelf);
-#else
- callback = PyMethod_New(callback, m_pythonSelf, m_pyClass);
-#endif
-
- PyObject* result = PyObject_CallObject(callback, args);
-
- if (m_isMethod)
- Py_DECREF(callback);
-
- return result;
-}
-
-void DynamicSlotData::addRef(const QObject *o)
-{
- m_refs.append(o);
-}
-
-void DynamicSlotData::decRef(const QObject *o)
-{
- m_refs.removeOne(o);
-}
-
-int DynamicSlotData::refCount() const
-{
- return m_refs.size();
-}
-
-int DynamicSlotData::id() const
-{
- return m_id;
-}
-
-int DynamicSlotData::hasRefTo(const QObject *o) const
-{
- return m_refs.count(o);
-}
-
-void DynamicSlotData::clear()
-{
- Shiboken::GilState gil;
- Py_XDECREF(m_weakRef);
- m_weakRef = 0;
- m_refs.clear();
-}
-
-DynamicSlotData::~DynamicSlotData()
-{
- Shiboken::GilState gil;
- clear();
- if (!m_isMethod)
- Py_DECREF(m_callback);
-}
-
-void DynamicSlotData::onCallbackDestroyed(void *data)
-{
- Shiboken::GilState gil;
- DynamicSlotData* self = reinterpret_cast<DynamicSlotData*>(data);
-
- //Disconnect all sources
- QMetaMethod m = self->m_parent->metaObject()->method(self->m_id);
- QByteArray methodName = QByteArray::number(m.methodType()).append(m.methodSignature());
- QLinkedList<const QObject*> sources = self->m_refs;
- foreach(const QObject* src, sources)
- const_cast<QObject*>(src)->disconnect(self->m_parent, methodName);
- self->m_weakRef = 0;
-}
-
-GlobalReceiver::GlobalReceiver()
- : m_metaObject(GLOBAL_RECEIVER_CLASS_NAME, &QObject::staticMetaObject)
-{
- //slot used to be notifyed of object destrouction
- m_metaObject.addSlot(RECEIVER_DESTROYED_SLOT_NAME);
- m_metaObject.update();
- setObjectName(QLatin1String("GLOBAL RECEIVER"));
-}
-
-GlobalReceiver::~GlobalReceiver()
-{
- while(!m_slotReceivers.empty()) {
- DynamicSlotData* data = m_slotReceivers.take(m_slotReceivers.begin().key());
- data->clear();
- delete data;
- }
-}
-
-void GlobalReceiver::connectNotify(QObject* source, int slotId)
-{
- if (m_slotReceivers.contains(slotId)) {
- DynamicSlotData* data = m_slotReceivers[slotId];
- if (!data->hasRefTo(source))
- QObject::connect(source, SIGNAL(destroyed(QObject*)), this, "1" RECEIVER_DESTROYED_SLOT_NAME);
- data->addRef(source);
- }
-}
-
-void GlobalReceiver::disconnectNotify(QObject* source, int slotId)
-{
- if (m_slotReceivers.contains(slotId)) {
- DynamicSlotData *data = m_slotReceivers[slotId];
- data->decRef(source);
- if (data->refCount() == 0)
- removeSlot(slotId);
-
- if (!hasConnectionWith(source))
- QObject::disconnect(source, SIGNAL(destroyed(QObject*)), this, "1" RECEIVER_DESTROYED_SLOT_NAME);
- }
-}
-
-const QMetaObject* GlobalReceiver::metaObject() const
-{
- return m_metaObject.update();
-}
-
-int GlobalReceiver::addSlot(const char* slot, PyObject* callback)
-{
- int slotId = m_metaObject.addSlot(slot);
- if (!m_slotReceivers.contains(slotId))
- m_slotReceivers[slotId] = new DynamicSlotData(slotId, callback, this);
-
- bool isShortCircuit = true;
- for (int i = 0; slot[i]; ++i) {
- if (slot[i] == '(') {
- isShortCircuit = false;
- break;
- }
- }
-
- if (isShortCircuit)
- m_shortCircuitSlots << slotId;
-
- Q_ASSERT(slotId >= QObject::staticMetaObject.methodCount());
- return slotId;
-}
-
-void GlobalReceiver::removeSlot(int slotId)
-{
- if (m_slotReceivers.contains(slotId)) {
- delete m_slotReceivers.take(slotId);
- m_metaObject.removeSlot(slotId);
- m_shortCircuitSlots.remove(slotId);
- }
-}
-
-bool GlobalReceiver::hasConnectionWith(const QObject *object)
-{
- QHash<int, DynamicSlotData*>::iterator i = m_slotReceivers.begin();
- while(i != m_slotReceivers.end()) {
- if (i.value()->hasRefTo(object)) {
- return true;
- }
- i++;
- }
- return false;
-}
-
-int GlobalReceiver::qt_metacall(QMetaObject::Call call, int id, void** args)
-{
- Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
- Q_ASSERT(id >= QObject::staticMetaObject.methodCount());
- QMetaMethod slot = metaObject()->method(id);
- Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
-
- if (strcmp(slot.methodSignature(), RECEIVER_DESTROYED_SLOT_NAME) == 0) {
- QObject *arg = *(QObject**)args[1];
-
- //avoid hash changes during the destruction
- QHash<int, DynamicSlotData*> copy = m_slotReceivers;
- QHash<int, DynamicSlotData*>::iterator i = copy.begin();
- while(i != copy.end()) {
- //Remove all refs
- int refs = i.value()->hasRefTo(arg);
- while(refs) {
- disconnectNotify(arg, i.key());
- refs--;
- }
- i++;
- }
- return -1;
- }
-
- DynamicSlotData* data = m_slotReceivers.value(id);
- if (!data) {
- qWarning() << "Unknown global slot, id:" << id;
- return -1;
- }
-
- Shiboken::GilState gil;
- PyObject* retval = 0;
- if (m_shortCircuitSlots.contains(id)) {
- retval = data->call(reinterpret_cast<PyObject*>(args[1]));
- } else {
- QList<QByteArray> paramTypes = slot.parameterTypes();
- Shiboken::AutoDecRef preparedArgs(PyTuple_New(paramTypes.count()));
- for (int i = 0, max = paramTypes.count(); i < max; ++i) {
- const QByteArray& paramType = paramTypes[i];
- Shiboken::Conversions::SpecificConverter converter(paramType.constData());
- PyTuple_SET_ITEM(preparedArgs.object(), i, converter.toPython(args[i+1]));
- }
- retval = data->call(preparedArgs);
- }
-
- if (!retval)
- PyErr_Print();
- else
- Py_DECREF(retval);
-
- return -1;
-}
diff --git a/sources/pyside2/libpyside/globalreceiverv2.cpp b/sources/pyside2/libpyside/globalreceiverv2.cpp
index 05565e516..43ce50a75 100644
--- a/sources/pyside2/libpyside/globalreceiverv2.cpp
+++ b/sources/pyside2/libpyside/globalreceiverv2.cpp
@@ -40,15 +40,13 @@
#include "globalreceiverv2.h"
#include "dynamicqmetaobject_p.h"
#include "pysideweakref.h"
+#include "signalmanager.h"
-#include <QMetaMethod>
-#include <QDebug>
-#include <QEvent>
-#include <QLinkedList>
#include <autodecref.h>
#include <gilstate.h>
-#include "signalmanager.h"
+#include <QtCore/QMetaMethod>
+#include <QtCore/QSet>
#define RECEIVER_DESTROYED_SLOT_NAME "__receiverDestroyed__(QObject*)"
@@ -62,6 +60,7 @@ namespace PySide
{
class DynamicSlotDataV2
{
+ Q_DISABLE_COPY(DynamicSlotDataV2)
public:
DynamicSlotDataV2(PyObject* callback, GlobalReceiverV2* parent);
~DynamicSlotDataV2();
@@ -128,11 +127,11 @@ QByteArray DynamicSlotDataV2::hash() const
QByteArray DynamicSlotDataV2::hash(PyObject* callback)
{
Shiboken::GilState gil;
- if (PyMethod_Check(callback))
+ if (PyMethod_Check(callback)) {
return QByteArray::number((qlonglong)PyObject_Hash(PyMethod_GET_FUNCTION(callback)))
+ QByteArray::number((qlonglong)PyObject_Hash(PyMethod_GET_SELF(callback)));
- else
- return QByteArray::number((qlonglong)PyObject_Hash(callback));
+ }
+ return QByteArray::number(qlonglong(PyObject_Hash(callback)));
}
PyObject* DynamicSlotDataV2::callback()
@@ -154,18 +153,15 @@ PyObject* DynamicSlotDataV2::callback()
int DynamicSlotDataV2::id(const char* signature) const
{
- if (m_signatures.contains(signature))
- return m_signatures[signature];
- return -1;
+ const auto it = m_signatures.constFind(signature);
+ return it != m_signatures.cend() ? it.value() : -1;
}
int DynamicSlotDataV2::addSlot(const char* signature)
{
int index = id(signature);
- if (index == -1) {
- DynamicQMetaObject *dmo = const_cast<DynamicQMetaObject*>(reinterpret_cast<const DynamicQMetaObject*>(m_parent->metaObject()));
- index = m_signatures[signature] = dmo->addSlot(signature);
- }
+ if (index == -1)
+ index = m_signatures[signature] = m_parent->metaObjectBuilder().addSlot(signature);
return index;
}
@@ -189,8 +185,10 @@ DynamicSlotDataV2::~DynamicSlotDataV2()
Py_DECREF(m_callback);
}
-GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map)
- : QObject(0), m_metaObject(GLOBAL_RECEIVER_CLASS_NAME, &QObject::staticMetaObject), m_sharedMap(map)
+GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map) :
+ QObject(nullptr),
+ m_metaObject(GLOBAL_RECEIVER_CLASS_NAME, &QObject::staticMetaObject),
+ m_sharedMap(std::move(map))
{
m_data = new DynamicSlotDataV2(callback, this);
m_metaObject.addSlot(RECEIVER_DESTROYED_SLOT_NAME);
@@ -202,7 +200,7 @@ GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map)
DESTROY_SIGNAL_ID = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
if (DESTROY_SLOT_ID == 0)
- DESTROY_SLOT_ID = m_metaObject.indexOfSlot(RECEIVER_DESTROYED_SLOT_NAME);
+ DESTROY_SLOT_ID = m_metaObject.indexOfMethod(QMetaMethod::Slot, RECEIVER_DESTROYED_SLOT_NAME);
}
@@ -251,7 +249,7 @@ void GlobalReceiverV2::incRef(const QObject* link)
void GlobalReceiverV2::decRef(const QObject* link)
{
- if (m_refs.size() <= 0)
+ if (m_refs.empty())
return;
@@ -268,7 +266,7 @@ void GlobalReceiverV2::decRef(const QObject* link)
}
}
- if (m_refs.size() == 0)
+ if (m_refs.empty())
Py_BEGIN_ALLOW_THREADS
delete this;
Py_END_ALLOW_THREADS
@@ -285,9 +283,9 @@ int GlobalReceiverV2::refCount(const QObject* link) const
void GlobalReceiverV2::notify()
{
- QSet<const QObject*> objs = QSet<const QObject*>::fromList(m_refs);
+ const auto objSet = QSet<const QObject*>::fromList(m_refs);
Py_BEGIN_ALLOW_THREADS
- foreach(const QObject* o, objs) {
+ for (const QObject *o : objSet) {
QMetaObject::disconnect(o, DESTROY_SIGNAL_ID, this, DESTROY_SLOT_ID);
QMetaObject::connect(o, DESTROY_SIGNAL_ID, this, DESTROY_SLOT_ID);
}
@@ -306,7 +304,7 @@ QByteArray GlobalReceiverV2::hash(PyObject* callback)
const QMetaObject* GlobalReceiverV2::metaObject() const
{
- return m_metaObject.update();
+ return const_cast<GlobalReceiverV2 *>(this)->m_metaObject.update();
}
int GlobalReceiverV2::qt_metacall(QMetaObject::Call call, int id, void** args)
@@ -328,9 +326,9 @@ int GlobalReceiverV2::qt_metacall(QMetaObject::Call call, int id, void** args)
}
if (id == DESTROY_SLOT_ID) {
- if (m_refs.size() == 0)
+ if (m_refs.empty())
return -1;
- QObject *obj = *(QObject**)args[1];
+ QObject *obj = *reinterpret_cast<QObject**>(args[1]);
incRef(); //keep the object live (safe ref)
m_refs.removeAll(obj); // remove all refs to this object
decRef(); //remove the safe ref
diff --git a/sources/pyside2/libpyside/globalreceiverv2.h b/sources/pyside2/libpyside/globalreceiverv2.h
index 880719d6f..b92be93a8 100644
--- a/sources/pyside2/libpyside/globalreceiverv2.h
+++ b/sources/pyside2/libpyside/globalreceiverv2.h
@@ -41,15 +41,14 @@
#define GLOBALRECEIVER_V2_H
#include <sbkpython.h>
-#include <QObject>
-#include <QHash>
-#include <QSet>
-#include <QSharedPointer>
-#include <QLinkedList>
-#include <QByteArray>
#include "dynamicqmetaobject.h"
+#include <QtCore/QByteArray>
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QSharedPointer>
+
namespace PySide
{
@@ -78,13 +77,13 @@ public:
/**
* Destructor
**/
- ~GlobalReceiverV2();
+ ~GlobalReceiverV2() override;
/**
* Reimplemented function from QObject
**/
- int qt_metacall(QMetaObject::Call call, int id, void** args);
- const QMetaObject* metaObject() const;
+ int qt_metacall(QMetaObject::Call call, int id, void** args) override;
+ const QMetaObject* metaObject() const override;
/**
* Add a extra slot to this object
@@ -122,22 +121,25 @@ public:
int refCount(const QObject* link) const;
/**
- * Use to retrive the unique hash of this GlobalReceiver object
+ * Use to retrieve the unique hash of this GlobalReceiver object
*
* @return a string with a unique id based on GlobalReceiver contents
**/
QByteArray hash() const;
/**
- * Use to retrive the unique hash of the PyObject based on GlobalReceiver rules
+ * Use to retrieve the unique hash of the PyObject based on GlobalReceiver rules
*
* @param callback The Python callable object used to calculate the id
* @return a string with a unique id based on GlobalReceiver contents
**/
static QByteArray hash(PyObject* callback);
+ const MetaObjectBuilder &metaObjectBuilder() const { return m_metaObject; }
+ MetaObjectBuilder &metaObjectBuilder() { return m_metaObject; }
+
private:
- DynamicQMetaObject m_metaObject;
+ MetaObjectBuilder m_metaObject;
DynamicSlotDataV2 *m_data;
QList<const QObject*> m_refs;
SharedMap m_sharedMap;
diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp
index b4f7d8771..6e4a3efd4 100644
--- a/sources/pyside2/libpyside/pyside.cpp
+++ b/sources/pyside2/libpyside/pyside.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "pyside.h"
+#include "pyside_p.h"
#include "signalmanager.h"
#include "pysideclassinfo_p.h"
#include "pysideproperty_p.h"
@@ -51,23 +52,24 @@
#include "destroylistener.h"
#include <autodecref.h>
-#include <qapp_macro.h>
#include <basewrapper.h>
+#include <bindingmanager.h>
+#include <gilstate.h>
#include <sbkconverter.h>
#include <sbkstring.h>
-#include <gilstate.h>
-#include <bindingmanager.h>
+#include <qapp_macro.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStack>
+
#include <algorithm>
-#include <typeinfo>
#include <cstring>
#include <cctype>
-#include <QByteArray>
-#include <QCoreApplication>
-#include <QDebug>
-#include <QDir>
-#include <QFileInfo>
-#include <QSharedPointer>
-#include <QStack>
+#include <typeinfo>
static QStack<PySide::CleanupFunction> cleanupFunctionList;
static void* qobjectNextAddr;
@@ -188,29 +190,21 @@ void destroyQCoreApplication()
MakeSingletonQAppWrapper(NULL);
}
-struct TypeUserData {
- TypeUserData(PyTypeObject* type, const QMetaObject* metaobject) : mo(type, metaobject) {}
- DynamicQMetaObject mo;
- std::size_t cppObjSize;
-};
-
std::size_t getSizeOfQObject(SbkObjectType* type)
{
- using namespace Shiboken::ObjectType;
- TypeUserData* userData = reinterpret_cast<TypeUserData*>(getTypeUserData(reinterpret_cast<SbkObjectType*>(type)));
- return userData->cppObjSize;
+ return retrieveTypeUserData(type)->cppObjSize;
}
-void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, const std::size_t& cppObjSize)
+void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, std::size_t cppObjSize)
{
//create DynamicMetaObject based on python type
- TypeUserData* userData = new TypeUserData(reinterpret_cast<PyTypeObject*>(type), base);
- userData->cppObjSize = cppObjSize;
+ auto userData =
+ new TypeUserData(reinterpret_cast<PyTypeObject*>(type), base, cppObjSize);
userData->mo.update();
Shiboken::ObjectType::setTypeUserData(type, userData, Shiboken::callCppDestructor<TypeUserData>);
//initialize staticQMetaObject property
- void* metaObjectPtr = &userData->mo;
+ void *metaObjectPtr = const_cast<QMetaObject *>(userData->mo.update());
static SbkConverter* converter = Shiboken::Conversions::getConverter("QMetaObject");
if (!converter)
return;
@@ -218,6 +212,36 @@ void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, const s
PyObject_SetAttrString(reinterpret_cast<PyObject*>(type), "staticMetaObject", pyMetaObject);
}
+TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj)
+{
+ return reinterpret_cast<TypeUserData *>(Shiboken::ObjectType::getTypeUserData(sbkTypeObj));
+}
+
+TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj)
+{
+ return retrieveTypeUserData(reinterpret_cast<SbkObjectType *>(pyTypeObj));
+}
+
+TypeUserData *retrieveTypeUserData(PyObject *pyObj)
+{
+ auto pyTypeObj = PyType_Check(pyObj)
+ ? reinterpret_cast<PyTypeObject *>(pyObj) : Py_TYPE(pyObj);
+ return retrieveTypeUserData(pyTypeObj);
+}
+
+const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj)
+{
+ TypeUserData *userData = retrieveTypeUserData(pyTypeObj);
+ return userData ? userData->mo.update() : nullptr;
+}
+
+const QMetaObject *retrieveMetaObject(PyObject *pyObj)
+{
+ auto pyTypeObj = PyType_Check(pyObj)
+ ? reinterpret_cast<PyTypeObject *>(pyObj) : Py_TYPE(pyObj);
+ return retrieveMetaObject(pyTypeObj);
+}
+
void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base)
{
initDynamicMetaObject(type, base, 0);
@@ -230,25 +254,21 @@ void initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject * /* kwds
PyObject* bases = PyTuple_GET_ITEM(args, 1);
int numBases = PyTuple_GET_SIZE(bases);
- QMetaObject* baseMo = 0;
- SbkObjectType* qobjBase = 0;
+
+ TypeUserData *userData = nullptr;
for (int i = 0; i < numBases; ++i) {
PyTypeObject* base = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i));
if (PyType_IsSubtype(base, qObjType)) {
- baseMo = reinterpret_cast<QMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(base)));
- qobjBase = reinterpret_cast<SbkObjectType*>(base);
- reinterpret_cast<DynamicQMetaObject*>(baseMo)->update();
+ userData = retrieveTypeUserData(base);
break;
}
}
- if (!baseMo) {
+ if (!userData) {
qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.", className.constData());
return;
}
-
- TypeUserData* userData = reinterpret_cast<TypeUserData*>(Shiboken::ObjectType::getTypeUserData(qobjBase));
- initDynamicMetaObject(type, baseMo, userData->cppObjSize);
+ initDynamicMetaObject(type, userData->mo.update(), userData->cppObjSize);
}
PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* name)
@@ -299,7 +319,7 @@ PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* nam
}
}
}
- if (signalList.size() > 0) {
+ if (!signalList.empty()) {
PyObject* pySignal = reinterpret_cast<PyObject*>(Signal::newObjectFromMethod(self, signalList));
PyObject_SetAttr(self, name, pySignal);
return pySignal;
@@ -366,7 +386,7 @@ PyObject* getWrapperForQObject(QObject* cppSelf, SbkObjectType* sbk_type)
// set and check if it's created after the set call
QVariant existing = cppSelf->property(invalidatePropertyName);
if (!existing.isValid()) {
- QSharedPointer<any_t> shared_with_del((any_t*)cppSelf, invalidatePtr);
+ QSharedPointer<any_t> shared_with_del(reinterpret_cast<any_t*>(cppSelf), invalidatePtr);
cppSelf->setProperty(invalidatePropertyName, QVariant::fromValue(shared_with_del));
pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppSelf));
if (pyOut) {
diff --git a/sources/pyside2/libpyside/pyside.h b/sources/pyside2/libpyside/pyside.h
index e2e108ed8..b53048eba 100644
--- a/sources/pyside2/libpyside/pyside.h
+++ b/sources/pyside2/libpyside/pyside.h
@@ -41,16 +41,15 @@
#define PYSIDE_H
#include <sbkpython.h>
+
#include <pysidemacros.h>
#ifdef PYSIDE_QML_SUPPORT
-# include <qqml.h>
+# include <QtQml/qqml.h>
#endif
-#include <QMetaType>
-#include <QHash>
-#include <QList>
-#include <QLoggingCategory>
+#include <QtCore/QMetaType>
+#include <QtCore/QHash>
struct SbkObjectType;
@@ -101,7 +100,8 @@ struct initQtMetaType<T, false> {
};
PYSIDE_DEPRECATED(PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base));
-PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, const std::size_t& cppObjSize);
+PYSIDE_API void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base,
+ std::size_t cppObjSize);
PYSIDE_API void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds);
/// Return the size in bytes of a type that inherits QObject.
diff --git a/sources/pyside2/libpyside/globalreceiver.h b/sources/pyside2/libpyside/pyside_p.h
index 426d40bfe..1084a40a1 100644
--- a/sources/pyside2/libpyside/globalreceiver.h
+++ b/sources/pyside2/libpyside/pyside_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -37,44 +37,35 @@
**
****************************************************************************/
-#ifndef GLOBALRECEIVER_H
-#define GLOBALRECEIVER_H
+#ifndef PYSIDE_P_H
+#define PYSIDE_P_H
-#include <sbkpython.h>
-#include <QObject>
-#include <QHash>
-#include <QSet>
-#include "dynamicqmetaobject.h"
+#include <pysidemacros.h>
-namespace PySide
-{
+#include <dynamicqmetaobject.h>
-class DynamicSlotData;
+struct SbkObjectType;
-class GlobalReceiver : public QObject
+namespace PySide
{
-public:
- GlobalReceiver();
- ~GlobalReceiver();
- int qt_metacall(QMetaObject::Call call, int id, void** args);
- const QMetaObject* metaObject() const;
- int addSlot(const char* slot, PyObject* callback);
- void removeSlot(int slotId);
- void connectNotify(QObject* sender, int slotId);
- void disconnectNotify(QObject* sender, int slotId);
- bool hasConnectionWith(const QObject* object);
-protected:
- using QObject::connectNotify;
- using QObject::disconnectNotify;
+// Struct associated with QObject's via Shiboken::Object::getTypeUserData()
+struct TypeUserData
+{
+ explicit TypeUserData(PyTypeObject* type, const QMetaObject* metaobject, std::size_t size) :
+ mo(type, metaobject), cppObjSize(size) {}
-private:
- DynamicQMetaObject m_metaObject;
- QSet<int> m_shortCircuitSlots;
- QHash<int, DynamicSlotData* > m_slotReceivers;
+ MetaObjectBuilder mo;
+ std::size_t cppObjSize;
};
-}
+TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj);
+TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj);
+TypeUserData *retrieveTypeUserData(PyObject *pyObj);
+// For QML
+PYSIDE_API const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj);
+PYSIDE_API const QMetaObject *retrieveMetaObject(PyObject *pyObj);
-#endif
+} //namespace PySide
+#endif // PYSIDE_P_H
diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp
index 5593825c3..4edf0fa91 100644
--- a/sources/pyside2/libpyside/pysideclassinfo.cpp
+++ b/sources/pyside2/libpyside/pysideclassinfo.cpp
@@ -38,12 +38,13 @@
****************************************************************************/
#include <sbkpython.h>
+
#include "pysideclassinfo.h"
+#include "pyside_p.h"
#include "pysideclassinfo_p.h"
#include "dynamicqmetaobject.h"
#include <shiboken.h>
-#include <QDebug>
#define CLASSINFO_CLASS_NAME "ClassInfo"
@@ -74,9 +75,8 @@ static PyType_Spec PySideClassInfoType_spec = {
PyTypeObject *PySideClassInfoTypeF(void)
{
- static PyTypeObject *type = nullptr;
- if (!type)
- type = (PyTypeObject *)PyType_FromSpec(&PySideClassInfoType_spec);
+ static PyTypeObject *type =
+ reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&PySideClassInfoType_spec));
return type;
}
@@ -97,8 +97,7 @@ PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */)
return 0;
}
- PyObject* klass;
- klass = PyTuple_GetItem(args, 0);
+ PyObject *klass = PyTuple_GetItem(args, 0);
bool validClass = false;
// This will sometimes segfault if you mistakenly use it on a function declaration
@@ -107,10 +106,11 @@ PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */)
return 0;
}
- if (Shiboken::ObjectType::checkType(reinterpret_cast<PyTypeObject*>(klass))) {
- PySide::DynamicQMetaObject* mo = reinterpret_cast<PySide::DynamicQMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(klass)));
- if (mo) {
- mo->addInfo(PySide::ClassInfo::getMap(data));
+ PyTypeObject *klassType = reinterpret_cast<PyTypeObject*>(klass);
+ if (Shiboken::ObjectType::checkType(klassType)) {
+ if (auto userData = PySide::retrieveTypeUserData(klassType)) {
+ PySide::MetaObjectBuilder &mo = userData->mo;
+ mo.addInfo(PySide::ClassInfo::getMap(data));
pData->m_alreadyWrapped = true;
validClass = true;
}
diff --git a/sources/pyside2/libpyside/pysideclassinfo.h b/sources/pyside2/libpyside/pysideclassinfo.h
index 910dd9f82..ff60b91c3 100644
--- a/sources/pyside2/libpyside/pysideclassinfo.h
+++ b/sources/pyside2/libpyside/pysideclassinfo.h
@@ -41,9 +41,11 @@
#define PYSIDE_CLASSINFO_H
#include <pysidemacros.h>
+
#include <sbkpython.h>
-#include <QMap>
-#include <QByteArray>
+
+#include <QtCore/QMap>
+#include <QtCore/QByteArray>
extern "C"
{
diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp
index a9fbbc7fc..4cdc7ec16 100644
--- a/sources/pyside2/libpyside/pysidemetafunction.cpp
+++ b/sources/pyside2/libpyside/pysidemetafunction.cpp
@@ -36,14 +36,13 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include <sbkpython.h>
+
#include "pysidemetafunction.h"
#include "pysidemetafunction_p.h"
#include <shiboken.h>
-#include <QObject>
-#include <QMetaMethod>
-#include <QDebug>
+
+#include <QtCore/QMetaMethod>
extern "C"
{
diff --git a/sources/pyside2/libpyside/pysidemetafunction.h b/sources/pyside2/libpyside/pysidemetafunction.h
index 020f02d49..1085ecb5e 100644
--- a/sources/pyside2/libpyside/pysidemetafunction.h
+++ b/sources/pyside2/libpyside/pysidemetafunction.h
@@ -40,13 +40,12 @@
#ifndef PYSIDE_METAFUNCTION_H
#define PYSIDE_METAFUNCTION_H
-#include <QObject>
-#include <QString>
-#include <QStringList>
-
#include <pysidemacros.h>
+
#include <sbkpython.h>
+#include <QtCore/QObject>
+
extern "C"
{
extern PYSIDE_API PyTypeObject *PySideMetaFunctionTypeF(void);
diff --git a/sources/pyside2/libpyside/pysidemetafunction_p.h b/sources/pyside2/libpyside/pysidemetafunction_p.h
index c3b8fe0c7..442e05ea7 100644
--- a/sources/pyside2/libpyside/pysidemetafunction_p.h
+++ b/sources/pyside2/libpyside/pysidemetafunction_p.h
@@ -41,8 +41,8 @@
#define PYSIDE_METAFUNCTION_P_H
#include <sbkpython.h>
-#include <QList>
-#include <QByteArray>
+
+#include <QtCore/QtGlobal>
QT_BEGIN_NAMESPACE
class QObject;
diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp
index 279e09ec1..091b0c447 100644
--- a/sources/pyside2/libpyside/pysideproperty.cpp
+++ b/sources/pyside2/libpyside/pysideproperty.cpp
@@ -45,8 +45,6 @@
#include "pysidesignal_p.h"
#include <shiboken.h>
-#include <QDebug>
-
#define QPROPERTY_CLASS_NAME "Property"
@@ -173,7 +171,8 @@ int qpropertyTpInit(PyObject* self, PyObject* args, PyObject* kwds)
"designable", "scriptable", "stored", "user",
"constant", "final", 0};
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "O|OOOOsObbbbbb:QtCore.QProperty", (char**) kwlist,
+ "O|OOOOsObbbbbb:QtCore.QProperty",
+ const_cast<char**>(kwlist),
/*OO*/ &type, &(pData->fget),
/*OOO*/ &(pData->fset), &(pData->freset), &(pData->fdel),
/*s*/ &(pData->doc),
@@ -197,14 +196,13 @@ int qpropertyTpInit(PyObject* self, PyObject* args, PyObject* kwds)
Py_XINCREF(pData->fdel);
Py_XINCREF(pData->notify);
return 1;
- } else {
- pData->fget = 0;
- pData->fset = 0;
- pData->freset = 0;
- pData->fdel = 0;
- pData->notify = 0;
- return -1;
}
+ pData->fget = nullptr;
+ pData->fset = nullptr;
+ pData->freset = nullptr;
+ pData->fdel = nullptr;
+ pData->notify = nullptr;
+ return -1;
}
void qpropertyDeAlloc(PyObject* self)
@@ -225,10 +223,9 @@ PyObject *qPropertyCall(PyObject *self, PyObject *args, PyObject * /* kw */)
Py_INCREF(self);
return self;
- } else {
- PyErr_SetString(PyExc_TypeError, "Invalid property usage.");
- return 0;
}
+ PyErr_SetString(PyExc_TypeError, "Invalid property usage.");
+ return nullptr;
}
PyObject* qPropertySetter(PyObject* self, PyObject* callback)
@@ -242,10 +239,9 @@ PyObject* qPropertySetter(PyObject* self, PyObject* callback)
Py_INCREF(callback);
return callback;
- } else {
- PyErr_SetString(PyExc_TypeError, "Invalid property setter agument.");
- return 0;
}
+ PyErr_SetString(PyExc_TypeError, "Invalid property setter agument.");
+ return nullptr;
}
PyObject* qPropertyGetter(PyObject* self, PyObject* callback)
@@ -259,10 +255,9 @@ PyObject* qPropertyGetter(PyObject* self, PyObject* callback)
Py_INCREF(callback);
return callback;
- } else {
- PyErr_SetString(PyExc_TypeError, "Invalid property getter agument.");
- return 0;
}
+ PyErr_SetString(PyExc_TypeError, "Invalid property getter agument.");
+ return nullptr;
}
static int qpropertyTraverse(PyObject* self, visitproc visit, void* arg)
diff --git a/sources/pyside2/libpyside/pysideproperty.h b/sources/pyside2/libpyside/pysideproperty.h
index d77416abe..0ea5e84d6 100644
--- a/sources/pyside2/libpyside/pysideproperty.h
+++ b/sources/pyside2/libpyside/pysideproperty.h
@@ -41,8 +41,10 @@
#define PYSIDE_PROPERTY_H
#include <pysidemacros.h>
+
#include <sbkpython.h>
-#include <QObject>
+
+#include <QtCore/QMetaObject>
extern "C"
{
diff --git a/sources/pyside2/libpyside/pysideqflags.cpp b/sources/pyside2/libpyside/pysideqflags.cpp
index 684628e57..cb57031b0 100644
--- a/sources/pyside2/libpyside/pysideqflags.cpp
+++ b/sources/pyside2/libpyside/pysideqflags.cpp
@@ -38,8 +38,9 @@
****************************************************************************/
#include "pysideqflags.h"
-#include <sbkenum.h>
+
#include <autodecref.h>
+#include <sbkenum.h>
extern "C" {
struct SbkConverter;
@@ -174,13 +175,8 @@ namespace QFlags
newspec->itemsize = SbkNewQFlagsType_spec.itemsize;
newspec->flags = SbkNewQFlagsType_spec.flags;
int idx = -1;
-#ifdef IS_PY3K
-# define SLOT slot
-#else
-# define SLOT slot_
-#endif
- while (numberMethods[++idx].SLOT) {
- assert(SbkNewQFlagsType_slots[idx].SLOT == numberMethods[idx].SLOT);
+ while (numberMethods[++idx].slot) {
+ assert(SbkNewQFlagsType_slots[idx].slot == numberMethods[idx].slot);
SbkNewQFlagsType_slots[idx].pfunc = numberMethods[idx].pfunc;
}
newspec->slots = SbkNewQFlagsType_spec.slots;
diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp
index c3dc65968..e7fd389a8 100644
--- a/sources/pyside2/libpyside/pysidesignal.cpp
+++ b/sources/pyside2/libpyside/pysidesignal.cpp
@@ -43,7 +43,12 @@
#include "signalmanager.h"
#include <shiboken.h>
-#include <QDebug>
+
+#include <QtCore/QObject>
+#include <QtCore/QMetaMethod>
+#include <QtCore/QMetaObject>
+
+#include <utility>
#define SIGNAL_CLASS_NAME "Signal"
#define SIGNAL_INSTANCE_NAME "SignalInstance"
@@ -54,14 +59,15 @@ namespace Signal {
//aux
class SignalSignature {
public:
- SignalSignature() : m_attributes(QMetaMethod::Compatibility) {}
- SignalSignature(QByteArray parameterTypes) : m_parameterTypes(parameterTypes),
- m_attributes(QMetaMethod::Compatibility) {}
- SignalSignature(QByteArray parameterTypes, QMetaMethod::Attributes attributes) :
- m_parameterTypes(parameterTypes),
+ SignalSignature() = default;
+ explicit SignalSignature(QByteArray parameterTypes) :
+ m_parameterTypes(std::move(parameterTypes)) {}
+ explicit SignalSignature(QByteArray parameterTypes, QMetaMethod::Attributes attributes) :
+ m_parameterTypes(std::move(parameterTypes)),
m_attributes(attributes) {}
+
QByteArray m_parameterTypes;
- QMetaMethod::Attributes m_attributes;
+ QMetaMethod::Attributes m_attributes = QMetaMethod::Compatibility;
};
static char* buildSignature(const char*, const char*);
@@ -412,8 +418,7 @@ PyObject* signalInstanceConnect(PyObject* self, PyObject* args, PyObject* kwds)
PyObject* result = PyObject_CallObject(pyMethod, tupleArgs);
if (result == Py_True || result == Py_False)
return result;
- else
- Py_XDECREF(result);
+ Py_XDECREF(result);
}
if (!PyErr_Occurred()) // PYSIDE-79: inverse the logic. A Null return needs an error.
PyErr_Format(PyExc_RuntimeError, "Failed to connect signal %s.", source->d->signature);
@@ -661,9 +666,10 @@ char* getTypeName(PyObject* type)
typeName = strdup("PyObject");
}
return typeName;
- } else if (type == Py_None) { // Must be checked before as Shiboken::String::check accepts Py_None
+ }
+ if (type == Py_None) // Must be checked before as Shiboken::String::check accepts Py_None
return strdup("void");
- } else if (Shiboken::String::check(type)) {
+ if (Shiboken::String::check(type)) {
const char *result = Shiboken::String::toCString(type);
if (!strcmp(result, "qreal"))
result = sizeof(qreal) == sizeof(double) ? "double" : "float";
@@ -778,7 +784,7 @@ PySideSignalInstance* newObjectFromMethod(PyObject* source, const QList<QMetaMet
{
PySideSignalInstance* root = 0;
PySideSignalInstance* previous = 0;
- foreach (const QMetaMethod &m, methodList) {
+ for (const QMetaMethod &m : methodList) {
PySideSignalInstance* item = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF());
if (!root)
root = item;
@@ -835,7 +841,7 @@ template<typename T>
static typename T::value_type join(T t, const char* sep)
{
typename T::value_type res;
- if (!t.size())
+ if (t.isEmpty())
return res;
typename T::const_iterator it = t.begin();
@@ -894,7 +900,7 @@ void registerSignals(SbkObjectType* pyObj, const QMetaObject* metaObject)
self->signaturesSize = 0;
self->signatures = 0;
self->signatureAttributes = 0;
- self->initialized = 0;
+ self->initialized = false;
self->homonymousMethod = 0;
// Empty signatures comes first! So they will be the default signal signature
@@ -949,9 +955,9 @@ QStringList getArgsFromSignature(const char* signature, bool* isShortCircuit)
if (isShortCircuit)
*isShortCircuit = !qsignature.contains(QLatin1Char('('));
- if (qsignature.contains(QLatin1String("()")) || qsignature.contains(QLatin1String("(void)"))) {
+ if (qsignature.contains(QLatin1String("()")) || qsignature.contains(QLatin1String("(void)")))
return result;
- } else if (qsignature.contains(QLatin1Char('('))) {
+ if (qsignature.contains(QLatin1Char('('))) {
static QRegExp regex(QLatin1String(".+\\((.*)\\)"));
//get args types
QString types = qsignature;
@@ -1047,9 +1053,8 @@ QString codeCallbackName(PyObject* callback, const QString& funcName)
PyObject* self = PyMethod_GET_SELF(callback);
PyObject* func = PyMethod_GET_FUNCTION(callback);
return funcName + QString::number(quint64(self), 16) + QString::number(quint64(func), 16);
- } else {
- return funcName + QString::number(quint64(callback), 16);
}
+ return funcName + QString::number(quint64(callback), 16);
}
} //namespace Signal
diff --git a/sources/pyside2/libpyside/pysidesignal.h b/sources/pyside2/libpyside/pysidesignal.h
index abbefbb1a..a2d58a27c 100644
--- a/sources/pyside2/libpyside/pysidesignal.h
+++ b/sources/pyside2/libpyside/pysidesignal.h
@@ -40,14 +40,19 @@
#ifndef PYSIDE_SIGNAL_H
#define PYSIDE_SIGNAL_H
-#include <QObject>
-#include <QString>
-#include <QStringList>
-
#include <pysidemacros.h>
+
#include <sbkpython.h>
#include <basewrapper.h>
+#include <QtCore/QList>
+#include <QtCore/QMetaMethod>
+
+QT_BEGIN_NAMESPACE
+struct QMetaObject;
+class QObject;
+QT_END_NAMESPACE
+
extern "C"
{
extern PYSIDE_API PyTypeObject *PySideSignalTypeF(void);
diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp
index 6ae664c42..6f6658cf8 100644
--- a/sources/pyside2/libpyside/pysideslot.cpp
+++ b/sources/pyside2/libpyside/pysideslot.cpp
@@ -42,8 +42,9 @@
#include "pysideslot_p.h"
#include <shiboken.h>
-#include <QString>
-#include <QMetaObject>
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QString>
#define SLOT_DEC_NAME "Slot"
@@ -96,8 +97,10 @@ int slotTpInit(PyObject *self, PyObject *args, PyObject *kw)
if (emptyTuple == 0)
emptyTuple = PyTuple_New(0);
- if (!PyArg_ParseTupleAndKeywords(emptyTuple, kw, "|sO:QtCore." SLOT_DEC_NAME, (char**) kwlist, &argName, &argResult))
+ if (!PyArg_ParseTupleAndKeywords(emptyTuple, kw, "|sO:QtCore." SLOT_DEC_NAME,
+ const_cast<char**>(kwlist), &argName, &argResult)) {
return 0;
+ }
PySideSlot *data = reinterpret_cast<PySideSlot*>(self);
for(Py_ssize_t i = 0, i_max = PyTuple_Size(args); i < i_max; i++) {
diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp
index 6c38d39c4..6b5073db8 100644
--- a/sources/pyside2/libpyside/pysideweakref.cpp
+++ b/sources/pyside2/libpyside/pysideweakref.cpp
@@ -65,7 +65,7 @@ static PyType_Spec PySideCallableObjectType_spec = {
};
-static PyTypeObject *PySideCallableObjectTypeF(void)
+static PyTypeObject *PySideCallableObjectTypeF()
{
static PyTypeObject *type =
(PyTypeObject *)PyType_FromSpec(&PySideCallableObjectType_spec);
diff --git a/sources/pyside2/libpyside/signalmanager.cpp.in b/sources/pyside2/libpyside/signalmanager.cpp
index c67bc6369..8925ffd35 100644
--- a/sources/pyside2/libpyside/signalmanager.cpp.in
+++ b/sources/pyside2/libpyside/signalmanager.cpp
@@ -43,25 +43,25 @@
#include "pysideproperty.h"
#include "pysideproperty_p.h"
#include "pyside.h"
+#include "pyside_p.h"
#include "dynamicqmetaobject.h"
#include "pysidemetafunction_p.h"
-#include <QtCore>
-#include <QHash>
-#include <QStringList>
-#include <QMetaMethod>
#include <autodecref.h>
-#include <gilstate.h>
-#include <QDebug>
-#include <limits>
-#include <algorithm>
#include <basewrapper.h>
#include <bindingmanager.h>
+#include <gilstate.h>
#include <sbkconverter.h>
#include <sbkstring.h>
+#include <QtCore/QDebug>
+#include <QtCore/QHash>
+
+#include <algorithm>
+#include <limits>
+
// These private headers are needed to throw JavaScript exceptions
-#if @QML_PRIVATE_API_SUPPORT@
+#if PYSIDE_QML_PRIVATE_API_SUPPORT
#include <private/qv4engine_p.h>
#include <private/qv4context_p.h>
#include <private/qqmldata_p.h>
@@ -76,7 +76,6 @@
#define PYSIDE_SLOT '1'
#define PYSIDE_SIGNAL '2'
#include "globalreceiverv2.h"
-#include "globalreceiver.h"
#define PYTHON_TYPE "PyObject"
@@ -91,7 +90,7 @@ namespace {
static void destroyMetaObject(PyObject* obj)
{
void* ptr = PyCapsule_GetPointer(obj, 0);
- PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(ptr);
+ auto meta = reinterpret_cast<PySide::MetaObjectBuilder*>(ptr);
SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta);
if (wrapper)
Shiboken::BindingManager::instance().releaseWrapper(wrapper);
@@ -101,7 +100,7 @@ namespace {
#else
static void destroyMetaObject(void* obj)
{
- PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(obj);
+ auto meta = reinterpret_cast<PySide::MetaObjectBuilder*>(obj);
SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta);
if (wrapper)
Shiboken::BindingManager::instance().releaseWrapper(wrapper);
@@ -142,11 +141,16 @@ PyObjectWrapper::~PyObjectWrapper()
Py_XDECREF(m_me);
}
-PyObjectWrapper& PyObjectWrapper::operator=(const PySide::PyObjectWrapper& other)
+void PyObjectWrapper::reset(PyObject *o)
{
- Py_XINCREF(other.m_me);
+ Py_XINCREF(o);
Py_XDECREF(m_me);
- m_me = other.m_me;
+ m_me = o;
+}
+
+PyObjectWrapper& PyObjectWrapper::operator=(const PySide::PyObjectWrapper& other)
+{
+ reset(other.m_me);
return *this;
}
@@ -205,10 +209,9 @@ QDataStream &operator>>(QDataStream& in, PyObjectWrapper& myObj)
in >> repr;
Shiboken::AutoDecRef pyCode(PyBytes_FromStringAndSize(repr.data(), repr.size()));
Shiboken::AutoDecRef value(PyObject_CallFunctionObjArgs(eval_func, pyCode.object(), 0));
- if (!value.object()) {
- value = Py_None;
- }
- myObj = PyObjectWrapper(value);
+ if (!value.object())
+ value.reset(Py_None);
+ myObj.reset(value);
return in;
}
@@ -220,9 +223,6 @@ struct SignalManager::SignalManagerPrivate
{
SharedMap m_globalReceivers;
- //Deprecated
- GlobalReceiver m_globalReceiver;
-
SignalManagerPrivate()
{
m_globalReceivers = SharedMap( new QMap<QByteArray, GlobalReceiverV2*>() );
@@ -304,44 +304,21 @@ SignalManager& SignalManager::instance()
return me;
}
-QObject* SignalManager::globalReceiver()
-{
- return &m_d->m_globalReceiver;
-}
-
-void SignalManager::globalReceiverConnectNotify(QObject* source, int slotIndex)
-{
- m_d->m_globalReceiver.connectNotify(source, slotIndex);
-}
-
-void SignalManager::globalReceiverDisconnectNotify(QObject* source, int slotIndex)
-{
- m_d->m_globalReceiver.disconnectNotify(source, slotIndex);
-}
-
-void SignalManager::addGlobalSlot(const char* slot, PyObject* callback)
-{
- addGlobalSlotGetIndex(slot, callback);
-}
-
-int SignalManager::addGlobalSlotGetIndex(const char* slot, PyObject* callback)
-{
- return m_d->m_globalReceiver.addSlot(slot, callback);
-}
-
QObject* SignalManager::globalReceiver(QObject *sender, PyObject *callback)
{
SharedMap globalReceivers = m_d->m_globalReceivers;
QByteArray hash = GlobalReceiverV2::hash(callback);
GlobalReceiverV2* gr = 0;
- if (!globalReceivers->contains(hash)) {
- gr = (*globalReceivers)[hash] = new GlobalReceiverV2(callback, globalReceivers);
+ auto it = globalReceivers->find(hash);
+ if (it == globalReceivers->end()) {
+ gr = new GlobalReceiverV2(callback, globalReceivers);
+ globalReceivers->insert(hash, gr);
if (sender) {
gr->incRef(sender); // create a link reference
gr->decRef(); // remove extra reference
}
} else {
- gr = (*globalReceivers)[hash];
+ gr = it.value();
if (sender)
gr->incRef(sender);
}
@@ -465,7 +442,7 @@ int SignalManager::qt_metacall(QObject* object, QMetaObject::Call call, int id,
if (PyErr_Occurred()) {
-#if @QML_PRIVATE_API_SUPPORT@
+#if PYSIDE_QML_PRIVATE_API_SUPPORT
// This JS engine grabber based off of Qt 5.5's `qjsEngine` function
QQmlData *data = QQmlData::get(object, false);
@@ -572,9 +549,26 @@ bool SignalManager::registerMetaMethod(QObject* source, const char* signature, Q
return (ret != -1);
}
+static MetaObjectBuilder *metaBuilderFromDict(PyObject* dict)
+{
+ if (!dict || !PyDict_Contains(dict, metaObjectAttr))
+ return nullptr;
+
+ PyObject *pyBuilder = PyDict_GetItem(dict, metaObjectAttr);
+#ifdef IS_PY3K
+ return reinterpret_cast<MetaObjectBuilder *>(PyCapsule_GetPointer(pyBuilder, nullptr));
+#else
+ return reinterpret_cast<MetaObjectBuilder *>(PyCObject_AsVoidPtr(pyBuilder));
+#endif
+}
+
int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signature, QMetaMethod::MethodType type)
{
- Q_ASSERT(source);
+ if (!source) {
+ qWarning("SignalManager::registerMetaMethodGetIndex(\"%s\") called with source=nullptr.",
+ signature);
+ return -1;
+ }
const QMetaObject* metaObject = source->metaObject();
int methodIndex = metaObject->indexOfMethod(signature);
// Create the dynamic signal is needed
@@ -584,13 +578,13 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa
qWarning() << "Invalid Signal signature:" << signature;
return -1;
} else {
- DynamicQMetaObject *dmo = 0;
PyObject *pySelf = reinterpret_cast<PyObject*>(self);
PyObject* dict = self->ob_dict;
+ MetaObjectBuilder *dmo = metaBuilderFromDict(dict);
// Create a instance meta object
- if (!dict || !PyDict_Contains(dict, metaObjectAttr)) {
- dmo = new DynamicQMetaObject(Py_TYPE(pySelf), metaObject);
+ if (!dmo) {
+ dmo = new MetaObjectBuilder(Py_TYPE(pySelf), metaObject);
#ifdef IS_PY3K
PyObject* pyDmo = PyCapsule_New(dmo, 0, destroyMetaObject);
#else
@@ -599,8 +593,6 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa
PyObject_SetAttr(pySelf, metaObjectAttr, pyDmo);
Py_DECREF(pyDmo);
- } else {
- dmo = reinterpret_cast<DynamicQMetaObject*>(const_cast<QMetaObject*>(metaObject));
}
if (type == QMetaMethod::Signal)
@@ -612,32 +604,16 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa
return methodIndex;
}
-bool SignalManager::hasConnectionWith(const QObject *object)
-{
- return m_d->m_globalReceiver.hasConnectionWith(object);
-}
-
-const QMetaObject* SignalManager::retriveMetaObject(PyObject *self)
+const QMetaObject* SignalManager::retrieveMetaObject(PyObject *self)
{
Shiboken::GilState gil;
- DynamicQMetaObject *mo = 0;
Q_ASSERT(self);
- PyObject* dict = reinterpret_cast<SbkObject*>(self)->ob_dict;
- if (dict && PyDict_Contains(dict, metaObjectAttr)) {
- PyObject *pyMo = PyDict_GetItem(dict, metaObjectAttr);
-
-#ifdef IS_PY3K
- mo = reinterpret_cast<DynamicQMetaObject*>(PyCapsule_GetPointer(pyMo, 0));
-#else
- mo = reinterpret_cast<DynamicQMetaObject*>(PyCObject_AsVoidPtr(pyMo));
-#endif
- } else {
- mo = reinterpret_cast<DynamicQMetaObject*>(Shiboken::Object::getTypeUserData(reinterpret_cast<SbkObject*>(self)));
- }
+ MetaObjectBuilder *builder = metaBuilderFromDict(reinterpret_cast<SbkObject*>(self)->ob_dict);
+ if (!builder)
+ builder = &(retrieveTypeUserData(self)->mo);
- mo->update();
- return mo;
+ return builder->update();
}
namespace {
diff --git a/sources/pyside2/libpyside/signalmanager.h b/sources/pyside2/libpyside/signalmanager.h
index 5948a7df1..229ddb91d 100644
--- a/sources/pyside2/libpyside/signalmanager.h
+++ b/sources/pyside2/libpyside/signalmanager.h
@@ -41,10 +41,12 @@
#define SIGNALMANAGER_H
#include "pysidemacros.h"
+
#include <sbkpython.h>
-#include <Qt>
-#include <QStringList>
-#include <QMetaMethod>
+
+#include <QtCore/QMetaMethod>
+
+QT_FORWARD_DECLARE_CLASS(QDataStream)
namespace PySide
{
@@ -53,12 +55,19 @@ namespace PySide
class PYSIDE_API PyObjectWrapper
{
public:
+ PyObjectWrapper(PyObjectWrapper&&) = delete;
+ PyObjectWrapper& operator=(PyObjectWrapper &&) = delete;
+
PyObjectWrapper();
- PyObjectWrapper(PyObject* me);
+ explicit PyObjectWrapper(PyObject* me);
PyObjectWrapper(const PyObjectWrapper &other);
+ PyObjectWrapper& operator=(const PyObjectWrapper &other);
+
+ void reset(PyObject *o);
+
~PyObjectWrapper();
operator PyObject*() const;
- PyObjectWrapper& operator=(const PyObjectWrapper &other);
+
private:
PyObject* m_me;
};
@@ -68,6 +77,7 @@ PYSIDE_API QDataStream &operator>>(QDataStream& in, PyObjectWrapper& myObj);
class PYSIDE_API SignalManager
{
+ Q_DISABLE_COPY(SignalManager)
public:
static SignalManager& instance();
@@ -84,7 +94,7 @@ public:
static int registerMetaMethodGetIndex(QObject* source, const char* signature, QMetaMethod::MethodType type);
// used to discovery metaobject
- static const QMetaObject* retriveMetaObject(PyObject* self);
+ static const QMetaObject* retrieveMetaObject(PyObject* self);
// Used to discovery if SignalManager was connected with object "destroyed()" signal.
int countConnectionsWith(const QObject *object);
@@ -95,24 +105,12 @@ public:
// Utility function to call a python method usign args received in qt_metacall
static int callPythonMetaMethod(const QMetaMethod& method, void** args, PyObject* obj, bool isShortCuit);
- PYSIDE_DEPRECATED(QObject* globalReceiver());
- PYSIDE_DEPRECATED(void addGlobalSlot(const char* slot, PyObject* callback));
- PYSIDE_DEPRECATED(int addGlobalSlotGetIndex(const char* slot, PyObject* callback));
-
- PYSIDE_DEPRECATED(void globalReceiverConnectNotify(QObject *sender, int slotIndex));
- PYSIDE_DEPRECATED(void globalReceiverDisconnectNotify(QObject *sender, int slotIndex));
- PYSIDE_DEPRECATED(bool hasConnectionWith(const QObject *object));
-
private:
struct SignalManagerPrivate;
SignalManagerPrivate* m_d;
SignalManager();
~SignalManager();
-
- // disable copy
- SignalManager(const SignalManager&);
- SignalManager operator=(const SignalManager&);
};
}
diff --git a/sources/pyside2/pyside_version.py b/sources/pyside2/pyside_version.py
index 789812464..a883bab96 100644
--- a/sources/pyside2/pyside_version.py
+++ b/sources/pyside2/pyside_version.py
@@ -38,16 +38,10 @@
#############################################################################
major_version = "5"
-minor_version = "11"
-patch_version = "1"
-
-# For example: "a", "b", "rc"
-# (which means "alpha", "beta", "release candidate").
-# An empty string means the generated package will be an official release.
-pre_release_version_type = "a"
-
-# For example: "1", "2" (which means "beta1", "beta2", if type is "b").
-pre_release_version = "1"
+minor_version = "12"
+patch_version = "0"
+pre_release_version_type = "a" # e.g. "a", "b", "rc".
+pre_release_version = "1" # e.g "1", "2", (which means "beta1", "beta2", if type is "b")
if __name__ == '__main__':
# Used by CMake.
diff --git a/sources/pyside2/tests/CMakeLists.txt b/sources/pyside2/tests/CMakeLists.txt
index 2386950e9..bed2d7cc1 100644
--- a/sources/pyside2/tests/CMakeLists.txt
+++ b/sources/pyside2/tests/CMakeLists.txt
@@ -46,7 +46,7 @@ else()
set_tests_properties(${TEST_NAME} PROPERTIES
TIMEOUT ${CTEST_TESTING_TIMEOUT}
WILL_FAIL ${EXPECT_TO_FAIL}
- ENVIRONMENT "PYTHONPATH=${TEST_PYTHONPATH};${LIBRARY_PATH_VAR}=${TEST_LIBRARY_PATH};PYSIDE_DISABLE_INTERNAL_QT_CONF=1;QT_NO_GLIB=1")
+ ENVIRONMENT "PYTHONPATH=${TEST_PYTHONPATH};${LIBRARY_PATH_VAR}=${TEST_LIBRARY_PATH};PYSIDE_DISABLE_INTERNAL_QT_CONF=1;QT_NO_GLIB=1;QT_MAC_WANTS_LAYER=0")
endmacro()
if (NOT DISABLE_QtCore AND NOT DISABLE_QtGui AND NOT DISABLE_QtWidgets)
diff --git a/sources/pyside2/tests/QtCore/CMakeLists.txt b/sources/pyside2/tests/QtCore/CMakeLists.txt
index 649e796cc..d6d12f651 100644
--- a/sources/pyside2/tests/QtCore/CMakeLists.txt
+++ b/sources/pyside2/tests/QtCore/CMakeLists.txt
@@ -52,6 +52,7 @@ PYSIDE_TEST(qbytearray_concatenation_operator_test.py)
PYSIDE_TEST(qbytearray_operator_iadd_test.py)
PYSIDE_TEST(qbytearray_operator_test.py)
PYSIDE_TEST(qbytearray_test.py)
+PYSIDE_TEST(qcbor_test.py)
PYSIDE_TEST(qcollator_test.py)
PYSIDE_TEST(qcommandlineparser_test.py)
PYSIDE_TEST(qcoreapplication_instance_test.py)
diff --git a/sources/pyside2/tests/QtCore/qcbor_test.py b/sources/pyside2/tests/QtCore/qcbor_test.py
new file mode 100644
index 000000000..2ac46673a
--- /dev/null
+++ b/sources/pyside2/tests/QtCore/qcbor_test.py
@@ -0,0 +1,74 @@
+#!/usr/bin/python
+
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+'''Test cases for QCbor'''
+
+import unittest
+
+from PySide2.QtCore import (QByteArray, QCborStreamReader, QCborStreamWriter,
+ QCborValue)
+
+class TestCbor(unittest.TestCase):
+ def testReader(self):
+ ba = QByteArray()
+ writer = QCborStreamWriter(ba)
+ writer.append(42)
+ del writer
+ self.assertTrue(not ba.isEmpty())
+ reader = QCborStreamReader(ba)
+ self.assertTrue(reader.hasNext())
+ value = reader.toInteger()
+ self.assertEqual(value, 42)
+
+ def testReader(self):
+ ba = QByteArray()
+ writer = QCborStreamWriter(ba)
+ writer.append("hello")
+ del writer
+ self.assertTrue(not ba.isEmpty())
+ reader = QCborStreamReader(ba)
+ self.assertTrue(reader.hasNext())
+ if (reader.isByteArray()): # Python 2
+ value = reader.readByteArray()
+ self.assertTrue(value)
+ self.assertEqual(value.data, "hello")
+ else:
+ self.assertTrue(reader.isString())
+ value = reader.readString()
+ self.assertTrue(value)
+ self.assertEqual(value.data, "hello")
+
+ def testValue(self):
+ value = QCborValue('hello')
+ self.assertTrue(value.isString())
+ self.assertEqual(value.toString(), 'hello')
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside2/tests/QtCore/qmetaobject_test.py b/sources/pyside2/tests/QtCore/qmetaobject_test.py
index 12b5312a6..73ab81c7c 100644
--- a/sources/pyside2/tests/QtCore/qmetaobject_test.py
+++ b/sources/pyside2/tests/QtCore/qmetaobject_test.py
@@ -78,6 +78,12 @@ class qmetaobject_test(unittest.TestCase):
#self.assertTrue(slot_index != signal_index)
+ # PYSIDE-784, plain Qt objects should not have intermediary
+ # metaObjects.
+ def test_PlainQObject(self):
+ timer = QTimer()
+ self.assertEqual(timer.metaObject().superClass().className(),
+ "QObject")
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/QtGui/qmatrix_test.py b/sources/pyside2/tests/QtGui/qmatrix_test.py
index cac8a7ab7..a917199c1 100644
--- a/sources/pyside2/tests/QtGui/qmatrix_test.py
+++ b/sources/pyside2/tests/QtGui/qmatrix_test.py
@@ -29,7 +29,7 @@
import unittest
from PySide2.QtCore import QPoint
-from PySide2.QtGui import QMatrix, QMatrix4x4
+from PySide2.QtGui import QMatrix, QMatrix2x2, QMatrix4x4
def qpointTimesQMatrix(point, matrix):
@@ -49,6 +49,19 @@ class QMatrixTest(unittest.TestCase):
point = QPoint(3, 3)
self.assertRaises(TypeError, matrix.__mul__, point)
+ def testMatrix2x2(self):
+ matrix = QMatrix2x2([1.0, 2.0, 3.0, 4.0])
+
+ expectedTransposed = QMatrix2x2([1.0, 3.0, 2.0, 4.0])
+ self.assertEqual(matrix.transposed(), expectedTransposed)
+
+ expectedMultiplied = QMatrix2x2([2.0, 4.0, 6.0, 8.0])
+ matrix *= 2.0
+ self.assertEqual(matrix, expectedMultiplied)
+
+ matrix.setToIdentity()
+ self.assertTrue(matrix.isIdentity())
+
def testMatrix4x4(self):
self.assertRaises(TypeError, QMatrix4x4, [0.0, 1.0, 2.0, 3.0])
self.assertRaises(TypeError, QMatrix4x4, [0.0, 1.0, 2.0, 'I',
diff --git a/sources/pyside2/tests/QtNetwork/CMakeLists.txt b/sources/pyside2/tests/QtNetwork/CMakeLists.txt
index c14c19fa9..57c5266c8 100644
--- a/sources/pyside2/tests/QtNetwork/CMakeLists.txt
+++ b/sources/pyside2/tests/QtNetwork/CMakeLists.txt
@@ -3,6 +3,7 @@ PYSIDE_TEST(bug_1084.py)
PYSIDE_TEST(accessManager_test.py)
PYSIDE_TEST(dnslookup_test.py)
# Qt5: QHttp is gone PYSIDE_TEST(http_test.py)
+PYSIDE_TEST(qpassworddigestor_test.py)
PYSIDE_TEST(tcpserver_test.py)
PYSIDE_TEST(udpsocket_test.py)
PYSIDE_TEST(qipv6address_test.py)
diff --git a/sources/pyside2/tests/QtNetwork/qpassworddigestor_test.py b/sources/pyside2/tests/QtNetwork/qpassworddigestor_test.py
new file mode 100644
index 000000000..503ffecdc
--- /dev/null
+++ b/sources/pyside2/tests/QtNetwork/qpassworddigestor_test.py
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+'''Test cases for QPasswordDigestor'''
+
+import unittest
+
+from PySide2.QtCore import QByteArray, QCryptographicHash
+from PySide2.QtNetwork import QPasswordDigestor
+
+class TestPasswordDigestor(unittest.TestCase):
+ def test(self):
+ b = QPasswordDigestor.deriveKeyPbkdf1(QCryptographicHash.Sha1,
+ b'test', b'saltnpep', 10, 20)
+ self.assertEqual(b.size(), 20)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside2/tests/QtWidgets/python_properties_test.py b/sources/pyside2/tests/QtWidgets/python_properties_test.py
index f5bcf5eb8..f4e46f2bd 100644
--- a/sources/pyside2/tests/QtWidgets/python_properties_test.py
+++ b/sources/pyside2/tests/QtWidgets/python_properties_test.py
@@ -39,6 +39,8 @@ class Properties(unittest.TestCase):
p = QtWidgets.QStyleOptionViewItem()
self.assertTrue(isinstance(p.locale, QtCore.QLocale))
+ # PSYIDE-304, can assign to a "const QWidget *" field
+ p.widget = None
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/QtWidgets/qwidget_test.py b/sources/pyside2/tests/QtWidgets/qwidget_test.py
index 1e8387d11..028751ba7 100644
--- a/sources/pyside2/tests/QtWidgets/qwidget_test.py
+++ b/sources/pyside2/tests/QtWidgets/qwidget_test.py
@@ -26,6 +26,7 @@
##
#############################################################################
+import sys
import unittest
from PySide2.QtWidgets import QWidget, QMainWindow
@@ -35,6 +36,17 @@ class QWidgetInherit(QMainWindow):
def __init__(self):
QWidget.__init__(self)
+class NativeEventTestWidget(QWidget):
+
+ nativeEventCount = 0
+
+ def __init__(self):
+ QWidget.__init__(self)
+
+ def nativeEvent(self, eventType, message):
+ self.nativeEventCount = self.nativeEventCount + 1
+ return [False, 0]
+
class QWidgetTest(UsesQApplication):
def testInheritance(self):
@@ -44,12 +56,19 @@ class QWidgetVisible(UsesQApplication):
def testBasic(self):
# Also related to bug #244, on existence of setVisible'''
- widget = QWidget()
+ widget = NativeEventTestWidget()
self.assertTrue(not widget.isVisible())
widget.setVisible(True)
self.assertTrue(widget.isVisible())
self.assertTrue(widget.winId() is not 0)
-
+ # skip this test on macOS since no native events are received
+ if sys.platform == 'darwin':
+ return
+ for i in range(10):
+ if widget.nativeEventCount > 0:
+ break
+ self.app.processEvents()
+ self.assertTrue(widget.nativeEventCount > 0)
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/pysidetest/CMakeLists.txt b/sources/pyside2/tests/pysidetest/CMakeLists.txt
index c6d3bb13b..119553fad 100644
--- a/sources/pyside2/tests/pysidetest/CMakeLists.txt
+++ b/sources/pyside2/tests/pysidetest/CMakeLists.txt
@@ -3,9 +3,6 @@ project(testbinding)
cmake_minimum_required(VERSION 3.1)
-# On Windows, don't link to qtmain.lib for executables automatically.
-cmake_policy(SET CMP0020 OLD)
-
set(QT_USE_QTCORE 1)
# no more supported: include(${QT_USE_FILE})
add_definitions(${Qt5Core_DEFINITIONS})
@@ -69,7 +66,9 @@ make_path(testbinding_include_dirs ${pyside2_BINARY_DIR}
make_path(testbinding_typesystem_path ${pyside2_SOURCE_DIR}
${pyside2_BINARY_DIR})
-add_custom_command(OUTPUT ${testbinding_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${testbinding_SRC}
COMMAND ${SHIBOKEN_BINARY} ${GENERATOR_EXTRA_FLAGS}
${CMAKE_CURRENT_SOURCE_DIR}/pysidetest_global.h
--include-paths=${testbinding_include_dirs}
@@ -119,6 +118,7 @@ target_link_libraries(testbinding
${SBK_PYTHON_LIBRARIES})
add_dependencies(testbinding pyside2 QtCore QtGui QtWidgets pysidetest)
+create_generator_target(testbinding)
PYSIDE_TEST(decoratedslot_test.py)
# Will always crash when built against Qt 5.6, no point in running it.
diff --git a/sources/pyside2/tests/pysidetest/new_inherited_functions_test.py b/sources/pyside2/tests/pysidetest/new_inherited_functions_test.py
index 960f675ea..54b81acae 100644
--- a/sources/pyside2/tests/pysidetest/new_inherited_functions_test.py
+++ b/sources/pyside2/tests/pysidetest/new_inherited_functions_test.py
@@ -32,17 +32,16 @@ import sys
import os
import unittest
-import PySide2.QtCore
+from PySide2 import *
+for modname, mod in sys.modules.items():
+ # Python 2 leaves "None" in the dict.
+ if modname.startswith("PySide2.") and mod is not None:
+ print("importing", modname)
+ exec("import " + modname)
# This test tests the existence and callability of the newly existing functions,
# after the inheritance was made complete in the course of PYSIDE-331.
-def warn_essential(modname):
- print(80 * "*")
- print("*** Warning: '{}' is an essential module! Are you sure to skip it?"
- .format(modname))
- print(80 * "*")
-
new_functions = """
PySide2.QtCore.QAbstractItemModel().parent()
PySide2.QtCore.QAbstractListModel().parent()
@@ -52,85 +51,67 @@ new_functions = """
PySide2.QtCore.QSortFilterProxyModel().parent()
PySide2.QtCore.QTemporaryFile(tfarg).open(openMode)
"""
-try:
- modname = "PySide2.QtGui"
- exec("import " + modname)
- new_functions += """
- PySide2.QtGui.QBitmap().transformed(qMatrix,transformationMode)
- PySide2.QtGui.QStandardItemModel().insertColumn(int,qModelIndex)
- PySide2.QtGui.QStandardItemModel().parent()
- # PySide2.QtGui.QTextList(qTextDocument).setFormat(qTextFormat) # Segmentation fault: 11
- # PySide2.QtGui.QTextTable(qTextDocument).setFormat(qTextFormat) # Segmentation fault: 11
- """
-except ImportError:
- warn_essential(modname)
-try:
- modname = "PySide2.QtWidgets"
- exec("import " + modname)
- new_functions += """
- PySide2.QtWidgets.QAbstractItemView().update()
- PySide2.QtWidgets.QApplication.palette()
- PySide2.QtWidgets.QApplication.setFont(qFont)
- PySide2.QtWidgets.QApplication.setPalette(qPalette)
- PySide2.QtWidgets.QBoxLayout(direction).addWidget(qWidget)
- PySide2.QtWidgets.QColorDialog().open()
- PySide2.QtWidgets.QDirModel().index(int,int,qModelIndex)
- PySide2.QtWidgets.QDirModel().parent()
- PySide2.QtWidgets.QFileDialog().open()
- PySide2.QtWidgets.QFileSystemModel().index(int,int,qModelIndex)
- PySide2.QtWidgets.QFileSystemModel().parent()
- PySide2.QtWidgets.QFontDialog().open()
- PySide2.QtWidgets.QGestureEvent([]).accept()
- PySide2.QtWidgets.QGestureEvent([]).ignore()
- PySide2.QtWidgets.QGestureEvent([]).isAccepted()
- PySide2.QtWidgets.QGestureEvent([]).setAccepted(bool)
- # PySide2.QtWidgets.QGraphicsView().render(qPaintDevice,qPoint,qRegion,renderFlags) # QPaintDevice: NotImplementedError
- PySide2.QtWidgets.QGridLayout().addWidget(qWidget)
- PySide2.QtWidgets.QHeaderView(orientation).initStyleOption(qStyleOptionFrame)
- PySide2.QtWidgets.QInputDialog().open()
- PySide2.QtWidgets.QLineEdit().addAction(qAction)
- PySide2.QtWidgets.QListWidget().closePersistentEditor(qModelIndex)
- PySide2.QtWidgets.QListWidget().openPersistentEditor(qModelIndex)
- PySide2.QtWidgets.QMessageBox().open()
- PySide2.QtWidgets.QPlainTextEdit.find(quintptr)
- PySide2.QtWidgets.QProgressDialog().open()
- PySide2.QtWidgets.QStackedLayout().widget()
- # PySide2.QtWidgets.QStylePainter().begin(qPaintDevice) # QPaintDevice: NotImplementedError
- PySide2.QtWidgets.QTableWidget().closePersistentEditor(qModelIndex)
- PySide2.QtWidgets.QTableWidget().openPersistentEditor(qModelIndex)
- PySide2.QtWidgets.QTextEdit.find(quintptr)
- PySide2.QtWidgets.QTreeWidget().closePersistentEditor(qModelIndex)
- PySide2.QtWidgets.QTreeWidget().openPersistentEditor(qModelIndex)
- """
-except ImportError:
- warn_essential(modname)
-try:
- modname = "PySide2.QtPrintSupport"
- exec("import " + modname)
- new_functions += """
- # PySide2.QtPrintSupport.QPageSetupDialog().open() # Segmentation fault: 11
- # PySide2.QtPrintSupport.QPrintDialog().open() # opens the dialog, but works
- PySide2.QtPrintSupport.QPrintDialog().printer()
- PySide2.QtPrintSupport.QPrintPreviewDialog().open() # note: this prints something, but really shouldn't ;-)
- """
-except ImportError:
- warn_essential(modname)
-try:
- import PySide2.QtHelp
- new_functions += """
- PySide2.QtHelp.QHelpContentModel().parent()
- # PySide2.QtHelp.QHelpIndexModel().createIndex(int,int,quintptr) # returned NULL without setting an error
- # PySide2.QtHelp.QHelpIndexModel().createIndex(int,int,object()) # returned NULL without setting an error
- """
-except ImportError:
- pass
-try:
- import PySide2.QtQuick
- new_functions += """
- PySide2.QtQuick.QQuickPaintedItem().update()
- """
-except ImportError:
- pass
+
+new_functions += """
+ PySide2.QtGui.QBitmap().transformed(qMatrix,transformationMode)
+ PySide2.QtGui.QStandardItemModel().insertColumn(int,qModelIndex)
+ PySide2.QtGui.QStandardItemModel().parent()
+ # PySide2.QtGui.QTextList(qTextDocument).setFormat(qTextFormat) # Segmentation fault: 11
+ # PySide2.QtGui.QTextTable(qTextDocument).setFormat(qTextFormat) # Segmentation fault: 11
+""" if "PySide2.QtGui" in sys.modules else ""
+
+new_functions += """
+ PySide2.QtWidgets.QAbstractItemView().update()
+ PySide2.QtWidgets.QApplication.palette()
+ PySide2.QtWidgets.QApplication.setFont(qFont)
+ PySide2.QtWidgets.QApplication.setPalette(qPalette)
+ PySide2.QtWidgets.QBoxLayout(direction).addWidget(qWidget)
+ PySide2.QtWidgets.QColorDialog().open()
+ PySide2.QtWidgets.QDirModel().index(int,int,qModelIndex)
+ PySide2.QtWidgets.QDirModel().parent()
+ PySide2.QtWidgets.QFileDialog().open()
+ PySide2.QtWidgets.QFileSystemModel().index(int,int,qModelIndex)
+ PySide2.QtWidgets.QFileSystemModel().parent()
+ PySide2.QtWidgets.QFontDialog().open()
+ PySide2.QtWidgets.QGestureEvent([]).accept()
+ PySide2.QtWidgets.QGestureEvent([]).ignore()
+ PySide2.QtWidgets.QGestureEvent([]).isAccepted()
+ PySide2.QtWidgets.QGestureEvent([]).setAccepted(bool)
+ # PySide2.QtWidgets.QGraphicsView().render(qPaintDevice,qPoint,qRegion,renderFlags) # QPaintDevice: NotImplementedError
+ PySide2.QtWidgets.QGridLayout().addWidget(qWidget)
+ PySide2.QtWidgets.QHeaderView(orientation).initStyleOption(qStyleOptionFrame)
+ PySide2.QtWidgets.QInputDialog().open()
+ PySide2.QtWidgets.QLineEdit().addAction(qAction)
+ PySide2.QtWidgets.QListWidget().closePersistentEditor(qModelIndex)
+ PySide2.QtWidgets.QListWidget().openPersistentEditor(qModelIndex)
+ PySide2.QtWidgets.QMessageBox().open()
+ PySide2.QtWidgets.QPlainTextEdit.find(quintptr)
+ PySide2.QtWidgets.QProgressDialog().open()
+ PySide2.QtWidgets.QStackedLayout().widget()
+ # PySide2.QtWidgets.QStylePainter().begin(qPaintDevice) # QPaintDevice: NotImplementedError
+ PySide2.QtWidgets.QTableWidget().closePersistentEditor(qModelIndex)
+ PySide2.QtWidgets.QTableWidget().openPersistentEditor(qModelIndex)
+ PySide2.QtWidgets.QTextEdit.find(quintptr)
+ PySide2.QtWidgets.QTreeWidget().closePersistentEditor(qModelIndex)
+ PySide2.QtWidgets.QTreeWidget().openPersistentEditor(qModelIndex)
+""" if "PySide2.QtWidgets" in sys.modules else ""
+
+new_functions += """
+ # PySide2.QtPrintSupport.QPageSetupDialog().open() # Segmentation fault: 11
+ # PySide2.QtPrintSupport.QPrintDialog().open() # opens the dialog, but works
+ PySide2.QtPrintSupport.QPrintDialog().printer()
+ PySide2.QtPrintSupport.QPrintPreviewDialog().open() # note: this prints something, but really shouldn't ;-)
+""" if "PySide2.QtPrintSupport" in sys.modules else ""
+
+new_functions += """
+ PySide2.QtHelp.QHelpContentModel().parent()
+ # PySide2.QtHelp.QHelpIndexModel().createIndex(int,int,quintptr) # returned NULL without setting an error
+ # PySide2.QtHelp.QHelpIndexModel().createIndex(int,int,object()) # returned NULL without setting an error
+""" if "PySide2.QtHelp" in sys.modules else ""
+
+new_functions += """
+ PySide2.QtQuick.QQuickPaintedItem().update()
+""" if "PySide2.QtQuick" in sys.modules else ""
class MainTest(unittest.TestCase):
diff --git a/sources/pyside2/tests/registry/init_platform.py b/sources/pyside2/tests/registry/init_platform.py
index 03d0ed133..22875a63e 100644
--- a/sources/pyside2/tests/registry/init_platform.py
+++ b/sources/pyside2/tests/registry/init_platform.py
@@ -55,9 +55,10 @@ from textwrap import dedent
all_modules = list("PySide2." + x for x in PySide2.__all__)
-from PySide2.support.signature import inspect
from PySide2.QtCore import __version__
+from PySide2.support.signature.lib.enum_sig import SimplifyingEnumerator
+
is_py3 = sys.version_info[0] == 3
is_ci = os.environ.get("QTEST_ENVIRONMENT", "") == "ci"
# Python2 legacy: Correct 'linux2' to 'linux', recommended way.
@@ -114,7 +115,7 @@ class Formatter(object):
Formatter is formatting the signature listing of an enumerator.
It is written as context managers in order to avoid many callbacks.
- The division in formatter and enumerator is done to keep the
+ The separation in formatter and enumerator is done to keep the
unrelated tasks of enumeration and formatting apart.
"""
def __init__(self, outfile):
@@ -134,7 +135,7 @@ class Formatter(object):
self.print(" })")
@contextmanager
- def klass(self, class_name):
+ def klass(self, class_name, class_str):
self.class_name = class_name
self.print()
self.print(" # class {}.{}:".format(self.mod_name, class_name))
@@ -152,89 +153,6 @@ class Formatter(object):
yield key
-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):
- self.fmt = formatter
- self.result_type = result_type
-
- def module(self, mod_name):
- __import__(mod_name)
- with self.fmt.module(mod_name):
- module = sys.modules[mod_name]
- members = inspect.getmembers(module, inspect.isclass)
- ret = self.result_type()
- for class_name, klass in members:
- ret.update(self.klass(class_name, klass))
- return ret
-
- def klass(self, class_name, klass):
- with self.fmt.klass(class_name):
- ret = self.function("__init__", klass)
- # class_members = inspect.getmembers(klass)
- # gives us also the inherited things.
- class_members = sorted(list(klass.__dict__.items()))
- for func_name, func in class_members:
- ret.update(self.function(func_name, func))
- return ret
-
- def function(self, func_name, func):
- ret = self.result_type()
- signature = getattr(func, '__signature__', None)
- if signature is not None:
- with self.fmt.function(func_name, signature) as key:
- ret[key] = signature
- return ret
-
-
-def simplify(signature):
- if isinstance(signature, list):
- # remove duplicates which still sometimes occour:
- ret = set(simplify(sig) for sig in signature)
- return sorted(ret) if len(ret) > 1 else list(ret)[0]
- ret = []
- for pv in signature.parameters.values():
- txt = str(pv)
- if txt == "self":
- continue
- txt = txt[txt.index(":") + 1:]
- if "=" in txt:
- txt = txt[:txt.index("=")]
- quote = txt[0]
- if quote in ("'", '"') and txt[-1] == quote:
- txt = txt[1:-1]
- ret.append(txt)
- return tuple(ret)
-
-
-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 = getattr(func, '__signature__', None)
- sig = simplify(signature) if signature is not None else None
- if sig is not None and func_name not in ("next", "__next__"):
- with self.fmt.function(func_name, sig) as key:
- ret[key] = sig
- return ret
-
-
def enum_all():
fmt = Formatter(None)
enu = SimplifyingEnumerator(fmt)
diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt
index b67a352f0..b4fd1cb99 100644
--- a/sources/shiboken2/ApiExtractor/CMakeLists.txt
+++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt
@@ -37,6 +37,7 @@ abstractmetabuilder.cpp
abstractmetalang.cpp
fileout.cpp
graph.cpp
+messages.cpp
reporthandler.cpp
typeparser.cpp
typesystem.cpp
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index 84c116708..9653831cc 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -27,6 +27,7 @@
****************************************************************************/
#include "abstractmetabuilder_p.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typedatabase.h"
@@ -159,38 +160,18 @@ AbstractMetaEnumList AbstractMetaBuilder::globalEnums() const
return d->m_globalEnums;
}
-static QString msgNoFunctionForModification(const QString &signature,
- const QString &originalSignature,
- const QString &className,
- const QStringList &possibleSignatures,
- const AbstractMetaFunctionList &allFunctions)
-{
- QString result;
- QTextStream str(&result);
- str << "signature '" << signature << '\'';
- if (!originalSignature.isEmpty() && originalSignature != signature)
- str << " (specified as '" << originalSignature << "')";
- str << " for function modification in '"
- << className << "' not found.";
- if (possibleSignatures.isEmpty()) {
- str << " No candidates were found. Member functions: ";
- for (int f = 0, size = allFunctions.size(); f < size; ++f) {
- if (f)
- str << ", ";
- str << allFunctions.at(f)->minimalSignature();
- }
- } else {
- str << " Possible candidates: " << possibleSignatures.join(QLatin1String(", "));
- }
- return result;
+AbstractMetaEnum *AbstractMetaBuilder::findEnum(const TypeEntry *typeEntry) const
+{
+ if (typeEntry && typeEntry->isFlags())
+ typeEntry = static_cast<const FlagsTypeEntry*>(typeEntry)->originator();
+ return d->m_enums.value(typeEntry);
}
void AbstractMetaBuilderPrivate::checkFunctionModifications()
{
- TypeDatabase *types = TypeDatabase::instance();
- const SingleTypeEntryHash entryHash = types->entries();
+ const auto &entries = TypeDatabase::instance()->entries();
- for (SingleTypeEntryHash::const_iterator it = entryHash.cbegin(), end = entryHash.cend(); it != end; ++it) {
+ for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
const TypeEntry *entry = it.value();
if (!entry)
continue;
@@ -241,7 +222,7 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications()
}
}
-AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(ArgumentModelItem argument)
+AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument)
{
AbstractMetaClass* returned = 0;
AbstractMetaType *type = translateType(argument->type());
@@ -256,7 +237,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(ArgumentModelItem
/**
* Checks the argument of a hash function and flags the type if it is a complex type
*/
-void AbstractMetaBuilderPrivate::registerHashFunction(FunctionModelItem function_item)
+void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &function_item)
{
ArgumentList arguments = function_item->arguments();
if (arguments.size() == 1) {
@@ -269,12 +250,12 @@ void AbstractMetaBuilderPrivate::registerHashFunction(FunctionModelItem function
* Check if a class has a debug stream operator that can be used as toString
*/
-void AbstractMetaBuilderPrivate::registerToStringCapability(FunctionModelItem function_item)
+void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelItem &function_item)
{
ArgumentList arguments = function_item->arguments();
if (arguments.size() == 2) {
if (arguments.at(0)->type().toString() == QLatin1String("QDebug")) {
- ArgumentModelItem arg = arguments.at(1);
+ const ArgumentModelItem &arg = arguments.at(1);
if (AbstractMetaClass *cls = argumentToClass(arg)) {
if (arg->type().indirections() < 2)
cls->setToStringCapability(true);
@@ -283,7 +264,7 @@ void AbstractMetaBuilderPrivate::registerToStringCapability(FunctionModelItem fu
}
}
-void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item)
+void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelItem &item)
{
if (item->accessPolicy() != CodeModel::Public)
return;
@@ -348,7 +329,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item
setupFunctionDefaults(metaFunction, baseoperandClass);
baseoperandClass->addFunction(metaFunction);
Q_ASSERT(!metaFunction->wasPrivate());
- } else if (metaFunction) {
+ } else {
delete metaFunction;
}
@@ -356,7 +337,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item
}
}
-void AbstractMetaBuilderPrivate::traverseStreamOperator(FunctionModelItem item)
+void AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem &item)
{
ArgumentList arguments = item->arguments();
if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
@@ -404,7 +385,7 @@ void AbstractMetaBuilderPrivate::traverseStreamOperator(FunctionModelItem item)
funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include());
m_currentClass = oldCurrentClass;
- } else if (streamFunction) {
+ } else {
delete streamFunction;
}
@@ -422,7 +403,7 @@ void AbstractMetaBuilderPrivate::fixQObjectForScope(const FileModelItem &dom,
TypeEntry* entry = types->findType(qualifiedName);
if (entry) {
if (isQObject(dom, qualifiedName) && entry->isComplex())
- ((ComplexTypeEntry*) entry)->setQObject(true);
+ static_cast<ComplexTypeEntry *>(entry)->setQObject(true);
}
}
@@ -475,19 +456,18 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
const ClassList &typeValues = dom->classes();
ReportHandler::setProgressReference(typeValues);
for (const ClassModelItem &item : typeValues) {
- ReportHandler::progress(QLatin1String("Generating class model..."));
- AbstractMetaClass *cls = traverseClass(dom, item);
- if (!cls)
- continue;
-
- addAbstractMetaClass(cls);
+ ReportHandler::progress(QStringLiteral("Generating class model (%1)...")
+ .arg(typeValues.size()));
+ if (AbstractMetaClass *cls = traverseClass(dom, item))
+ addAbstractMetaClass(cls);
}
// We need to know all global enums
const EnumList &enums = dom->enums();
ReportHandler::setProgressReference(enums);
for (const EnumModelItem &item : enums) {
- ReportHandler::progress(QLatin1String("Generating enum model..."));
+ ReportHandler::progress(QStringLiteral("Generating enum model (%1)...")
+ .arg(enums.size()));
AbstractMetaEnum *metaEnum = traverseEnum(item, 0, QSet<QString>());
if (metaEnum) {
if (metaEnum->typeEntry()->generateCode())
@@ -498,7 +478,8 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
const QSet<NamespaceModelItem> &namespaceTypeValues = dom->uniqueNamespaces();
ReportHandler::setProgressReference(namespaceTypeValues);
for (const NamespaceModelItem &item : namespaceTypeValues) {
- ReportHandler::progress(QLatin1String("Generating namespace model..."));
+ ReportHandler::progress(QStringLiteral("Generating namespace model (%1)...")
+ .arg(namespaceTypeValues.size()));
AbstractMetaClass *metaClass = traverseNamespace(dom, item);
if (metaClass)
m_metaClasses << metaClass;
@@ -509,11 +490,14 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
const TypeDefList typeDefs = dom->typeDefs();
ReportHandler::setProgressReference(typeDefs);
for (const TypeDefModelItem &typeDef : typeDefs) {
- ReportHandler::progress(QLatin1String("Resolving typedefs..."));
- AbstractMetaClass* cls = traverseTypeDef(dom, typeDef);
- addAbstractMetaClass(cls);
+ ReportHandler::progress(QStringLiteral("Resolving typedefs (%1)...")
+ .arg(typeDefs.size()));
+ if (AbstractMetaClass *cls = traverseTypeDef(dom, typeDef))
+ addAbstractMetaClass(cls);
}
+ traverseTypesystemTypedefs();
+
for (const ClassModelItem &item : typeValues)
traverseClassMembers(item);
@@ -580,13 +564,12 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
if (cls->isAbstract() && !cls->isInterface())
cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + QLatin1String("$ConcreteWrapper"));
}
- const TypeEntryHash allEntries = types->allEntries();
- ReportHandler::progress(QLatin1String("Detecting inconsistencies in typesystem..."));
- for (TypeEntryHash::const_iterator it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
- for (TypeEntry *entry : it.value()) {
- if (entry->isPrimitive())
- continue;
-
+ const auto &allEntries = types->entries();
+ ReportHandler::progress(QStringLiteral("Detecting inconsistencies in typesystem (%1)...")
+ .arg(allEntries.size()));
+ for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
+ TypeEntry *entry = it.value();
+ if (!entry->isPrimitive()) {
if ((entry->isValue() || entry->isObject())
&& !entry->isString()
&& !entry->isChar()
@@ -616,20 +599,13 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
}
}
} else if (entry->isEnum() && (entry->generateCode() & TypeEntry::GenerateTargetLang)) {
- const QString name = ((EnumTypeEntry*) entry)->targetLangQualifier();
+ const QString name = static_cast<const EnumTypeEntry *>(entry)->targetLangQualifier();
AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, name);
- bool enumFound = false;
- if (cls) {
- enumFound = cls->findEnum(entry->targetLangName());
- } else { // Global enum
- for (AbstractMetaEnum *metaEnum : qAsConst(m_enums)) {
- if (metaEnum->typeEntry() == entry) {
- enumFound = true;
- break;
- }
- }
- }
+ const bool enumFound = cls
+ ? cls->findEnum(entry->targetLangName()) != nullptr
+ : m_enums.contains(entry);
+
if (!enumFound) {
entry->setCodeGeneration(TypeEntry::GenerateNothing);
qCWarning(lcShiboken).noquote().nospace()
@@ -727,6 +703,15 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
std::puts("");
}
+static bool metaEnumLessThan(const AbstractMetaEnum *e1, const AbstractMetaEnum *e2)
+{ return e1->fullName() < e2->fullName(); }
+
+static bool metaClassLessThan(const AbstractMetaClass *c1, const AbstractMetaClass *c2)
+{ return c1->fullName() < c2->fullName(); }
+
+static bool metaFunctionLessThan(const AbstractMetaFunction *f1, const AbstractMetaFunction *f2)
+{ return f1->name() < f2->name(); }
+
bool AbstractMetaBuilder::build(const QByteArrayList &arguments,
LanguageLevel level,
unsigned clangFlags)
@@ -737,6 +722,14 @@ bool AbstractMetaBuilder::build(const QByteArrayList &arguments,
if (ReportHandler::isDebug(ReportHandler::MediumDebug))
qCDebug(lcShiboken) << dom.data();
d->traverseDom(dom);
+
+ // Ensure that indexes are in alphabetical order, roughly
+ std::sort(d->m_globalEnums.begin(), d->m_globalEnums.end(), metaEnumLessThan);
+ std::sort(d->m_metaClasses.begin(), d->m_metaClasses.end(), metaClassLessThan);
+ std::sort(d->m_templates.begin(), d->m_templates.end(), metaClassLessThan);
+ std::sort(d->m_smartPointers.begin(), d->m_smartPointers.end(), metaClassLessThan);
+ std::sort(d->m_globalFunctions.begin(), d->m_globalFunctions.end(), metaFunctionLessThan);
+
return true;
}
@@ -749,9 +742,6 @@ void AbstractMetaBuilder::setLogDirectory(const QString& logDir)
void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls)
{
- if (!cls)
- return;
-
cls->setOriginalAttributes(cls->attributes());
if (cls->typeEntry()->isContainer()) {
m_templates << cls;
@@ -848,7 +838,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel
return metaClass;
}
-AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumItem,
+AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem &enumItem,
AbstractMetaClass *enclosing,
const QSet<QString> &enumsDeclarations)
{
@@ -857,7 +847,7 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
TypeEntry* typeEntry = 0;
if (enumItem->accessPolicy() == CodeModel::Private) {
QStringList names = enumItem->qualifiedName();
- QString enumName = names.constLast();
+ const QString &enumName = names.constLast();
QString nspace;
if (names.size() > 1)
nspace = QStringList(names.mid(0, names.size() - 1)).join(colonColon());
@@ -892,15 +882,23 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
return 0;
}
- if ((!typeEntry || !typeEntry->isEnum())) {
- if (!m_currentClass ||
- (m_currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("enum '%1' does not have a type entry or is not an enum")
- .arg(qualifiedName);
+ const bool rejectionWarning = !m_currentClass
+ || (m_currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang);
+
+ if (!typeEntry) {
+ if (rejectionWarning)
+ qCWarning(lcShiboken, "%s", qPrintable(msgNoEnumTypeEntry(enumItem, className)));
+ m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem);
+ return nullptr;
+ }
+
+ if (!typeEntry->isEnum()) {
+ if (rejectionWarning) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgNoEnumTypeConflict(enumItem, className, typeEntry)));
}
m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem);
- return 0;
+ return nullptr;
}
AbstractMetaEnum *metaEnum = new AbstractMetaEnum;
@@ -946,15 +944,9 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
qCDebug(lcShiboken) << " - " << metaEnumValue->name() << " = "
<< metaEnumValue->value() << " = " << metaEnumValue->value();
}
-
- // Add into global register...
- if (enclosing)
- m_enumValues[enclosing->name() + colonColon() + metaEnumValue->name()] = metaEnumValue;
- else
- m_enumValues[metaEnumValue->name()] = metaEnumValue;
}
- m_enums << metaEnum;
+ m_enums.insert(typeEntry, metaEnum);
if (!metaEnum->typeEntry()->include().isValid())
setInclude(metaEnum->typeEntry(), enumItem->fileName());
@@ -962,6 +954,15 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
metaEnum->setOriginalAttributes(metaEnum->attributes());
// Register all enum values on Type database
+ QString prefix;
+ if (enclosing) {
+ prefix += enclosing->typeEntry()->qualifiedCppName();
+ prefix += colonColon();
+ }
+ if (enumItem->enumKind() == EnumClass) {
+ prefix += enumItem->name();
+ prefix += colonColon();
+ }
const EnumeratorList &enumerators = enumItem->enumerators();
for (const EnumeratorModelItem &e : enumerators) {
QString name;
@@ -969,11 +970,12 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
name += enclosing->name();
name += colonColon();
}
- name += e->name();
EnumValueTypeEntry *enumValue =
- new EnumValueTypeEntry(name, e->stringValue(),
+ new EnumValueTypeEntry(prefix + e->name(), e->stringValue(),
enumTypeEntry, enumTypeEntry->version());
TypeDatabase::instance()->addType(enumValue);
+ if (e->value().isNullValue())
+ enumTypeEntry->setNullValue(enumValue);
}
return metaEnum;
@@ -1014,7 +1016,7 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelIt
AbstractMetaClass *metaClass = new AbstractMetaClass;
metaClass->setTypeDef(true);
metaClass->setTypeEntry(type);
- metaClass->setBaseClassNames(QStringList() << typeDef->type().qualifiedName().join(colonColon()));
+ metaClass->setBaseClassNames(QStringList(typeDef->type().toString()));
*metaClass += AbstractMetaAttributes::Public;
// Set the default include file name
@@ -1026,6 +1028,22 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelIt
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) {
+ TypedefEntry *te = it.value();
+ AbstractMetaClass *metaClass = new AbstractMetaClass;
+ metaClass->setTypeDef(true);
+ metaClass->setTypeEntry(te->target());
+ metaClass->setBaseClassNames(QStringList(te->sourceType()));
+ *metaClass += AbstractMetaAttributes::Public;
+ fillAddedFunctions(metaClass);
+ addAbstractMetaClass(metaClass);
+ }
+}
+
AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom,
const ClassModelItem &classItem)
{
@@ -1204,18 +1222,18 @@ void AbstractMetaBuilderPrivate::traverseNamespaceMembers(NamespaceModelItem ite
m_currentClass = oldCurrentClass;
}
-static inline QString fieldSignatureWithType(VariableModelItem field)
+static inline QString fieldSignatureWithType(const VariableModelItem &field)
{
return field->name() + QStringLiteral(" -> ") + field->type().toString();
}
static inline QString qualifiedFieldSignatureWithType(const QString &className,
- VariableModelItem field)
+ const VariableModelItem &field)
{
return className + colonColon() + fieldSignatureWithType(field);
}
-AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem field,
+AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(const VariableModelItem &field,
const AbstractMetaClass *cls)
{
QString fieldName = field->name();
@@ -1272,7 +1290,7 @@ AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem f
return metaField;
}
-void AbstractMetaBuilderPrivate::traverseFields(ScopeModelItem scope_item,
+void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item,
AbstractMetaClass *metaClass)
{
const VariableList &variables = scope_item->variables();
@@ -1327,14 +1345,8 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF
static bool _compareAbstractMetaTypes(const AbstractMetaType* type, const AbstractMetaType* other)
{
- if (!type && !other)
- return true;
- if (!type || !other)
- return false;
- return type->typeEntry() == other->typeEntry()
- && type->isConstant() == other->isConstant()
- && type->referenceType() == other->referenceType()
- && type->indirections() == other->indirections();
+ return (type != nullptr) == (other != nullptr)
+ && (type == nullptr || *type == *other);
}
static bool _compareAbstractMetaFunctions(const AbstractMetaFunction* func, const AbstractMetaFunction* other)
@@ -1426,7 +1438,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem,
}
} else if (QPropertySpec* reset = metaClass->propertySpecForReset(metaFunction->name())) {
// Property resetter must be in the form "void name()"
- if ((!metaFunction->type()) && (metaFunction->arguments().size() == 0)) {
+ if ((!metaFunction->type()) && metaFunction->arguments().isEmpty()) {
*metaFunction += AbstractMetaAttributes::PropertyResetter;
metaFunction->setPropertySpec(reset);
}
@@ -1635,7 +1647,7 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass)
return true;
}
-void AbstractMetaBuilderPrivate::traverseEnums(ScopeModelItem scopeItem,
+void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem,
AbstractMetaClass *metaClass,
const QStringList &enumsDeclarations)
{
@@ -1724,13 +1736,9 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu
replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1);
if (!replacedExpression.isEmpty()) {
- QString expr = replacedExpression;
if (!metaFunction->removedDefaultExpression(m_currentClass, i + 1)) {
- metaArg->setDefaultValueExpression(expr);
- metaArg->setOriginalDefaultValueExpression(expr);
-
- if (metaArg->type()->isEnum() || metaArg->type()->isFlags())
- m_enumDefaultArguments << QPair<AbstractMetaArgument*, AbstractMetaFunction*>(metaArg, metaFunction);
+ metaArg->setDefaultValueExpression(replacedExpression);
+ metaArg->setOriginalDefaultValueExpression(replacedExpression);
}
}
}
@@ -1784,7 +1792,7 @@ void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func, co
}
}
-static QString functionSignature(FunctionModelItem functionItem)
+static QString functionSignature(const FunctionModelItem &functionItem)
{
QStringList args;
const ArgumentList &arguments = functionItem->arguments();
@@ -1802,50 +1810,6 @@ static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem
result += functionSignature(functionItem);
return result;
}
-
-static inline QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n)
-{
- QString result;
- QTextStream str(&result);
- str << "unmatched type '" << arg->type().toString() << "' in parameter #"
- << (n + 1);
- if (!arg->name().isEmpty())
- str << " \"" << arg->name() << '"';
- return result;
-}
-
-static inline QString msgUnmatchedReturnType(const FunctionModelItem &functionItem)
-{
- return QLatin1String("unmatched return type '")
- + functionItem->type().toString() + QLatin1Char('\'');
-}
-
-static inline QString msgVoidParameterType(const ArgumentModelItem &arg, int n)
-{
- QString result;
- QTextStream str(&result);
- str << "'void' encountered at parameter #" << (n + 1);
- if (!arg->name().isEmpty())
- str << " \"" << arg->name() << '"';
- return result;
-}
-
-static QString msgSkippingFunction(const FunctionModelItem &functionItem,
- const QString &signature, const QString &why)
-{
- QString result;
- QTextStream str(&result);
- str << "skipping ";
- if (functionItem->isAbstract())
- str << "abstract ";
- str << "function '" << signature << "', " << why;
- if (functionItem->isAbstract()) {
- str << "\nThis will lead to compilation errors due to not "
- "being able to instantiate the wrapper.";
- }
- return result;
-}
-
static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeModel::FunctionType ft)
{
AbstractMetaFunction::FunctionType result = AbstractMetaFunction::NormalFunction;
@@ -1874,12 +1838,6 @@ static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeM
return result;
}
-static inline QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason)
-{
- return function + QLatin1String(": Cannot use parameter ") + QString::number(i + 1)
- + QLatin1String(" as an array: ") + reason;
-}
-
bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func,
const FunctionModelItem &functionItem,
int i)
@@ -1911,12 +1869,40 @@ bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func
return true;
}
-AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModelItem functionItem)
+static bool generateExceptionHandling(const AbstractMetaFunction *func,
+ ExceptionSpecification spec,
+ TypeSystem::ExceptionHandling handling)
+{
+ switch (func->functionType()) {
+ case AbstractMetaFunction::CopyConstructorFunction:
+ case AbstractMetaFunction::MoveConstructorFunction:
+ case AbstractMetaFunction::AssignmentOperatorFunction:
+ case AbstractMetaFunction::MoveAssignmentOperatorFunction:
+ case AbstractMetaFunction::DestructorFunction:
+ return false;
+ default:
+ break;
+ }
+ switch (handling) {
+ case TypeSystem::ExceptionHandling::On:
+ return true;
+ case TypeSystem::ExceptionHandling::AutoDefaultToOn:
+ return spec != ExceptionSpecification::NoExcept;
+ case TypeSystem::ExceptionHandling::AutoDefaultToOff:
+ return spec == ExceptionSpecification::Throws;
+ default:
+ break;
+ }
+ return false;
+}
+
+AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem)
{
if (functionItem->isDeleted() || !functionItem->templateParameters().isEmpty())
return nullptr;
QString functionName = functionItem->name();
QString className;
+ TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
if (m_currentClass) {
// Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT
// and overridden metaObject(), QGADGET helpers
@@ -1925,6 +1911,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
return nullptr;
}
className = m_currentClass->typeEntry()->qualifiedCppName();
+ exceptionHandling = m_currentClass->typeEntry()->exceptionHandling();
if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject"))
return nullptr;
}
@@ -1936,13 +1923,16 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
QString rejectReason;
if (TypeDatabase::instance()->isFunctionRejected(className, functionName, &rejectReason)) {
m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
- return 0;
- }
- else if (TypeDatabase::instance()->isFunctionRejected(className,
- functionSignature(functionItem), &rejectReason)) {
- m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
- return 0;
+ return nullptr;
}
+ const QString &signature = functionSignature(functionItem);
+ const bool rejected =
+ TypeDatabase::instance()->isFunctionRejected(className, signature, &rejectReason);
+ qCDebug(lcShiboken).nospace().noquote() << __FUNCTION__
+ << ": Checking rejection for signature \"" << signature << "\" for " << className
+ << ": " << rejected;
+ if (rejected)
+ return nullptr;
if (functionItem->isFriend())
return 0;
@@ -1951,6 +1941,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
// Additional check for assignment/move assignment down below
metaFunction->setFunctionType(functionTypeFromCodeModel(functionItem->functionType()));
metaFunction->setConstant(functionItem->isConstant());
+ metaFunction->setExceptionSpecification(functionItem->exceptionSpecification());
if (ReportHandler::isDebug(ReportHandler::MediumDebug))
qCDebug(lcShiboken).noquote().nospace() << " - " << functionName << "()";
@@ -1987,6 +1978,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
else
*metaFunction += AbstractMetaAttributes::Protected;
+ QString errorMessage;
switch (metaFunction->functionType()) {
case AbstractMetaFunction::DestructorFunction:
break;
@@ -2005,9 +1997,9 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
AbstractMetaType *type = nullptr;
if (!returnType.isVoid()) {
- type = translateType(returnType);
+ type = translateType(returnType, true, &errorMessage);
if (!type) {
- const QString reason = msgUnmatchedReturnType(functionItem);
+ const QString reason = msgUnmatchedReturnType(functionItem, errorMessage);
qCWarning(lcShiboken, "%s",
qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason)));
m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType);
@@ -2033,7 +2025,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
AbstractMetaArgumentList metaArguments;
for (int i = 0; i < arguments.size(); ++i) {
- ArgumentModelItem arg = arguments.at(i);
+ const ArgumentModelItem &arg = arguments.at(i);
if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) {
m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
@@ -2041,7 +2033,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
return nullptr;
}
- AbstractMetaType *metaType = translateType(arg->type());
+ AbstractMetaType *metaType = translateType(arg->type(), true, &errorMessage);
if (!metaType) {
// If an invalid argument has a default value, simply remove it
if (arg->defaultValue()) {
@@ -2058,18 +2050,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
break;
}
Q_ASSERT(metaType == 0);
- const QString reason = msgUnmatchedParameterType(arg, i);
- qCWarning(lcShiboken, "%s",
- qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason)));
- const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn
- + QLatin1String(": ") + reason;
- m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType);
- delete metaFunction;
- return nullptr;
- }
-
- if (metaType == Q_NULLPTR) {
- const QString reason = msgVoidParameterType(arg, i);
+ const QString reason = msgUnmatchedParameterType(arg, i, errorMessage);
qCWarning(lcShiboken, "%s",
qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason)));
const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn
@@ -2089,9 +2070,22 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
metaFunction->setArguments(metaArguments);
+ const FunctionModificationList functionMods = metaFunction->modifications(m_currentClass);
+
+ for (const FunctionModification &mod : functionMods) {
+ if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) {
+ exceptionHandling = mod.exceptionHandling();
+ break;
+ }
+ }
+
+ metaFunction->setGenerateExceptionHandling(generateExceptionHandling(metaFunction,
+ functionItem->exceptionSpecification(),
+ exceptionHandling));
+
// Find the correct default values
for (int i = 0, size = metaArguments.size(); i < size; ++i) {
- ArgumentModelItem arg = arguments.at(i);
+ const ArgumentModelItem &arg = arguments.at(i);
AbstractMetaArgument* metaArg = metaArguments.at(i);
//use relace-default-expression for set default value
@@ -2099,9 +2093,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
if (m_currentClass) {
replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1);
} else {
- FunctionModificationList mods = TypeDatabase::instance()->functionModifications(metaFunction->minimalSignature());
- if (!mods.isEmpty()) {
- QVector<ArgumentModification> argMods = mods.constFirst().argument_mods;
+ if (!functionMods.isEmpty()) {
+ QVector<ArgumentModification> argMods = functionMods.constFirst().argument_mods;
if (!argMods.isEmpty())
replacedExpression = argMods.constFirst().replacedDefaultExpression;
}
@@ -2119,10 +2112,6 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
expr = replacedExpression;
}
metaArg->setDefaultValueExpression(expr);
-
- if (metaArg->type()->isEnum() || metaArg->type()->isFlags())
- m_enumDefaultArguments << QPair<AbstractMetaArgument *, AbstractMetaFunction *>(metaArg, metaFunction);
-
hasDefaultValue = !expr.isEmpty();
}
@@ -2140,9 +2129,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
}
if (!metaArguments.isEmpty()) {
- const FunctionModificationList &mods = metaFunction->modifications(m_currentClass);
- fixArgumentNames(metaFunction, mods);
- for (const FunctionModification &mod : mods) {
+ fixArgumentNames(metaFunction, functionMods);
+ for (const FunctionModification &mod : functionMods) {
for (const ArgumentModification &argMod : mod.argument_mods) {
if (argMod.array)
setArrayArgumentType(metaFunction, functionItem, argMod.index - 1);
@@ -2202,8 +2190,8 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction:
if (!type) {
QStringList candidates;
- SingleTypeEntryHash entries = typeDb->entries();
- for (SingleTypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
+ const auto &entries = typeDb->entries();
+ for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
// Let's try to find the type in different scopes.
if (it.key().endsWith(colonColon() + typeName))
candidates.append(it.key());
@@ -2211,15 +2199,17 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction:
QString msg = QStringLiteral("Type '%1' wasn't found in the type database.\n").arg(typeName);
- if (candidates.isEmpty())
- qFatal(qPrintable(QString(msg + QLatin1String("Declare it in the type system using the proper <*-type> tag."))), NULL);
+ if (candidates.isEmpty()) {
+ qFatal("%sDeclare it in the type system using the proper <*-type> tag.",
+ qPrintable(msg));
+ }
msg += QLatin1String("Remember to inform the full qualified name for the type you want to use.\nCandidates are:\n");
candidates.sort();
for (const QString& candidate : qAsConst(candidates)) {
msg += QLatin1String(" ") + candidate + QLatin1Char('\n');
}
- qFatal(qPrintable(msg), NULL);
+ qFatal("%s", qPrintable(msg));
}
AbstractMetaType *metaType = new AbstractMetaType;
@@ -2243,7 +2233,7 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC
{
const TypeEntry* type = 0;
QStringList context = metaClass->qualifiedCppName().split(colonColon());
- while(!type && (context.size() > 0) ) {
+ while (!type && !context.isEmpty()) {
type = TypeDatabase::instance()->findType(context.join(colonColon()) + colonColon() + qualifiedName);
context.removeLast();
}
@@ -2251,43 +2241,48 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC
}
AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei,
- bool resolveType)
+ bool resolveType,
+ QString *errorMessage)
+{
+ return translateTypeStatic(_typei, m_currentClass, this, resolveType, errorMessage);
+}
+
+AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei,
+ AbstractMetaClass *currentClass,
+ AbstractMetaBuilderPrivate *d,
+ bool resolveType,
+ QString *errorMessageIn)
{
// 1. Test the type info without resolving typedefs in case this is present in the
// type system
- TypeInfo typei;
if (resolveType) {
- if (AbstractMetaType *resolved = translateType(_typei, false))
+ if (AbstractMetaType *resolved = translateTypeStatic(_typei, currentClass, d, false, errorMessageIn))
return resolved;
}
- if (!resolveType) {
- typei = _typei;
- } else {
+ 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
- int i = m_scopes.size() - 1;
+ int i = d ? d->m_scopes.size() - 1 : -1;
while (i >= 0) {
- typei = TypeInfo::resolveType(_typei, m_scopes.at(i--));
- if (typei.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon()))
+ typeInfo = TypeInfo::resolveType(_typei, d->m_scopes.at(i--));
+ if (typeInfo.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon()))
break;
}
}
- if (typei.isFunctionPointer())
+ if (typeInfo.isFunctionPointer()) {
+ if (errorMessageIn)
+ *errorMessageIn = msgUnableToTranslateType(_typei, QLatin1String("Unsupported function pointer."));
return nullptr;
+ }
QString errorMessage;
- TypeInfo typeInfo = TypeParser::parse(typei.toString(), &errorMessage);
- if (typeInfo.qualifiedName().isEmpty()) {
- qWarning().noquote().nospace() << "Unable to translate type \"" << _typei.toString()
- << "\": " << errorMessage;
- return 0;
- }
// 2. Handle arrays.
// 2.1 Handle char arrays with unspecified size (aka "const char[]") as "const char*" with
@@ -2312,16 +2307,22 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
if (!typeInfo.arrayElements().isEmpty() && !isConstCharStarCase) {
TypeInfo newInfo;
//newInfo.setArguments(typeInfo.arguments());
- newInfo.setIndirections(typeInfo.indirections());
+ 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());
- AbstractMetaType *elementType = translateType(newInfo);
- if (!elementType)
+ AbstractMetaType *elementType = translateTypeStatic(newInfo, currentClass, d, true, &errorMessage);
+ if (!elementType) {
+ if (errorMessageIn) {
+ errorMessage.prepend(QLatin1String("Unable to translate array element: "));
+ *errorMessageIn = msgUnableToTranslateType(_typei, errorMessage);
+ }
return nullptr;
+ }
for (int i = typeInfo.arrayElements().size() - 1; i >= 0; --i) {
AbstractMetaType *arrayType = new AbstractMetaType;
@@ -2329,7 +2330,9 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
const QString &arrayElement = typeInfo.arrayElements().at(i);
if (!arrayElement.isEmpty()) {
bool _ok;
- const qint64 elems = findOutValueFromString(arrayElement, _ok);
+ const qint64 elems = d
+ ? d->findOutValueFromString(arrayElement, _ok)
+ : arrayElement.toLongLong(&_ok, 0);
if (_ok)
arrayType->setArrayElementCount(int(elems));
}
@@ -2344,8 +2347,11 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
QStringList qualifierList = typeInfo.qualifiedName();
if (qualifierList.isEmpty()) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("horribly broken type '%1'").arg(_typei.toString());
+ errorMessage = msgUnableToTranslateType(_typei, QLatin1String("horribly broken type"));
+ if (errorMessageIn)
+ *errorMessageIn = errorMessage;
+ else
+ qCWarning(lcShiboken,"%s", qPrintable(errorMessage));
return nullptr;
}
@@ -2353,19 +2359,21 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
QString name = qualifierList.takeLast();
// 4. Special case QFlags (include instantiation in name)
- if (qualifiedName == QLatin1String("QFlags"))
+ if (qualifiedName == QLatin1String("QFlags")) {
qualifiedName = typeInfo.toString();
+ typeInfo.clearInstantiations();
+ }
const TypeEntry *type = 0;
// 5. Try to find the type
// 5.1 - Try first using the current scope
- if (m_currentClass) {
- type = findTypeEntryUsingContext(m_currentClass, qualifiedName);
+ if (currentClass) {
+ type = findTypeEntryUsingContext(currentClass, qualifiedName);
// 5.1.1 - Try using the class parents' scopes
- if (!type && !m_currentClass->baseClassNames().isEmpty()) {
- const AbstractMetaClassList &baseClasses = getBaseClasses(m_currentClass);
+ if (!type && d && !currentClass->baseClassNames().isEmpty()) {
+ const AbstractMetaClassList &baseClasses = d->getBaseClasses(currentClass);
for (const AbstractMetaClass *cls : baseClasses) {
type = findTypeEntryUsingContext(cls, qualifiedName);
if (type)
@@ -2388,36 +2396,40 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
// 8. No? Check if the current class is a template and this type is one
// of the parameters.
- if (!type && m_currentClass) {
- const QVector<TypeEntry *> &template_args = m_currentClass->templateArguments();
+ if (!type && currentClass) {
+ const QVector<TypeEntry *> &template_args = currentClass->templateArguments();
for (TypeEntry *te : template_args) {
if (te->name() == qualifiedName)
type = te;
}
}
- if (!type)
+ if (!type) {
+ if (errorMessageIn) {
+ *errorMessageIn =
+ msgUnableToTranslateType(_typei, msgCannotFindTypeEntry(qualifiedName));
+ }
return nullptr;
-
- // Used to for diagnostics later...
- m_usedTypes << type;
+ }
// These are only implicit and should not appear in code...
Q_ASSERT(!type->isInterface());
AbstractMetaType *metaType = new AbstractMetaType;
metaType->setTypeEntry(type);
- metaType->setIndirections(typeInfo.indirections());
+ metaType->setIndirectionsV(typeInfo.indirectionsV());
metaType->setReferenceType(typeInfo.referenceType());
metaType->setConstant(typeInfo.isConstant());
+ metaType->setVolatile(typeInfo.isVolatile());
metaType->setOriginalTypeDescription(_typei.toString());
- const auto &templateArguments = typeInfo.arguments();
+ const auto &templateArguments = typeInfo.instantiations();
for (int t = 0, size = templateArguments.size(); t < size; ++t) {
- TypeInfo ti = templateArguments.at(t);
- ti.setQualifiedName(ti.instantiationName());
- AbstractMetaType *targType = translateType(ti);
+ const TypeInfo &ti = templateArguments.at(t);
+ AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, true, &errorMessage);
if (!targType) {
+ if (errorMessageIn)
+ *errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage);
delete metaType;
return nullptr;
}
@@ -2434,6 +2446,33 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
return metaType;
}
+AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei,
+ AbstractMetaClass *currentClass,
+ bool resolveType,
+ QString *errorMessage)
+{
+ return AbstractMetaBuilderPrivate::translateTypeStatic(_typei, currentClass,
+ nullptr, resolveType,
+ errorMessage);
+}
+
+AbstractMetaType *AbstractMetaBuilder::translateType(const QString &t,
+ AbstractMetaClass *currentClass,
+ bool resolveType,
+ 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 nullptr;
+ }
+ return translateType(typeInfo, currentClass, resolveType, errorMessageIn);
+}
qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringValue, bool &ok)
{
@@ -2472,7 +2511,7 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV
return 0;
}
-QString AbstractMetaBuilderPrivate::fixDefaultValue(ArgumentModelItem item,
+QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &item,
AbstractMetaType *type,
AbstractMetaFunction *fnc,
AbstractMetaClass *implementingClass,
@@ -2676,59 +2715,55 @@ bool AbstractMetaBuilderPrivate::ancestorHasPrivateCopyConstructor(const Abstrac
return false;
}
-AbstractMetaType* AbstractMetaBuilderPrivate::inheritTemplateType(const QVector<AbstractMetaType *> &templateTypes,
- const AbstractMetaType *metaType,
- bool *ok)
+AbstractMetaType *
+ AbstractMetaBuilderPrivate::inheritTemplateType(const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaType *metaType)
{
- if (ok)
- *ok = true;
- if (!metaType || (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations()))
- return metaType ? metaType->copy() : 0;
+ Q_ASSERT(metaType);
+
+ QScopedPointer<AbstractMetaType> returned(metaType->copy());
- AbstractMetaType *returned = metaType->copy();
- returned->setOriginalTemplateType(metaType->copy());
+ if (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations())
+ return returned.take();
+
+ returned->setOriginalTemplateType(metaType);
if (returned->typeEntry()->isTemplateArgument()) {
const TemplateArgumentEntry* tae = static_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.
- if (templateTypes.size() <= tae->ordinal() || templateTypes.at(tae->ordinal())->typeEntry()->name() == QLatin1String("void")) {
- if (ok)
- *ok = false;
- return 0;
- }
+ const AbstractMetaType *templateType = templateTypes.value(tae->ordinal());
+ if (!templateType || templateType->typeEntry()->isVoid())
+ return nullptr;
AbstractMetaType* t = returned->copy();
- t->setTypeEntry(templateTypes.at(tae->ordinal())->typeEntry());
- t->setIndirections(templateTypes.at(tae->ordinal())->indirections() + t->indirections() ? 1 : 0);
+ t->setTypeEntry(templateType->typeEntry());
+ t->setIndirections(templateType->indirections() + t->indirections() ? 1 : 0);
t->decideUsagePattern();
- delete returned;
- returned = inheritTemplateType(templateTypes, t, ok);
- if (ok && !(*ok))
- return 0;
+ return inheritTemplateType(templateTypes, t);
}
if (returned->hasInstantiations()) {
AbstractMetaTypeList instantiations = returned->instantiations();
for (int i = 0; i < instantiations.count(); ++i) {
- AbstractMetaType *type = instantiations[i];
- instantiations[i] = inheritTemplateType(templateTypes, type, ok);
- if (ok && !(*ok))
- return 0;
+ instantiations[i] =
+ inheritTemplateType(templateTypes, instantiations.at(i));
+ if (!instantiations.at(i))
+ return nullptr;
}
returned->setInstantiations(instantiations, true);
}
- return returned;
+ return returned.take();
}
bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
const AbstractMetaClass *templateClass,
const TypeInfo &info)
{
- QVector<TypeInfo> targs = info.arguments();
+ QVector<TypeInfo> targs = info.instantiations();
QVector<AbstractMetaType *> templateTypes;
if (subclass->isTypeDef()) {
@@ -2743,20 +2778,35 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
for (const TypeInfo &i : qAsConst(targs)) {
QString typeName = i.qualifiedName().join(colonColon());
- QStringList possibleNames;
- possibleNames << subclass->qualifiedCppName() + colonColon() + typeName;
- possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName;
- if (subclass->enclosingClass())
- possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName;
- possibleNames << typeName;
-
- TypeDatabase* typeDb = TypeDatabase::instance();
- TypeEntry* t = 0;
- QString templateParamName;
- for (const QString &possibleName : qAsConst(possibleNames)) {
- t = typeDb->findType(possibleName);
- if (t)
- break;
+ TypeDatabase *typeDb = TypeDatabase::instance();
+ TypeEntry *t = nullptr;
+ // 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.
+ const bool isNumber = std::all_of(typeName.cbegin(), typeName.cend(),
+ [](QChar c) { return c.isDigit(); });
+ if (isNumber) {
+ t = typeDb->findType(typeName);
+ if (!t) {
+ t = new EnumValueTypeEntry(typeName, typeName, nullptr,
+ QVersionNumber(0, 0));
+ t->setCodeGeneration(0);
+ typeDb->addType(t);
+ }
+ } else {
+ QStringList possibleNames;
+ possibleNames << subclass->qualifiedCppName() + colonColon() + typeName;
+ possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName;
+ if (subclass->enclosingClass())
+ possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName;
+ possibleNames << typeName;
+
+ for (const QString &possibleName : qAsConst(possibleNames)) {
+ t = typeDb->findType(possibleName);
+ if (t)
+ break;
+ }
}
if (t) {
@@ -2764,48 +2814,48 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
temporaryType->setTypeEntry(t);
temporaryType->setConstant(i.isConstant());
temporaryType->setReferenceType(i.referenceType());
- temporaryType->setIndirections(i.indirections());
+ temporaryType->setIndirectionsV(i.indirectionsV());
temporaryType->decideUsagePattern();
templateTypes << temporaryType;
} else {
qCWarning(lcShiboken).noquote().nospace()
- << "Ignoring template parameter " << templateParamName << " from "
- << info.instantiationName() << ", because I don't know what it is.";
+ << "Ignoring template parameter " << typeName << " from "
+ << info.toString() << ". The corresponding type was not found in the typesystem.";
}
}
- AbstractMetaFunctionList funcs = subclass->functions();
+ const AbstractMetaFunctionList &subclassFuncs = subclass->functions();
const AbstractMetaFunctionList &templateClassFunctions = templateClass->functions();
for (const AbstractMetaFunction *function : templateClassFunctions) {
- if (function->isModifiedRemoved(TypeSystem::All))
+ // If the function is modified or the instantiation has an equally named
+ // function we have shadowing, so we need to skip it.
+ if (function->isModifiedRemoved(TypeSystem::All)
+ || AbstractMetaFunction::find(subclassFuncs, function->name()) != nullptr) {
continue;
+ }
- AbstractMetaFunction *f = function->copy();
+ QScopedPointer<AbstractMetaFunction> f(function->copy());
f->setArguments(AbstractMetaArgumentList());
- bool ok = true;
- AbstractMetaType *ftype = function->type();
- f->replaceType(inheritTemplateType(templateTypes, ftype, &ok));
- if (!ok) {
- delete f;
- continue;
+ if (function->type()) { // Non-void
+ AbstractMetaType *returnType = inheritTemplateType(templateTypes, function->type());
+ if (!returnType)
+ continue;
+ f->replaceType(returnType);
}
const AbstractMetaArgumentList &arguments = function->arguments();
for (AbstractMetaArgument *argument : arguments) {
- AbstractMetaType* atype = argument->type();
-
- AbstractMetaArgument *arg = argument->copy();
- arg->replaceType(inheritTemplateType(templateTypes, atype, &ok));
- if (!ok)
+ AbstractMetaType *argType = inheritTemplateType(templateTypes, argument->type());
+ if (!argType)
break;
+ AbstractMetaArgument *arg = argument->copy();
+ arg->replaceType(argType);
f->addArgument(arg);
}
- if (!ok) {
- delete f;
+ if (f->arguments().size() < function->arguments().size())
continue;
- }
// There is no base class in the target language to inherit from here, so
// the template instantiation is the class that implements the function.
@@ -2816,27 +2866,11 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
// on the inherited functions.
f->setDeclaringClass(subclass);
-
- if (f->isConstructor() && subclass->isTypeDef()) {
+ if (f->isConstructor()) {
+ if (!subclass->isTypeDef())
+ continue;
f->setName(subclass->name());
f->setOriginalName(subclass->name());
- } else if (f->isConstructor()) {
- delete f;
- continue;
- }
-
- // if the instantiation has a function named the same as an existing
- // function we have shadowing so we need to skip it.
- bool found = false;
- for (int i = 0; i < funcs.size(); ++i) {
- if (funcs.at(i)->name() == f->name()) {
- found = true;
- continue;
- }
- }
- if (found) {
- delete f;
- continue;
}
ComplexTypeEntry* te = subclass->typeEntry();
@@ -2863,7 +2897,27 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
te->addFunctionModification(mod);
}
- subclass->addFunction(f);
+ subclass->addFunction(f.take());
+ }
+
+ const AbstractMetaFieldList &subClassFields = 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(TypeSystem::All)
+ || field->attributes().testFlag(AbstractMetaAttributes::Static)
+ || AbstractMetaField::find(subClassFields, field->name()) != nullptr) {
+ continue;
+ }
+
+ QScopedPointer<AbstractMetaField> f(field->copy());
+ f->setEnclosingClass(subclass);
+ AbstractMetaType *fieldType = inheritTemplateType(templateTypes, field->type());
+ if (!fieldType)
+ continue;
+ f->replaceType(fieldType);
+ subclass->addField(f.take());
}
subclass->setTemplateBaseClass(templateClass);
@@ -2878,9 +2932,9 @@ void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass,
const QStringList &declarations)
{
for (int i = 0; i < declarations.size(); ++i) {
- QString p = declarations.at(i);
+ const QString &p = declarations.at(i);
- QStringList l = p.split(QLatin1String(" "));
+ QStringList l = p.split(QLatin1Char(' '));
QStringList qualifiedScopeName = currentScope()->qualifiedName();
@@ -2925,8 +2979,8 @@ void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass,
static AbstractMetaFunction* findCopyCtor(AbstractMetaClass* cls)
{
- AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::Invisible);
- functions << cls->queryFunctions(AbstractMetaClass::Visible);
+
+ const auto &functions = cls->functions();
for (AbstractMetaFunction *f : qAsConst(functions)) {
const AbstractMetaFunction::FunctionType t = f->functionType();
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
index a0ca71b94..01806f6b4 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
@@ -38,7 +38,10 @@ QT_FORWARD_DECLARE_CLASS(QIODevice)
class AbstractMetaBuilderPrivate;
class AbstractMetaClass;
+class AbstractMetaType;
class AbstractMetaEnumValue;
+class TypeInfo;
+class TypeEntry;
class AbstractMetaBuilder
{
@@ -61,6 +64,7 @@ public:
AbstractMetaClassList smartPointers() const;
AbstractMetaFunctionList globalFunctions() const;
AbstractMetaEnumList globalEnums() const;
+ AbstractMetaEnum *findEnum(const TypeEntry *typeEntry) const;
/**
* Sorts a list of classes topologically, if an AbstractMetaClass object
@@ -83,6 +87,16 @@ public:
*/
void setGlobalHeader(const QString& globalHeader);
+ static AbstractMetaType *translateType(const TypeInfo &_typei,
+ AbstractMetaClass *currentClass = nullptr,
+ bool resolveType = true,
+ QString *errorMessage = nullptr);
+ static AbstractMetaType *translateType(const QString &t,
+ AbstractMetaClass *currentClass = nullptr,
+ bool resolveType = true,
+ QString *errorMessage = nullptr);
+
+
#ifndef QT_NO_DEBUG_STREAM
void formatDebug(QDebug &d) const;
#endif
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
index 59e3cfc94..ec55d1b47 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
@@ -60,11 +60,12 @@ public:
ScopeModelItem currentScope() const { return m_scopes.constLast(); }
- AbstractMetaClass *argumentToClass(ArgumentModelItem);
+ AbstractMetaClass *argumentToClass(const ArgumentModelItem &);
void addAbstractMetaClass(AbstractMetaClass *cls);
AbstractMetaClass *traverseTypeDef(const FileModelItem &dom,
const TypeDefModelItem &typeDef);
+ void traverseTypesystemTypedefs();
AbstractMetaClass *traverseClass(const FileModelItem &dom,
const ClassModelItem &item);
AbstractMetaClass *currentTraversedClass(ScopeModelItem item);
@@ -74,9 +75,9 @@ public:
bool setupInheritance(AbstractMetaClass *metaClass);
AbstractMetaClass *traverseNamespace(const FileModelItem &dom,
const NamespaceModelItem &item);
- AbstractMetaEnum *traverseEnum(EnumModelItem item, AbstractMetaClass *enclosing,
+ AbstractMetaEnum *traverseEnum(const EnumModelItem &item, AbstractMetaClass *enclosing,
const QSet<QString> &enumsDeclarations);
- void traverseEnums(ScopeModelItem item, AbstractMetaClass *parent,
+ void traverseEnums(const ScopeModelItem &item, AbstractMetaClass *parent,
const QStringList &enumsDeclarations);
AbstractMetaFunctionList classFunctionList(const ScopeModelItem &scopeItem,
bool *constructorRejected);
@@ -85,18 +86,18 @@ public:
bool *constructorRejected);
void traverseFunctions(ScopeModelItem item, AbstractMetaClass *parent);
void applyFunctionModifications(AbstractMetaFunction* func);
- void traverseFields(ScopeModelItem item, AbstractMetaClass *parent);
- void traverseStreamOperator(FunctionModelItem functionItem);
- void traverseOperatorFunction(FunctionModelItem item);
+ void traverseFields(const ScopeModelItem &item, AbstractMetaClass *parent);
+ void traverseStreamOperator(const FunctionModelItem &functionItem);
+ void traverseOperatorFunction(const FunctionModelItem &item);
AbstractMetaFunction* traverseFunction(const AddedFunction &addedFunc);
AbstractMetaFunction* traverseFunction(const AddedFunction &addedFunc,
AbstractMetaClass *metaClass);
- AbstractMetaFunction *traverseFunction(FunctionModelItem function);
- AbstractMetaField *traverseField(VariableModelItem field,
+ AbstractMetaFunction *traverseFunction(const FunctionModelItem &function);
+ AbstractMetaField *traverseField(const VariableModelItem &field,
const AbstractMetaClass *cls);
void checkFunctionModifications();
- void registerHashFunction(FunctionModelItem functionItem);
- void registerToStringCapability(FunctionModelItem functionItem);
+ void registerHashFunction(const FunctionModelItem &functionItem);
+ void registerToStringCapability(const FunctionModelItem &functionItem);
/**
* A conversion operator function should not have its owner class as
@@ -118,12 +119,19 @@ public:
void setupFunctionDefaults(AbstractMetaFunction *metaFunction,
AbstractMetaClass *metaClass);
- QString fixDefaultValue(ArgumentModelItem item, AbstractMetaType *type,
+ QString fixDefaultValue(const ArgumentModelItem &item, AbstractMetaType *type,
AbstractMetaFunction *fnc, AbstractMetaClass *,
int argumentIndex);
AbstractMetaType *translateType(const AddedFunction::TypeInfo &typeInfo);
AbstractMetaType *translateType(const TypeInfo &type,
- bool resolveType = true);
+ bool resolveType = true,
+ QString *errorMessage = nullptr);
+ static AbstractMetaType *translateTypeStatic(const TypeInfo &type,
+ AbstractMetaClass *current,
+ AbstractMetaBuilderPrivate *d = nullptr,
+ bool resolveType = true,
+ QString *errorMessageIn = nullptr);
+
qint64 findOutValueFromString(const QString &stringValue, bool &ok);
AbstractMetaClass *findTemplateClass(const QString& name, const AbstractMetaClass *context,
@@ -135,9 +143,8 @@ public:
bool inheritTemplate(AbstractMetaClass *subclass,
const AbstractMetaClass *templateClass,
const TypeInfo &info);
- AbstractMetaType *inheritTemplateType(const QVector<AbstractMetaType *> &templateTypes,
- const AbstractMetaType *metaType,
- bool *ok = Q_NULLPTR);
+ AbstractMetaType *inheritTemplateType(const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaType *metaType);
bool isQObject(const FileModelItem &dom, const QString &qualifiedName);
bool isEnum(const FileModelItem &dom, const QStringList &qualifiedName);
@@ -161,8 +168,6 @@ public:
AbstractMetaFunctionList m_globalFunctions;
AbstractMetaEnumList m_globalEnums;
- QSet<const TypeEntry *> m_usedTypes;
-
typedef QMap<QString, AbstractMetaBuilder::RejectReason> RejectMap;
RejectMap m_rejectedClasses;
@@ -170,11 +175,7 @@ public:
RejectMap m_rejectedFunctions;
RejectMap m_rejectedFields;
- QList<AbstractMetaEnum *> m_enums;
-
- QList<QPair<AbstractMetaArgument *, AbstractMetaFunction *> > m_enumDefaultArguments;
-
- QHash<QString, AbstractMetaEnumValue *> m_enumValues;
+ QHash<const TypeEntry *, AbstractMetaEnum *> m_enums;
AbstractMetaClass *m_currentClass;
QList<ScopeModelItem> m_scopes;
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index 5be7050bf..c65d7e0bd 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -27,10 +27,13 @@
****************************************************************************/
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typedatabase.h"
#include "typesystem.h"
+#include <parser/codemodel.h>
+
#ifndef QT_NO_DEBUG_STREAM
# include <QtCore/QMetaEnum>
# include <QtCore/QMetaObject>
@@ -55,6 +58,16 @@ QDebug operator<<(QDebug d, const AbstractMetaAttributes *aa)
}
#endif // !QT_NO_DEBUG_STREAM
+template <class MetaClass>
+MetaClass *findByName(QVector<MetaClass *> haystack, QStringView needle)
+{
+ for (MetaClass *c : haystack) {
+ if (c->name() == needle)
+ return c;
+ }
+ return nullptr;
+}
+
/*******************************************************************************
* AbstractMetaVariable
*/
@@ -112,8 +125,8 @@ void AbstractMetaAttributes::assignMetaAttributes(const AbstractMetaAttributes &
AbstractMetaType::AbstractMetaType() :
m_constant(false),
+ m_volatile(false),
m_cppInstantiation(true),
- m_indirections(0),
m_reserved(0)
{
}
@@ -155,8 +168,9 @@ AbstractMetaType *AbstractMetaType::copy() const
cpy->setTypeUsagePattern(typeUsagePattern());
cpy->setConstant(isConstant());
+ cpy->setVolatile(isVolatile());
cpy->setReferenceType(referenceType());
- cpy->setIndirections(indirections());
+ cpy->setIndirectionsV(indirectionsV());
cpy->setInstantiations(instantiations());
cpy->setArrayElementCount(arrayElementCount());
cpy->setOriginalTypeDescription(originalTypeDescription());
@@ -278,6 +292,26 @@ bool AbstractMetaType::hasTemplateChildren() const
return false;
}
+bool AbstractMetaType::equals(const AbstractMetaType &rhs) const
+{
+ if (m_typeEntry != rhs.m_typeEntry || m_constant != rhs.m_constant
+ || m_referenceType != rhs.m_referenceType
+ || m_indirections != rhs.m_indirections
+ || m_instantiations.size() != rhs.m_instantiations.size()
+ || m_arrayElementCount != rhs.m_arrayElementCount) {
+ return false;
+ }
+ if ((m_arrayElementType != nullptr) != (rhs.m_arrayElementType != nullptr)
+ || (m_arrayElementType != nullptr && !m_arrayElementType->equals(*rhs.m_arrayElementType))) {
+ return false;
+ }
+ for (int i = 0, size = m_instantiations.size(); i < size; ++i) {
+ if (!m_instantiations.at(i)->equals(*rhs.m_instantiations.at(i)))
+ return false;
+ }
+ return true;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const AbstractMetaType *at)
{
@@ -291,16 +325,32 @@ QDebug operator<<(QDebug d, const AbstractMetaType *at)
d << ", typeEntry=" << at->typeEntry() << ", signature=\""
<< at->cppSignature() << "\", pattern="
<< at->typeUsagePattern();
- if (at->indirections())
- d << ", indirections=" << at->indirections();
+ const auto indirections = at->indirectionsV();
+ if (!indirections.isEmpty()) {
+ d << ", indirections=";
+ for (auto i : indirections)
+ d << ' ' << TypeInfo::indirectionKeyword(i);
+ }
if (at->referenceType())
d << ", reftype=" << at->referenceType();
if (at->isConstant())
d << ", [const]";
+ if (at->isVolatile())
+ d << ", [volatile]";
if (at->isArray()) {
d << ", array of \"" << at->arrayElementType()->cppSignature()
<< "\", arrayElementCount=" << at->arrayElementCount();
}
+ const auto &instantiations = at->instantiations();
+ if (const int instantiationsSize = instantiations.size()) {
+ d << ", instantiations[" << instantiationsSize << "]=<";
+ for (int i = 0; i < instantiationsSize; ++i) {
+ if (i)
+ d << ", ";
+ d << instantiations.at(i);
+ }
+ }
+ d << '>';
}
} else {
d << '0';
@@ -357,7 +407,8 @@ AbstractMetaFunction::AbstractMetaFunction()
m_userAdded(false),
m_explicit(false),
m_pointerOperator(false),
- m_isCallOperator(false)
+ m_isCallOperator(false),
+ m_generateExceptionHandling(false)
{
}
@@ -475,6 +526,8 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const
if (type())
cpy->setType(type()->copy());
cpy->setConstant(isConstant());
+ cpy->setExceptionSpecification(m_exceptionSpecification);
+ cpy->setGenerateExceptionHandling(m_generateExceptionHandling);
for (AbstractMetaArgument *arg : m_arguments)
cpy->addArgument(arg->copy());
@@ -504,18 +557,17 @@ QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStrin
if (arguments.size() == resolvedArguments.size()) {
QString signature = name() + QLatin1Char('(') + resolvedArguments.join(QLatin1Char(',')) + QLatin1Char(')');
return QStringList(TypeDatabase::normalizedSignature(signature));
- } else {
- QStringList returned;
-
- AbstractMetaArgument *argument = arguments.at(resolvedArguments.size());
- QStringList minimalTypeSignature = argument->type()->minimalSignature().split(QLatin1String("::"));
- for (int i = 0; i < minimalTypeSignature.size(); ++i) {
- returned += introspectionCompatibleSignatures(QStringList(resolvedArguments)
- << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join(QLatin1String("::")));
- }
+ }
+ QStringList returned;
- return returned;
+ AbstractMetaArgument *argument = arguments.at(resolvedArguments.size());
+ QStringList minimalTypeSignature = argument->type()->minimalSignature().split(QLatin1String("::"));
+ for (int i = 0; i < minimalTypeSignature.size(); ++i) {
+ returned += introspectionCompatibleSignatures(QStringList(resolvedArguments)
+ << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join(QLatin1String("::")));
}
+
+ return returned;
}
QString AbstractMetaFunction::signature() const
@@ -674,38 +726,54 @@ bool AbstractMetaFunction::argumentRemoved(int key) const
return false;
}
-bool AbstractMetaFunction::isVirtualSlot() const
+bool AbstractMetaFunction::isDeprecated() const
{
const FunctionModificationList &modifications = this->modifications(declaringClass());
for (const FunctionModification &modification : modifications) {
- if (modification.isVirtualSlot())
+ if (modification.isDeprecated())
return true;
}
-
return false;
}
-bool AbstractMetaFunction::isDeprecated() const
+// 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
{
- const FunctionModificationList &modifications = this->modifications(declaringClass());
- for (const FunctionModification &modification : modifications) {
- if (modification.isDeprecated())
- return true;
- }
- return false;
+ // Disallow for simple getter functions.
+ const bool maybeGetter = m_constant != 0 && m_type != nullptr
+ && m_arguments.isEmpty();
+ return !maybeGetter;
}
bool AbstractMetaFunction::allowThread() const
{
- const FunctionModificationList &modifications = this->modifications(declaringClass());
- for (const FunctionModification &modification : modifications) {
- if (modification.allowThread())
- return true;
+ using AllowThread = TypeSystem::AllowThread;
+
+ if (m_cachedAllowThread < 0) {
+ AllowThread allowThread = AllowThread::Auto;
+ // Find a modification that specifies allowThread
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ if (modification.allowThread() != AllowThread::Unspecified) {
+ allowThread = modification.allowThread();
+ break;
+ }
+ }
+
+ m_cachedAllowThread = allowThread == AllowThread::Allow
+ || (allowThread == AllowThread::Auto && autoDetectAllowThread()) ? 1 : 0;
+
+ if (m_cachedAllowThread == 0)
+ qCDebug(lcShiboken).noquote() << msgDisallowThread(this);
}
- return false;
+ return m_cachedAllowThread > 0;
}
-
TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const
{
const FunctionModificationList &modifications = this->modifications(cls);
@@ -751,6 +819,18 @@ QString AbstractMetaFunction::typeReplaced(int key) const
return QString();
}
+bool AbstractMetaFunction::isModifiedToArray(int argumentIndex) const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == argumentIndex && argumentModification.array != 0)
+ return true;
+ }
+ }
+ return false;
+}
+
QString AbstractMetaFunction::minimalSignature() const
{
if (!m_cachedMinimalSignature.isEmpty())
@@ -809,8 +889,9 @@ FunctionModificationList AbstractMetaFunction::modifications(const AbstractMetaC
while (implementor) {
mods += implementor->typeEntry()->functionModifications(minimalSignature());
if ((implementor == implementor->baseClass()) ||
- (implementor == implementingClass() && (mods.size() > 0)))
+ (implementor == implementingClass() && !mods.isEmpty())) {
break;
+ }
const AbstractMetaClassList &interfaces = implementor->interfaces();
for (const AbstractMetaClass *interface : interfaces)
mods += this->modifications(interface);
@@ -873,14 +954,24 @@ bool AbstractMetaFunction::hasSignatureModifications() const
return false;
}
-bool AbstractMetaFunction::isConversionOperator(QString funcName)
+bool AbstractMetaFunction::isConversionOperator(const QString& funcName)
{
static const QRegularExpression opRegEx(QStringLiteral("^operator(?:\\s+(?:const|volatile))?\\s+(\\w+\\s*)&?$"));
Q_ASSERT(opRegEx.isValid());
return opRegEx.match(funcName).hasMatch();
}
-bool AbstractMetaFunction::isOperatorOverload(QString funcName)
+ExceptionSpecification AbstractMetaFunction::exceptionSpecification() const
+{
+ return m_exceptionSpecification;
+}
+
+void AbstractMetaFunction::setExceptionSpecification(ExceptionSpecification e)
+{
+ m_exceptionSpecification = e;
+}
+
+bool AbstractMetaFunction::isOperatorOverload(const QString& funcName)
{
if (isConversionOperator(funcName))
return true;
@@ -1038,6 +1129,13 @@ bool function_sorter(AbstractMetaFunction *a, AbstractMetaFunction *b)
return a->signature() < b->signature();
}
+AbstractMetaFunction *
+AbstractMetaFunction::find(const AbstractMetaFunctionList &haystack,
+ const QString &needle)
+{
+ return findByName(haystack, needle);
+}
+
#ifndef QT_NO_DEBUG_STREAM
static inline void formatMetaFunctionBrief(QDebug &d, const AbstractMetaFunction *af)
{
@@ -1046,7 +1144,20 @@ static inline void formatMetaFunctionBrief(QDebug &d, const AbstractMetaFunction
void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const
{
- d << m_functionType << ' ' << m_type << ' ' << m_name << '(';
+ d << m_functionType << ' ' << m_type << ' ' << m_name;
+ switch (m_exceptionSpecification) {
+ case ExceptionSpecification::Unknown:
+ break;
+ case ExceptionSpecification::NoExcept:
+ d << " noexcept";
+ break;
+ case ExceptionSpecification::Throws:
+ d << " throw(...)";
+ break;
+ }
+ if (m_generateExceptionHandling)
+ d << "[generate-exception-handling]";
+ d << '(';
for (int i = 0, count = m_arguments.size(); i < count; ++i) {
if (i)
d << ", ";
@@ -1106,7 +1217,6 @@ AbstractMetaClass::AbstractMetaClass()
: m_hasVirtuals(false),
m_isPolymorphic(false),
m_hasNonpublic(false),
- m_hasVirtualSlots(false),
m_hasNonPrivateConstructor(false),
m_hasPrivateConstructor(false),
m_functionsFixed(false),
@@ -1330,11 +1440,8 @@ void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions)
for (AbstractMetaFunction *f : qAsConst(m_functions)) {
f->setOwnerClass(this);
-
- m_hasVirtualSlots = m_hasVirtualSlots || f->isVirtualSlot();
- m_hasVirtuals = m_hasVirtuals || f->isVirtualSlot() || hasVirtualDestructor();
- m_isPolymorphic = m_isPolymorphic || m_hasVirtuals;
- m_hasNonpublic = m_hasNonpublic || !f->isPublic();
+ if (!f->isPublic())
+ m_hasNonpublic = true;
}
}
@@ -1368,8 +1475,7 @@ void AbstractMetaClass::addFunction(AbstractMetaFunction *function)
else
Q_ASSERT(false); //memory leak
- m_hasVirtualSlots |= function->isVirtualSlot();
- m_hasVirtuals |= function->isVirtual() || function->isVirtualSlot() || hasVirtualDestructor();
+ m_hasVirtuals |= function->isVirtual() || hasVirtualDestructor();
m_isPolymorphic |= m_hasVirtuals;
m_hasNonpublic |= !function->isPublic();
}
@@ -1432,11 +1538,7 @@ bool AbstractMetaClass::hasFunction(const QString &str) const
const AbstractMetaFunction* AbstractMetaClass::findFunction(const QString& functionName) const
{
- for (const AbstractMetaFunction *f : m_functions) {
- if (f->name() == functionName)
- return f;
- }
- return 0;
+ return AbstractMetaFunction::find(m_functions, functionName);
}
bool AbstractMetaClass::hasProtectedFunctions() const
@@ -1511,6 +1613,13 @@ void AbstractMetaClass::setTemplateBaseClassInstantiations(AbstractMetaTypeList&
metaClassBaseTemplateInstantiations()->insert(this, instantiations);
}
+// Does any of the base classes require deletion in the main thread?
+bool AbstractMetaClass::deleteInMainThread() const
+{
+ return typeEntry()->deleteInMainThread()
+ || (m_baseClass && m_baseClass->deleteInMainThread());
+}
+
static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func)
{
for (const AbstractMetaFunction *f : l) {
@@ -1537,6 +1646,11 @@ AbstractMetaField *AbstractMetaField::copy() const
return returned;
}
+AbstractMetaField *AbstractMetaField::find(const AbstractMetaFieldList &haystack,
+ const QString &needle)
+{
+ return findByName(haystack, needle);
+}
/*******************************************************************************
* Indicates that this field has a modification that removes it
*/
@@ -1723,27 +1837,22 @@ QDebug operator<<(QDebug d, const AbstractMetaEnum *ae)
bool AbstractMetaClass::hasConstructors() const
{
- return queryFunctions(Constructors).size();
+ return AbstractMetaClass::queryFirstFunction(m_functions, Constructors) != nullptr;
}
-bool AbstractMetaClass::hasCopyConstructor() const
+const AbstractMetaFunction *AbstractMetaClass::copyConstructor() const
{
- const AbstractMetaFunctionList &ctors = queryFunctions(Constructors);
- for (const AbstractMetaFunction* ctor : ctors) {
- if (ctor->functionType() == AbstractMetaFunction::CopyConstructorFunction)
- return true;
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->functionType() == AbstractMetaFunction::CopyConstructorFunction)
+ return f;
}
- return false;
+ return nullptr;
}
bool AbstractMetaClass::hasPrivateCopyConstructor() const
{
- const AbstractMetaFunctionList &ctors = queryFunctions(Constructors);
- for (const AbstractMetaFunction *ctor : ctors) {
- if (ctor->functionType() == AbstractMetaFunction::CopyConstructorFunction && ctor->isPrivate())
- return true;
- }
- return false;
+ const AbstractMetaFunction *copyCt = copyConstructor();
+ return copyCt && copyCt->isPrivate();
}
void AbstractMetaClass::addDefaultConstructor()
@@ -1801,85 +1910,122 @@ bool AbstractMetaClass::hasFunction(const AbstractMetaFunction *f) const
return functions_contains(m_functions, f);
}
+bool AbstractMetaClass::generateExceptionHandling() const
+{
+ return queryFirstFunction(m_functions, AbstractMetaClass::Visible
+ | AbstractMetaClass::GenerateExceptionHandling) != nullptr;
+}
/* Goes through the list of functions and returns a list of all
functions matching all of the criteria in \a query.
*/
-AbstractMetaFunctionList AbstractMetaClass::queryFunctions(FunctionQueryOptions query) const
+bool AbstractMetaClass::queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query)
{
- AbstractMetaFunctionList functions;
-
- for (AbstractMetaFunction *f : m_functions) {
- if ((query & NotRemovedFromTargetLang) && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode))
- continue;
+ if ((query & NotRemovedFromTargetLang)
+ && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode)) {
+ return false;
+ }
- if ((query & NotRemovedFromTargetLang) && f->isVirtual() && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode))
- continue;
+ if ((query & NotRemovedFromTargetLang) && f->isVirtual()
+ && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode)) {
+ return false;
+ }
- if ((query & Visible) && f->isPrivate())
- continue;
+ if ((query & Visible) && f->isPrivate())
+ return false;
- if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang())
- continue;
+ if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang())
+ return false;
- if ((query & Invisible) && !f->isPrivate())
- continue;
+ if ((query & Invisible) && !f->isPrivate())
+ return false;
- if ((query & Empty) && !f->isEmptyFunction())
- continue;
+ if ((query & Empty) && !f->isEmptyFunction())
+ return false;
- if ((query & WasPublic) && !f->wasPublic())
- continue;
+ if ((query & WasPublic) && !f->wasPublic())
+ return false;
- if ((query & ClassImplements) && f->ownerClass() != f->implementingClass())
- continue;
+ if ((query & ClassImplements) && f->ownerClass() != f->implementingClass())
+ return false;
- if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang())
- continue;
+ if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang())
+ return false;
- if ((query & VirtualInCppFunctions) && !f->isVirtual())
- continue;
+ if ((query & VirtualInCppFunctions) && !f->isVirtual())
+ return false;
- if ((query & Signals) && (!f->isSignal()))
- continue;
+ if ((query & Signals) && (!f->isSignal()))
+ return false;
- if ((query & Constructors) && (!f->isConstructor() || f->ownerClass() != f->implementingClass()))
- continue;
+ if ((query & Constructors) && (!f->isConstructor() || f->ownerClass() != f->implementingClass()))
+ return false;
- if (!(query & Constructors) && f->isConstructor())
- continue;
+ if (!(query & Constructors) && f->isConstructor())
+ return false;
- // Destructors are never included in the functions of a class currently
- /*
+ // 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) {
- continue;
+ return false;
}*/
- if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal()))
- continue;
+ if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal()))
+ return false;
- if ((query & NonStaticFunctions) && (f->isStatic()))
- continue;
+ if ((query & NonStaticFunctions) && (f->isStatic()))
+ return false;
- if ((query & NormalFunctions) && (f->isSignal()))
- continue;
+ if ((query & NormalFunctions) && (f->isSignal()))
+ return false;
- if ((query & OperatorOverloads) && !f->isOperatorOverload())
- continue;
+ if ((query & OperatorOverloads) && !f->isOperatorOverload())
+ return false;
+
+ if ((query & GenerateExceptionHandling) && !f->generateExceptionHandling())
+ return false;
+
+ return true;
+}
- functions << f;
+AbstractMetaFunctionList AbstractMetaClass::queryFunctionList(const AbstractMetaFunctionList &list,
+ FunctionQueryOptions query)
+{
+ AbstractMetaFunctionList result;
+ for (AbstractMetaFunction *f : list) {
+ if (queryFunction(f, query))
+ result.append(f);
+ }
+ return result;
+}
+
+const AbstractMetaFunction *AbstractMetaClass::queryFirstFunction(const AbstractMetaFunctionList &list,
+ FunctionQueryOptions query)
+{
+ AbstractMetaFunctionList result;
+ for (AbstractMetaFunction *f : list) {
+ if (queryFunction(f, query))
+ return f;
}
+ return nullptr;
+}
- return functions;
+AbstractMetaFunctionList AbstractMetaClass::queryFunctions(FunctionQueryOptions query) const
+{
+ return AbstractMetaClass::queryFunctionList(m_functions, query);
}
bool AbstractMetaClass::hasSignals() const
{
- return cppSignalFunctions().size() > 0;
+ return queryFirstFunction(m_functions, Signals | Visible | NotRemovedFromTargetLang) != nullptr;
}
+AbstractMetaFunctionList AbstractMetaClass::cppSignalFunctions() const
+{
+ return queryFunctions(Signals | Visible | NotRemovedFromTargetLang);
+}
/**
* Adds the specified interface to this class by adding all the
@@ -1932,13 +2078,15 @@ void AbstractMetaClass::setInterfaces(const AbstractMetaClassList &interfaces)
}
}
+AbstractMetaField *AbstractMetaClass::findField(const QString &name) const
+{
+ return AbstractMetaField::find(m_fields, name);
+}
AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName)
{
- for (AbstractMetaEnum *e : qAsConst(m_enums)) {
- if (e->name() == enumName)
- return e;
- }
+ if (AbstractMetaEnum *e = findByName(m_enums, enumName))
+ return e;
if (typeEntry()->designatedInterface())
return extractInterface()->findEnum(enumName);
@@ -2002,8 +2150,8 @@ void AbstractMetaClass::fixFunctions()
{
if (m_functionsFixed)
return;
- else
- m_functionsFixed = true;
+
+ m_functionsFixed = true;
AbstractMetaClass *superClass = baseClass();
AbstractMetaFunctionList funcs = functions();
@@ -2046,8 +2194,7 @@ void AbstractMetaClass::fixFunctions()
// 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 = (sf->isNormal() || sf->isSignal() || sf->isEmptyFunction());
- for (int fi = 0; fi < funcs.size(); ++fi) {
- AbstractMetaFunction *f = funcs.at(fi);
+ for (AbstractMetaFunction *f : funcs) {
if (f->isRemovedFromAllLanguages(f->implementingClass()))
continue;
@@ -2114,7 +2261,8 @@ void AbstractMetaClass::fixFunctions()
if (mod.isNonFinal()) {
hasNonFinalModifier = true;
break;
- } else if (mod.isPrivate()) {
+ }
+ if (mod.isPrivate()) {
isBaseImplPrivate = true;
break;
}
@@ -2222,6 +2370,8 @@ QString AbstractMetaType::formatSignature(bool minimal) const
QString result;
if (isConstant())
result += QLatin1String("const ");
+ if (isVolatile())
+ result += QLatin1String("volatile ");
if (isArray()) {
// Build nested array dimensions a[2][3] in correct order
result += m_arrayElementType->minimalSignature();
@@ -2245,10 +2395,10 @@ QString AbstractMetaType::formatSignature(bool minimal) const
result += QLatin1String(" >");
}
- if (!minimal && (m_indirections != 0 || m_referenceType != NoReference))
+ if (!minimal && (!m_indirections.isEmpty() || m_referenceType != NoReference))
result += QLatin1Char(' ');
- if (m_indirections)
- result += QString(m_indirections, QLatin1Char('*'));
+ for (Indirection i : m_indirections)
+ result += TypeInfo::indirectionKeyword(i);
switch (referenceType()) {
case NoReference:
break;
@@ -2376,6 +2526,8 @@ QDebug operator<<(QDebug d, const AbstractMetaClass *ac)
d << " [final]";
if (ac->m_baseClass)
d << ", inherits \"" << ac->m_baseClass->name() << '"';
+ if (ac->m_templateBaseClass)
+ d << ", inherits template \"" << ac->m_templateBaseClass->name() << '"';
const AbstractMetaEnumList &enums = ac->enums();
if (!enums.isEmpty())
d << ", enums[" << enums.size() << "]=" << enums;
@@ -2406,6 +2558,18 @@ QDebug operator<<(QDebug d, const AbstractMetaClass *ac)
}
d << ')';
}
+ const auto &templateArguments = ac->templateArguments();
+ if (const int count = templateArguments.size()) {
+ d << ", templateArguments=[" << count << "](";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ d << ", ";
+ d << templateArguments.at(i);
+ }
+ d << ')';
+ }
+
+
} else {
d << '0';
}
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index d1a0fbf88..aaefa32d5 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -288,6 +288,7 @@ class AbstractMetaType
{
Q_GADGET
public:
+ typedef QVector<Indirection> Indirections;
enum TypeUsagePattern {
InvalidPattern,
@@ -436,6 +437,9 @@ public:
m_constant = constant;
}
+ bool isVolatile() const { return m_volatile; }
+ void setVolatile(bool v) { m_volatile = v; }
+
bool isConstRef() const;
ReferenceType referenceType() const { return m_referenceType; }
@@ -443,16 +447,21 @@ public:
int actualIndirections() const
{
- return m_indirections + (m_referenceType == LValueReference ? 1 : 0);
- }
- int indirections() const
- {
- return m_indirections;
+ return m_indirections.size() + (m_referenceType == LValueReference ? 1 : 0);
}
+
+ Indirections indirectionsV() const { return m_indirections; }
+ void setIndirectionsV(const Indirections &i) { m_indirections = i; }
+ void clearIndirections() { m_indirections.clear(); }
+
+ // "Legacy"?
+ int indirections() const { return m_indirections.size(); }
void setIndirections(int indirections)
{
- m_indirections = indirections;
+ m_indirections = Indirections(indirections, Indirection::Pointer);
}
+ void addIndirection(Indirection i = Indirection::Pointer)
+ { m_indirections.append(i); }
void setArrayElementCount(int n)
{
@@ -527,6 +536,8 @@ public:
bool hasTemplateChildren() const;
+ bool equals(const AbstractMetaType &rhs) const;
+
private:
TypeUsagePattern determineUsagePattern() const;
QString formatSignature(bool minimal) const;
@@ -541,18 +552,25 @@ private:
int m_arrayElementCount = -1;
const AbstractMetaType *m_arrayElementType = nullptr;
const AbstractMetaType *m_originalTemplateType = nullptr;
+ Indirections m_indirections;
TypeUsagePattern m_pattern = InvalidPattern;
uint m_constant : 1;
+ uint m_volatile : 1;
uint m_cppInstantiation : 1;
- int m_indirections : 4;
- uint m_reserved : 26; // unused
+ uint m_reserved : 29; // unused
+
ReferenceType m_referenceType = NoReference;
AbstractMetaTypeList m_children;
Q_DISABLE_COPY(AbstractMetaType)
};
+inline bool operator==(const AbstractMetaType &t1, const AbstractMetaType &t2)
+{ return t1.equals(t2); }
+inline bool operator!=(const AbstractMetaType &t1, const AbstractMetaType &t2)
+{ return !t1.equals(t2); }
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const AbstractMetaType *at);
#endif
@@ -650,6 +668,13 @@ public:
m_originalExpression = expr;
}
+ bool hasDefaultValueExpression() const
+ { return !m_originalExpression.isEmpty() || !m_expression.isEmpty(); }
+ bool hasUnmodifiedDefaultValueExpression() const
+ { return !m_originalExpression.isEmpty() && m_originalExpression == m_expression; }
+ bool hasModifiedDefaultValueExpression() const
+ { return !m_expression.isEmpty() && m_originalExpression != m_expression; }
+
QString toString() const
{
return type()->name() + QLatin1Char(' ') + AbstractMetaVariable::name() +
@@ -709,6 +734,9 @@ public:
AbstractMetaField *copy() const;
+ static AbstractMetaField *
+ find(const AbstractMetaFieldList &haystack, const QString &needle);
+
private:
mutable AbstractMetaFunction *m_getter = nullptr;
mutable AbstractMetaFunction *m_setter = nullptr;
@@ -816,13 +844,20 @@ public:
return m_explicit;
}
- static bool isConversionOperator(QString funcName);
+ static bool isConversionOperator(const QString& funcName);
+
+ ExceptionSpecification exceptionSpecification() const;
+ void setExceptionSpecification(ExceptionSpecification e);
+
+ bool generateExceptionHandling() const { return m_generateExceptionHandling; }
+ void setGenerateExceptionHandling(bool g) { m_generateExceptionHandling = g; }
+
bool isConversionOperator() const
{
return isConversionOperator(originalName());
}
- static bool isOperatorOverload(QString funcName);
+ static bool isOperatorOverload(const QString& funcName);
bool isOperatorOverload() const
{
return isOperatorOverload(originalName());
@@ -1000,9 +1035,8 @@ public:
// Returns the ownership rules for the given argument in the given context
TypeSystem::Ownership ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int idx) const;
- bool isVirtualSlot() const;
-
QString typeReplaced(int argument_index) const;
+ bool isModifiedToArray(int argumentIndex) const;
bool isRemovedFromAllLanguages(const AbstractMetaClass *) const;
bool isRemovedFrom(const AbstractMetaClass *, TypeSystem::Language language) const;
bool argumentRemoved(int) const;
@@ -1057,11 +1091,16 @@ public:
bool isCallOperator() const;
+ static AbstractMetaFunction *
+ find(const AbstractMetaFunctionList &haystack, const QString &needle);
+
#ifndef QT_NO_DEBUG_STREAM
void formatDebugVerbose(QDebug &d) const;
#endif
private:
+ bool autoDetectAllowThread() const;
+
QString m_name;
QString m_originalName;
mutable QString m_cachedMinimalSignature;
@@ -1082,6 +1121,9 @@ private:
uint m_explicit : 1;
uint m_pointerOperator : 1;
uint m_isCallOperator : 1;
+ uint m_generateExceptionHandling: 1;
+ mutable int m_cachedAllowThread = -1;
+ ExceptionSpecification m_exceptionSpecification = ExceptionSpecification::Unknown;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::CompareResult)
@@ -1246,7 +1288,8 @@ public:
VirtualInCppFunctions = 0x0020000, // Only functions that are virtual in C++
VirtualInTargetLangFunctions = 0x0080000, // Only functions which are virtual in TargetLang
NotRemovedFromTargetLang = 0x0400000, // Only functions that have not been removed from TargetLang
- OperatorOverloads = 0x2000000 // Only functions that are operator overloads
+ OperatorOverloads = 0x2000000, // Only functions that are operator overloads
+ GenerateExceptionHandling = 0x4000000
};
Q_DECLARE_FLAGS(FunctionQueryOptions, FunctionQueryOption)
Q_FLAG(FunctionQueryOption)
@@ -1286,7 +1329,8 @@ public:
bool hasSignal(const AbstractMetaFunction *f) const;
bool hasConstructors() const;
- bool hasCopyConstructor() const;
+ const AbstractMetaFunction *copyConstructor() const;
+ bool hasCopyConstructor() const { return copyConstructor() != nullptr; }
bool hasPrivateCopyConstructor() const;
void addDefaultConstructor();
@@ -1347,10 +1391,18 @@ public:
return (hasNonPrivateConstructor() || !hasPrivateConstructor()) && !hasPrivateDestructor();
}
+ bool generateExceptionHandling() const;
+
AbstractMetaFunctionList queryFunctionsByName(const QString &name) const;
+ static bool queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query);
+ static AbstractMetaFunctionList queryFunctionList(const AbstractMetaFunctionList &list,
+ FunctionQueryOptions query);
+ static const AbstractMetaFunction *queryFirstFunction(const AbstractMetaFunctionList &list,
+ FunctionQueryOptions query);
+
AbstractMetaFunctionList queryFunctions(FunctionQueryOptions query) const;
AbstractMetaFunctionList functionsInTargetLang() const;
- inline AbstractMetaFunctionList cppSignalFunctions() const;
+ AbstractMetaFunctionList cppSignalFunctions() const;
AbstractMetaFunctionList implicitConversions() const;
/**
@@ -1383,6 +1435,8 @@ public:
m_fields << field;
}
+ AbstractMetaField *findField(const QString &name) const;
+
AbstractMetaEnumList enums() const
{
return m_enums;
@@ -1478,11 +1532,6 @@ public:
m_forceShellClass = on;
}
- bool hasVirtualSlots() const
- {
- return m_hasVirtualSlots;
- }
-
/**
* Says if the class that declares or inherits a virtual function.
* \return true if the class implements or inherits any virtual methods
@@ -1650,6 +1699,8 @@ public:
return m_hasToStringCapability;
}
+ bool deleteInMainThread() const;
+
static AbstractMetaClass *findClass(const AbstractMetaClassList &classes,
const QString &name);
static AbstractMetaClass *findClass(const AbstractMetaClassList &classes,
@@ -1666,7 +1717,6 @@ private:
uint m_hasVirtuals : 1;
uint m_isPolymorphic : 1;
uint m_hasNonpublic : 1;
- uint m_hasVirtualSlots : 1;
uint m_hasNonPrivateConstructor : 1;
uint m_hasPrivateConstructor : 1;
uint m_functionsFixed : 1;
@@ -1784,11 +1834,4 @@ private:
int m_index = -1;
};
-inline AbstractMetaFunctionList AbstractMetaClass::cppSignalFunctions() const
-{
- return queryFunctions(Signals
- | Visible
- | NotRemovedFromTargetLang);
-}
-
#endif // ABSTRACTMETALANG_H
diff --git a/sources/shiboken2/ApiExtractor/apiextractor.cpp b/sources/shiboken2/ApiExtractor/apiextractor.cpp
index 171011cd4..775485c81 100644
--- a/sources/shiboken2/ApiExtractor/apiextractor.cpp
+++ b/sources/shiboken2/ApiExtractor/apiextractor.cpp
@@ -177,41 +177,9 @@ static const AbstractMetaEnum* findEnumOnClasses(AbstractMetaClassList metaClass
return result;
}
-const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const
-{
- if (!typeEntry)
- return 0;
- const AbstractMetaEnumList &globalEnums = m_builder->globalEnums();
- for (AbstractMetaEnum* metaEnum : globalEnums) {
- if (metaEnum->typeEntry() == typeEntry)
- return metaEnum;
- }
- return findEnumOnClasses(m_builder->classes(), typeEntry);
-}
-
const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const TypeEntry* typeEntry) const
{
- if (!typeEntry)
- return 0;
- if (typeEntry->isFlags())
- return findAbstractMetaEnum(reinterpret_cast<const FlagsTypeEntry*>(typeEntry));
- if (typeEntry->isEnum())
- return findAbstractMetaEnum(reinterpret_cast<const EnumTypeEntry*>(typeEntry));
- return 0;
-}
-
-const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const
-{
- if (!typeEntry)
- return 0;
- return findAbstractMetaEnum(typeEntry->originator());
-}
-
-const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const AbstractMetaType* metaType) const
-{
- if (!metaType)
- return 0;
- return findAbstractMetaEnum(metaType->typeEntry());
+ return m_builder->findEnum(typeEntry);
}
int ApiExtractor::classCount() const
diff --git a/sources/shiboken2/ApiExtractor/apiextractor.h b/sources/shiboken2/ApiExtractor/apiextractor.h
index 674e5a742..ab520c9de 100644
--- a/sources/shiboken2/ApiExtractor/apiextractor.h
+++ b/sources/shiboken2/ApiExtractor/apiextractor.h
@@ -87,10 +87,7 @@ public:
PrimitiveTypeEntryList primitiveTypes() const;
ContainerTypeEntryList containerTypes() const;
- const AbstractMetaEnum* findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const;
const AbstractMetaEnum* findAbstractMetaEnum(const TypeEntry* typeEntry) const;
- const AbstractMetaEnum* findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const;
- const AbstractMetaEnum* findAbstractMetaEnum(const AbstractMetaType* metaType) const;
int classCount() const;
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
index af7f96068..40f915028 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
@@ -146,6 +146,7 @@ class BuilderPrivate {
public:
typedef QHash<CXCursor, ClassModelItem> CursorClassHash;
typedef QHash<CXCursor, TypeDefModelItem> CursorTypedefHash;
+ typedef QHash<CXType, TypeInfo> TypeInfoHash;
explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel)
{
@@ -180,9 +181,16 @@ public:
CodeModel::FunctionType t = CodeModel::Normal) const;
FunctionModelItem createMemberFunction(const CXCursor &cursor) const;
void qualifyConstructor(const CXCursor &cursor);
+ TypeInfo createTypeInfoHelper(const CXType &type) const; // uncashed
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 TypeInfo &ti);
TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const;
TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const;
@@ -205,6 +213,8 @@ public:
CursorClassHash m_cursorClassHash;
CursorTypedefHash m_cursorTypedefHash;
+ mutable TypeInfoHash m_typeInfoHash; // Cache type information
+
ClassModelItem m_currentClass;
EnumModelItem m_currentEnum;
FunctionModelItem m_currentFunction;
@@ -247,6 +257,25 @@ bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t)
return true;
}
+static inline ExceptionSpecification exceptionSpecificationFromClang(int ce)
+{
+ switch (ce) {
+ case CXCursor_ExceptionSpecificationKind_BasicNoexcept:
+ case CXCursor_ExceptionSpecificationKind_ComputedNoexcept:
+ case CXCursor_ExceptionSpecificationKind_DynamicNone: // throw()
+ 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) const
{
@@ -256,10 +285,11 @@ FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor,
name = fixTypeName(name);
FunctionModelItem result(new _FunctionModelItem(m_model, name));
setFileName(cursor, result.data());
- result->setType(createTypeInfo(clang_getCursorResultType(cursor)));
+ result->setType(createTypeInfoHelper(clang_getCursorResultType(cursor)));
result->setFunctionType(t);
result->setScope(m_scope);
result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static);
+ result->setExceptionSpecification(exceptionSpecificationFromClang(clang_getCursorExceptionSpecificationType(cursor)));
switch (clang_getCursorAvailability(cursor)) {
case CXAvailability_Available:
break;
@@ -335,7 +365,7 @@ TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCurso
TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const
{
TemplateParameterModelItem result = createTemplateParameter(cursor);
- result->setType(createTypeInfo(cursor));
+ result->setType(createTypeInfoHelper(clang_getCursorType(cursor)));
return result;
}
@@ -359,38 +389,6 @@ struct ArrayDimensionResult
int position;
};
-static ArrayDimensionResult arrayDimensions(const QString &typeName)
-{
- ArrayDimensionResult result;
- result.position = typeName.indexOf(QLatin1Char('['));
- for (int openingPos = result.position; openingPos != -1; ) {
- const int closingPos = typeName.indexOf(QLatin1Char(']'), openingPos + 1);
- if (closingPos == -1)
- break;
- result.dimensions.append(typeName.midRef(openingPos + 1, closingPos - openingPos - 1));
- openingPos = typeName.indexOf(QLatin1Char('['), closingPos + 1);
- }
- return result;
-}
-
-// Array helpers: Parse "a[2][4]" into a list of dimensions or "" for none
-static QStringList parseArrayArgs(const CXType &type, QString *typeName)
-{
- const ArrayDimensionResult dimensions = arrayDimensions(*typeName);
- Q_ASSERT(!dimensions.dimensions.isEmpty());
-
- QStringList result;
- // get first dimension from clang, preferably.
- // "a[]" is seen as pointer by Clang, set special indicator ""
- const long long size = clang_getArraySize(type);
- result.append(size >= 0 ? QString::number(size) : QString());
- // Parse out remaining dimensions
- for (int i = 1, count = dimensions.dimensions.size(); i < count; ++i)
- result.append(dimensions.dimensions.at(i).toString());
- typeName->truncate(dimensions.position);
- return result;
-}
-
// Create qualified name "std::list<std::string>" -> ("std", "list<std::string>")
static QStringList qualifiedName(const QString &t)
{
@@ -412,71 +410,143 @@ static QStringList qualifiedName(const QString &t)
return result;
}
-TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const
+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(createTypeInfoHelper(argType));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+static void dummyTemplateArgumentHandler(int, const QStringRef &) {}
+
+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();
+ const QPair<int, int> 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::createTypeInfoHelper(const CXType &type) 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 = createTypeInfo(clang_getResultType(pointeeType));
+ TypeInfo result = createTypeInfoHelper(clang_getResultType(pointeeType));
result.setFunctionPointer(true);
for (int a = 0; a < argCount; ++a)
- result.addArgument(createTypeInfo(clang_getArgType(pointeeType, unsigned(a))));
+ result.addArgument(createTypeInfoHelper(clang_getArgType(pointeeType, unsigned(a))));
return result;
}
}
TypeInfo typeInfo;
- QString typeName = fixTypeName(getTypeName(type));
- int indirections = 0;
- // "int **"
- for ( ; typeName.endsWith(QLatin1Char('*')) ; ++indirections)
- typeName.chop(1);
- typeInfo.setIndirections(indirections);
- // "int &&"
- if (typeName.endsWith(QLatin1String("&&"))) {
- typeName.chop(2);
- typeInfo.setReferenceType(RValueReference);
- } else if (typeName.endsWith(QLatin1Char('&'))) { // "int &"
- typeName.chop(1);
- typeInfo.setReferenceType(LValueReference);
+ 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());
}
- // "int [3], int[]"
- if (type.kind == CXType_ConstantArray || type.kind == CXType_IncompleteArray
- || type.kind == CXType_VariableArray || type.kind == CXType_DependentSizedArray) {
- typeInfo.setArrayElements(parseArrayArgs(type, &typeName));
+ 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);
- bool isConstant = clang_isConstQualifiedType(type) != 0;
- // A "char *const" parameter, is considered to be const-qualified by Clang, but
- // not in the TypeInfo sense (corresponds to "char *" and not "const char *").
- if (type.kind == CXType_Pointer && isConstant && typeName.endsWith(QLatin1String("const"))) {
- typeName.chop(5);
- typeName = typeName.trimmed();
- isConstant = false;
- }
- // Clang has been observed to return false for "const int .."
- if (!isConstant && typeName.startsWith(QLatin1String("const "))) {
- typeName.remove(0, 6);
- isConstant = true;
- }
- typeInfo.setConstant(isConstant);
+ typeInfo.setConstant(clang_isConstQualifiedType(nestedType) != 0);
+ typeInfo.setVolatile(clang_isVolatileQualifiedType(nestedType) != 0);
- // clang_isVolatileQualifiedType() returns true for "volatile int", but not for "volatile int *"
- if (typeName.startsWith(QLatin1String("volatile "))) {
- typeName.remove(0, 9);
- typeInfo.setVolatile(true);
+ QString typeName = getTypeName(nestedType);
+ while (TypeInfo::stripLeadingConst(&typeName)
+ || TypeInfo::stripLeadingVolatile(&typeName)) {
}
- typeName = typeName.trimmed();
+ // Obtain template instantiations if the name has '<' (thus excluding
+ // typedefs like "std::string".
+ if (typeName.contains(QLatin1Char('<')))
+ 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
+{
+ TypeInfoHash::iterator it = m_typeInfoHash.find(type);
+ if (it == m_typeInfoHash.end())
+ it = m_typeInfoHash.insert(type, createTypeInfoHelper(type));
+ return it.value();
+}
+
+void BuilderPrivate::addTypeDef(const CXCursor &cursor, const TypeInfo &ti)
+{
+ TypeDefModelItem item(new _TypeDefModelItem(m_model, getCursorSpelling(cursor)));
+ setFileName(cursor, item.data());
+ item->setType(ti);
+ item->setScope(m_scope);
+ m_scopeStack.back()->addTypeDef(item);
+ m_cursorTypedefHash.insert(cursor, item);
+}
+
// extract an expression from the cursor via source
// CXCursor_EnumConstantDecl, ParmDecl (a = Flag1 | Flag2)
QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor) const
@@ -795,9 +865,8 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
d->m_currentFunction = d->createMemberFunction(cursor);
d->m_scopeStack.back()->addFunction(d->m_currentFunction);
break;
- } else {
- return Skip; // inline member functions outside class
}
+ return Skip; // inline member functions outside class
}
}
Q_FALLTHROUGH(); // fall through to free template function.
@@ -868,17 +937,14 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
}
break;
case CXCursor_TypeAliasDecl:
- case CXCursor_TypeAliasTemplateDecl: // May contain nested CXCursor_TemplateTypeParameter
- return Skip;
- case CXCursor_TypedefDecl: {
- const QString name = getCursorSpelling(cursor);
- TypeDefModelItem item(new _TypeDefModelItem(d->m_model, name));
- setFileName(cursor, item.data());
- item->setType(d->createTypeInfo(clang_getTypedefDeclUnderlyingType(cursor)));
- item->setScope(d->m_scope);
- d->m_scopeStack.back()->addTypeDef(item);
- d->m_cursorTypedefHash.insert(cursor, item);
+ case CXCursor_TypeAliasTemplateDecl: { // May contain nested CXCursor_TemplateTypeParameter
+ const CXType type = clang_getCanonicalType(clang_getCursorType(cursor));
+ if (type.kind > CXType_Unexposed)
+ d->addTypeDef(cursor, d->createTypeInfo(type));
}
+ return Skip;
+ case CXCursor_TypedefDecl:
+ d->addTypeDef(cursor, d->createTypeInfo(clang_getTypedefDeclUnderlyingType(cursor)));
break;
case CXCursor_TypeRef:
if (!d->m_currentFunction.isNull()) {
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp
index ce0b6554d..e116f8b83 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp
@@ -166,7 +166,7 @@ static inline const char **byteArrayListToFlatArgV(const QByteArrayList &bl)
return result;
}
-static QByteArray msgCreateTranslationUnit(const QByteArrayList clangArgs, unsigned flags)
+static QByteArray msgCreateTranslationUnit(const QByteArrayList &clangArgs, unsigned flags)
{
QByteArray result = "clang_parseTranslationUnit2(0x";
result += QByteArray::number(flags, 16);
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
index 2ff18b23b..8bee28cdf 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
@@ -46,6 +46,18 @@ uint qHash(const CXCursor &c, uint seed)
^ qHash(c.data[1]) ^ qHash(c.data[2]) ^ seed;
}
+bool operator==(const CXType &t1, const CXType &t2)
+{
+ return t1.kind == t2.kind && t1.data[0] == t2.data[0]
+ && t1.data[1] == t2.data[1];
+}
+
+uint qHash(const CXType &ct, uint seed)
+{
+ return uint(ct.kind) ^ uint(0xFFFFFFFF & quintptr(ct.data[0]))
+ ^ uint(0xFFFFFFFF & quintptr(ct.data[1])) ^ seed;
+}
+
namespace clang {
SourceLocation getExpansionLocation(const CXSourceLocation &location)
@@ -160,6 +172,43 @@ QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu)
return result;
}
+QPair<int, int> parseTemplateArgumentList(const QString &l,
+ const TemplateArgumentHandler &handler,
+ int from)
+{
+ const int ltPos = l.indexOf(QLatin1Char('<'), from);
+ if (ltPos == - 1)
+ return qMakePair(-1, -1);
+ int startPos = ltPos + 1;
+ int level = 1;
+ for (int p = startPos, end = l.size(); p < end; ) {
+ const char c = l.at(p).toLatin1();
+ switch (c) {
+ case ',':
+ case '>':
+ handler(level, l.midRef(startPos, p - startPos).trimmed());
+ ++p;
+ if (c == '>') {
+ if (--level == 0)
+ return qMakePair(ltPos, p);
+ // Skip over next ',': "a<b<c,d>,e>"
+ for (; p < end && (l.at(p).isSpace() || l.at(p) == QLatin1Char(',')); ++p) {}
+ }
+ startPos = p;
+ break;
+ case '<':
+ handler(level, l.midRef(startPos, p - startPos).trimmed());
+ ++level;
+ startPos = ++p;
+ break;
+ default:
+ ++p;
+ break;
+ }
+ }
+ return qMakePair(-1, -1);
+}
+
CXDiagnosticSeverity maxSeverity(const QVector<Diagnostic> &ds)
{
CXDiagnosticSeverity result = CXDiagnostic_Ignored;
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
index 98d0c9752..b290aac9a 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
@@ -34,11 +34,16 @@
#include <QtCore/QString>
#include <QtCore/QVector>
+#include <functional>
+
QT_FORWARD_DECLARE_CLASS(QDebug)
bool operator==(const CXCursor &c1, const CXCursor &c2);
uint qHash(const CXCursor &c, uint seed = 0);
+bool operator==(const CXType &t1, const CXType &t2);
+uint qHash(const CXType &ct, uint seed);
+
namespace clang {
QString getCursorKindName(CXCursorKind cursorKind);
@@ -92,6 +97,14 @@ struct Diagnostic {
QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu);
CXDiagnosticSeverity maxSeverity(const QVector<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.
+typedef std::function<void(int /*level*/, const QStringRef &)> TemplateArgumentHandler;
+
+QPair<int, int> parseTemplateArgumentList(const QString &l,
+ const TemplateArgumentHandler &handler,
+ int from = 0);
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug, const SourceLocation &);
QDebug operator<<(QDebug, const Diagnostic &);
diff --git a/sources/shiboken2/ApiExtractor/doc/conf.py.in b/sources/shiboken2/ApiExtractor/doc/conf.py.in
index 7251aaccd..609c4a363 100644
--- a/sources/shiboken2/ApiExtractor/doc/conf.py.in
+++ b/sources/shiboken2/ApiExtractor/doc/conf.py.in
@@ -132,10 +132,6 @@ html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_themes']
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-html_use_smartypants = True
-
# Custom sidebar templates, maps document names to template names.
#html_sidebars = { '' : ''}
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst
index ff6ea5317..12b866ad7 100644
--- a/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst
@@ -11,6 +11,9 @@ inject-code
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.
+ The code can be embedded into XML (be careful to use the correct XML entities
+ for characters like '<', '>', '&'):
+
.. code-block:: xml
<value-type>
@@ -20,6 +23,18 @@ inject-code
</inject-code>
</value-type>
+ or obtained from an external file:
+
+ .. code-block:: xml
+
+ <value-type>
+ <inject-code class="native | target | target-declaration"
+ position="beginning | end" since="..."
+ file="external_source.cpp"
+ snippet="label"/>
+ </value-type>
+
+
The ``class`` attribute specifies which module of the generated code that
will be affected by the code injection. The ``class`` attribute accepts the
following values:
@@ -28,6 +43,8 @@ inject-code
* target: The binding code
* target-declaration: The code will be injected into the generated header
file containing the c++ wrapper class definition.
+ * file: The file name
+ * snippet: The snippet label (optional)
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
@@ -35,6 +52,16 @@ inject-code
The ``since`` attribute specify the API version where this code was injected.
+ If a ``snippet`` label is given, the code between annotations of the form
+
+ .. code-block:: c++
+
+ // @snippet label
+ ...
+ // @snippet label
+
+ will be extracted.
+
modify-field
^^^^^^^^^^^^
@@ -74,6 +101,8 @@ modify-function
since="..."
remove="all | c++"
access="public | private | protected"
+ allow-thread="true | auto | false"
+ exception-handling="off | auto-off | auto-on | on"
rename="..." />
</object-type>
@@ -82,6 +111,26 @@ modify-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 ``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 ``remove``, ``access`` and ``rename`` attributes are *optional* attributes
for added convenience; they serve the same purpose as the deprecated tags :ref:`remove`, :ref:`access` and :ref:`rename`.
@@ -130,3 +179,4 @@ conversion-rule
.. note:: You can also use the conversion-rule node to specify :ref:`how the conversion of a single function argument should be done in a function <conversion-rule>`.
+ The ``file`` and ``snippet`` attributes are also supported (see :ref:`inject-code` nodes).
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
index 322f9bca6..c3180ae88 100644
--- a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
@@ -11,7 +11,7 @@ typesystem
.. code-block:: xml
- <typesystem package="..." default-superclass="...">
+ <typesystem package="..." default-superclass="..." exception-handling="...">
</typesystem>
The **package** attribute is a string describing the package to be used,
@@ -19,6 +19,9 @@ typesystem
The *optional* **default-superclass** attribute is the canonical C++ base class
name of all objects, e.g., "object".
+ The *optional* **exception-handling** attribute specifies the default exception
+ handling mode of all objects (see :ref:`modify-function`).
+
load-typesystem
^^^^^^^^^^^^^^^
@@ -216,6 +219,7 @@ value-type
<typesystem>
<value-type name="..." since="..."
copyable="yes | no"
+ exception-handling="..."
hash-function="..."
stream="yes | no"
default-constructor="..."
@@ -243,6 +247,9 @@ value-type
The **revision** attribute can be used to specify a revision for each type, easing the
production of ABI compatible bindings.
+ The *optional* **exception-handling** attribute specifies the default exception
+ handling mode of all functions (see :ref:`modify-function`).
+
.. _object-type:
object-type
@@ -258,6 +265,7 @@ object-type
<object-type name="..."
since="..."
copyable="yes | no"
+ exception-handling="..."
hash-function="..."
stream="yes | no"
revision="..." />
@@ -278,6 +286,9 @@ object-type
The **revision** attribute can be used to specify a revision for each type, easing the
production of ABI compatible bindings.
+ The *optional* **exception-handling** attribute specifies the default exception
+ handling mode of all functions (see :ref:`modify-function`).
+
interface-type
^^^^^^^^^^^^^^
@@ -329,6 +340,38 @@ container-type
The *optional* **since** value is used to specify the API version of this container.
+typedef-type
+^^^^^^^^^^^^
+
+ The typedef-type 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.
+
+ .. 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:
@@ -348,6 +391,26 @@ custom-type
The **name** attribute is the name of the custom type, e.g., "PyObject".
+.. _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, only the **type** *shared* is supported and the usage is limited
+ to function return values.
+ **ref-count-method** specifies the name of the method used to do reference counting.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <smart-pointer-type name="..."
+ since="..."
+ type="..."
+ getter="..."
+ ref-count-method="..."/>
+ </typesystem>
.. _function:
diff --git a/sources/shiboken2/ApiExtractor/docparser.cpp b/sources/shiboken2/ApiExtractor/docparser.cpp
index 9305332ba..99921e7d3 100644
--- a/sources/shiboken2/ApiExtractor/docparser.cpp
+++ b/sources/shiboken2/ApiExtractor/docparser.cpp
@@ -27,6 +27,7 @@
****************************************************************************/
#include "docparser.h"
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typesystem.h"
#include <QtCore/QDebug>
@@ -50,9 +51,7 @@ DocParser::DocParser()
#endif
}
-DocParser::~DocParser()
-{
-}
+DocParser::~DocParser() = default;
QString DocParser::getDocumentation(QXmlQuery& xquery, const QString& query,
const DocModificationList& mods) const
@@ -109,58 +108,21 @@ AbstractMetaFunctionList DocParser::documentableFunctions(const AbstractMetaClas
return result;
}
-QString DocParser::msgCannotFindDocumentation(const QString &fileName,
- const char *what, const QString &name,
- const QString &query)
-{
- QString result;
- QTextStream(&result) << "Cannot find documentation for " << what
- << ' ' << name << " in:\n " << QDir::toNativeSeparators(fileName)
- << "\n using query:\n " << query;
- return result;
-}
-
-QString DocParser::msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaFunction *function,
- const QString &query)
-{
- const QString name = metaClass->name() + QLatin1String("::")
- + function->minimalSignature();
- return msgCannotFindDocumentation(fileName, "function", name, query);
-}
-
-QString DocParser::msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaEnum *e,
- const QString &query)
-{
- return msgCannotFindDocumentation(fileName, "enum",
- metaClass->name() + QLatin1String("::") + e->name(),
- query);
-}
-
-QString DocParser::msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaField *f,
- const QString &query)
-{
- return msgCannotFindDocumentation(fileName, "field",
- metaClass->name() + QLatin1String("::") + f->name(),
- query);
-}
#ifdef HAVE_LIBXSLT
namespace
{
-struct XslResources
+class XslResources
{
- xmlDocPtr xmlDoc;
- xsltStylesheetPtr xslt;
- xmlDocPtr xslResult;
+ Q_DISABLE_COPY(XslResources)
+
+public:
+ xmlDocPtr xmlDoc = nullptr;
+ xsltStylesheetPtr xslt = nullptr;
+ xmlDocPtr xslResult = nullptr;
- XslResources() : xmlDoc(0), xslt(0), xslResult(0) {}
+ XslResources() = default;
~XslResources()
{
@@ -186,27 +148,6 @@ static inline bool isXpathDocModification(const DocModification &mod)
return mod.mode() == TypeSystem::DocModificationXPathReplace;
}
-QString msgXpathDocModificationError(const DocModificationList& mods,
- const QString &what)
-{
- QString result;
- QTextStream str(&result);
- str << "Error when applying modifications (";
- for (const DocModification &mod : mods) {
- if (isXpathDocModification(mod)) {
- str << '"' << mod.xpath() << "\" -> \"";
- const QString simplified = mod.code().simplified();
- if (simplified.size() > 20)
- str << simplified.leftRef(20) << "...";
- else
- str << simplified;
- str << '"';
- }
- }
- str << "): " << what;
- return result;
-}
-
QString DocParser::applyDocModifications(const DocModificationList& mods, const QString& xml) const
{
if (mods.isEmpty() || xml.isEmpty()
diff --git a/sources/shiboken2/ApiExtractor/docparser.h b/sources/shiboken2/ApiExtractor/docparser.h
index fff71a877..7cbbef28e 100644
--- a/sources/shiboken2/ApiExtractor/docparser.h
+++ b/sources/shiboken2/ApiExtractor/docparser.h
@@ -120,22 +120,6 @@ protected:
static AbstractMetaFunctionList documentableFunctions(const AbstractMetaClass *metaClass);
- static QString msgCannotFindDocumentation(const QString &fileName,
- const char *what, const QString &name,
- const QString &query);
- static QString msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaFunction *function,
- const QString &query);
- static QString msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaEnum *e,
- const QString &query);
- static QString msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaField *f,
- const QString &query);
-
private:
QString m_packageName;
QString m_docDataDir;
diff --git a/sources/shiboken2/ApiExtractor/doxygenparser.cpp b/sources/shiboken2/ApiExtractor/doxygenparser.cpp
index dfdb37a47..e238aa1f7 100644
--- a/sources/shiboken2/ApiExtractor/doxygenparser.cpp
+++ b/sources/shiboken2/ApiExtractor/doxygenparser.cpp
@@ -28,6 +28,7 @@
#include "doxygenparser.h"
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typesystem.h"
@@ -35,23 +36,17 @@
#include <QtCore/QFile>
#include <QtCore/QDir>
-namespace
+static QString getSectionKindAttr(const AbstractMetaFunction *func)
{
-
-QString getSectionKindAttr(const AbstractMetaFunction* func)
-{
- if (func->isSignal()) {
+ if (func->isSignal())
return QLatin1String("signal");
- } else {
- QString kind = func->isPublic() ? QLatin1String("public") : QLatin1String("protected");
- if (func->isStatic())
- kind += QLatin1String("-static");
- else if (func->isSlot())
- kind += QLatin1String("-slot");
- return kind;
- }
-}
-
+ QString kind = func->isPublic()
+ ? QLatin1String("public") : QLatin1String("protected");
+ if (func->isStatic())
+ kind += QLatin1String("-static");
+ else if (func->isSlot())
+ kind += QLatin1String("-slot");
+ return kind;
}
Documentation DoxygenParser::retrieveModuleDocumentation()
@@ -73,13 +68,12 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass)
doxyFileSuffix += QLatin1String(".xml");
const char* prefixes[] = { "class", "struct", "namespace" };
- const int numPrefixes = sizeof(prefixes) / sizeof(const char*);
bool isProperty = false;
QString doxyFilePath;
- for (int i = 0; i < numPrefixes; ++i) {
+ for (const char *prefix : prefixes) {
doxyFilePath = documentationDataDirectory() + QLatin1Char('/')
- + QLatin1String(prefixes[i]) + doxyFileSuffix;
+ + QLatin1String(prefix) + doxyFileSuffix;
if (QFile::exists(doxyFilePath))
break;
doxyFilePath.clear();
diff --git a/sources/shiboken2/ApiExtractor/fileout.cpp b/sources/shiboken2/ApiExtractor/fileout.cpp
index e3c96d57b..10a8f6be8 100644
--- a/sources/shiboken2/ApiExtractor/fileout.cpp
+++ b/sources/shiboken2/ApiExtractor/fileout.cpp
@@ -27,11 +27,13 @@
****************************************************************************/
#include "fileout.h"
+#include "messages.h"
#include "reporthandler.h"
#include <QtCore/QTextCodec>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
+#include <QtCore/QDebug>
#include <cstdio>
@@ -50,24 +52,25 @@ static const char colorInfo[] = "";
static const char colorReset[] = "";
#endif
-FileOut::FileOut(QString n):
- name(n),
- stream(&tmp),
- isDone(false)
-{}
+FileOut::FileOut(QString n) :
+ name(std::move(n)),
+ stream(&tmp),
+ isDone(false)
+{
+}
+
+FileOut::~FileOut()
+{
+ if (!isDone)
+ done();
+}
-static int* lcsLength(QList<QByteArray> a, QList<QByteArray> b)
+static QVector<int> lcsLength(const QByteArrayList &a, const QByteArrayList &b)
{
const int height = a.size() + 1;
const int width = b.size() + 1;
- int *res = new int[width * height];
-
- for (int row = 0; row < height; row++)
- res[width * row] = 0;
-
- for (int col = 0; col < width; col++)
- res[col] = 0;
+ QVector<int> res(width * height, 0);
for (int row = 1; row < height; row++) {
for (int col = 1; col < width; col++) {
@@ -89,88 +92,84 @@ enum Type {
struct Unit
{
- Unit(Type type, int pos) :
- type(type),
- start(pos),
- end(pos) {}
-
Type type;
int start;
int end;
- void print(QList<QByteArray> a, QList<QByteArray> b)
- {
- if (type == Unchanged) {
- if ((end - start) > 9) {
- for (int i = start; i <= start + 2; i++)
- std::printf(" %s\n", a[i].data());
- std::printf("%s=\n= %d more lines\n=%s\n", colorInfo, end - start - 6, colorReset);
- for (int i = end - 2; i <= end; i++)
- std::printf(" %s\n", a[i].data());
- } else {
- for (int i = start; i <= end; i++)
- std::printf(" %s\n", a[i].data());
- }
- } else if (type == Add) {
- std::printf("%s", colorAdd);
- for (int i = start; i <= end; i++)
- std::printf("+ %s\n", b[i].data());
- std::printf("%s", colorReset);
- } else if (type == Delete) {
- std::printf("%s", colorDelete);
- for (int i = start; i <= end; i++)
- std::printf("- %s\n", a[i].data());
- std::printf("%s", colorReset);
- }
- }
+ void print(const QByteArrayList &a, const QByteArrayList &b) const;
};
-static QList<Unit*> *unitAppend(QList<Unit*> *res, Type type, int pos)
+void Unit::print(const QByteArrayList &a, const QByteArrayList &b) const
{
- if (!res) {
- res = new QList<Unit*>;
- res->append(new Unit(type, pos));
- return res;
+ switch (type) {
+ case Unchanged:
+ if ((end - start) > 9) {
+ for (int 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, end - start - 6, colorReset);
+ for (int i = end - 2; i <= end; i++)
+ std::printf(" %s\n", a.at(i).constData());
+ } else {
+ for (int i = start; i <= end; i++)
+ std::printf(" %s\n", a.at(i).constData());
+ }
+ break;
+ case Add:
+ std::fputs(colorAdd, stdout);
+ for (int 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 (int i = start; i <= end; i++)
+ std::printf("- %s\n", a.at(i).constData());
+ std::fputs(colorReset, stdout);
+ break;
}
+}
- Unit *last = res->last();
- if (last->type == type)
- last->end = pos;
+static void unitAppend(Type type, int pos, QVector<Unit> *units)
+{
+ if (!units->isEmpty() && units->last().type == type)
+ units->last().end = pos;
else
- res->append(new Unit(type, pos));
-
- return res;
+ units->append(Unit{type, pos, pos});
}
-static QList<Unit*> *diffHelper(int *lcs, QList<QByteArray> a, QList<QByteArray> b, int row, int col)
+static QVector<Unit> diffHelper(const QVector<int> &lcs,
+ const QByteArrayList &a, const QByteArrayList &b,
+ int row, int col)
{
- if (row > 0 && col > 0 && (a[row-1] == b[col-1])) {
- return unitAppend(diffHelper(lcs, a, b, row - 1, col - 1), Unchanged, row - 1);
- } else {
- int width = b.size() + 1;
- if ((col > 0)
- && (row == 0 || lcs[width * row + col-1] >= lcs[width *(row-1) + col])) {
- return unitAppend(diffHelper(lcs, a, b, row, col - 1), Add, col - 1);
- } else if ((row > 0)
- && (col == 0 || lcs[width * row + col-1] < lcs[width *(row-1) + col])) {
- return unitAppend(diffHelper(lcs, a, b, row - 1, col), Delete, row - 1);
- }
+ if (row > 0 && col > 0 && a.at(row - 1) == b.at(col - 1)) {
+ QVector<Unit> result = diffHelper(lcs, a, b, row - 1, col - 1);
+ unitAppend(Unchanged, row - 1, &result);
+ return result;
}
- delete lcs;
- return 0;
-}
-static void diff(QList<QByteArray> a, QList<QByteArray> b)
-{
- QList<Unit*> *res = diffHelper(lcsLength(a, b), a, b, a.size(), b.size());
- for (int i = 0; i < res->size(); i++) {
- Unit *unit = res->at(i);
- unit->print(a, b);
- delete(unit);
+ const int width = b.size() + 1;
+ if (col > 0
+ && (row == 0 || lcs.at(width * row + col -1 ) >= lcs.at(width * (row - 1) + col))) {
+ QVector<Unit> result = diffHelper(lcs, a, b, row, col - 1);
+ unitAppend(Add, col - 1, &result);
+ return result;
}
- delete(res);
+ if (row > 0
+ && (col == 0 || lcs.at(width * row + col-1) < lcs.at(width * (row - 1) + col))) {
+ QVector<Unit> result = diffHelper(lcs, a, b, row - 1, col);
+ unitAppend(Delete, row - 1, &result);
+ return result;
+ }
+ return QVector<Unit>{};
}
+static void diff(const QByteArrayList &a, const QByteArrayList &b)
+{
+ const QVector<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()
{
@@ -181,18 +180,6 @@ FileOut::State FileOut::done()
return result;
}
-QString FileOut::msgCannotOpenForReading(const QFile &f)
-{
- return QStringLiteral("Failed to open file '%1' for reading: %2")
- .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
-}
-
-QString FileOut::msgCannotOpenForWriting(const QFile &f)
-{
- return QStringLiteral("Failed to open file '%1' for writing: %2")
- .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
-}
-
FileOut::State FileOut::done(QString *errorMessage)
{
Q_ASSERT(!isDone);
@@ -245,3 +232,18 @@ FileOut::State FileOut::done(QString *errorMessage)
return Success;
}
+
+void FileOut::touchFile(const QString &filePath)
+{
+ QFile toucher(filePath);
+ qint64 size = toucher.size();
+ if (!toucher.open(QIODevice::ReadWrite)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Failed to touch file '%1'")
+ .arg(QDir::toNativeSeparators(filePath));
+ return;
+ }
+ toucher.resize(size+1);
+ toucher.resize(size);
+ toucher.close();
+}
diff --git a/sources/shiboken2/ApiExtractor/fileout.h b/sources/shiboken2/ApiExtractor/fileout.h
index 539ae7a43..aace70131 100644
--- a/sources/shiboken2/ApiExtractor/fileout.h
+++ b/sources/shiboken2/ApiExtractor/fileout.h
@@ -43,18 +43,17 @@ private:
public:
enum State { Failure, Unchanged, Success };
- FileOut(QString name);
- ~FileOut()
- {
- if (!isDone)
- done();
- }
+ explicit FileOut(QString name);
+ ~FileOut();
+
+ QString filePath() const { return name; }
State done();
State done(QString *errorMessage);
- static QString msgCannotOpenForReading(const QFile &f);
- static QString msgCannotOpenForWriting(const QFile &f);
+ void touch() { touchFile(name); }
+
+ static void touchFile(const QString &filePath);
QTextStream stream;
diff --git a/sources/shiboken2/ApiExtractor/include.cpp b/sources/shiboken2/ApiExtractor/include.cpp
index 963999b9d..d6a451992 100644
--- a/sources/shiboken2/ApiExtractor/include.cpp
+++ b/sources/shiboken2/ApiExtractor/include.cpp
@@ -36,10 +36,9 @@ QString Include::toString() const
{
if (m_type == IncludePath)
return QLatin1String("#include <") + m_name + QLatin1Char('>');
- else if (m_type == LocalPath)
+ if (m_type == LocalPath)
return QLatin1String("#include \"") + m_name + QLatin1Char('"');
- else
- return QLatin1String("import ") + m_name + QLatin1Char(';');
+ return QLatin1String("import ") + m_name + QLatin1Char(';');
}
uint qHash(const Include& inc)
diff --git a/sources/shiboken2/ApiExtractor/include.h b/sources/shiboken2/ApiExtractor/include.h
index 16059876a..4890eea2c 100644
--- a/sources/shiboken2/ApiExtractor/include.h
+++ b/sources/shiboken2/ApiExtractor/include.h
@@ -42,7 +42,8 @@ public:
enum IncludeType {
IncludePath,
LocalPath,
- TargetLangImport
+ TargetLangImport,
+ InvalidInclude
};
Include() : m_type(IncludePath) {}
diff --git a/sources/shiboken2/ApiExtractor/messages.cpp b/sources/shiboken2/ApiExtractor/messages.cpp
new file mode 100644
index 000000000..fa4c75743
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/messages.cpp
@@ -0,0 +1,446 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "messages.h"
+#include "abstractmetalang.h"
+#include "typesystem.h"
+#include <codemodel.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QStringList>
+#include <QtCore/QXmlStreamReader>
+
+static inline QString colonColon() { return QStringLiteral("::"); }
+
+// abstractmetabuilder.cpp
+
+QString msgNoFunctionForModification(const QString &signature,
+ const QString &originalSignature,
+ const QString &className,
+ const QStringList &possibleSignatures,
+ const AbstractMetaFunctionList &allFunctions)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "signature '" << signature << '\'';
+ if (!originalSignature.isEmpty() && originalSignature != signature)
+ str << " (specified as '" << originalSignature << "')";
+ str << " for function modification in '"
+ << className << "' 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 int maxCount = qMin(10, allFunctions.size());
+ for (int f = 0; f < maxCount; ++f)
+ str << " " << allFunctions.at(f)->minimalSignature() << '\n';
+ if (maxCount < allFunctions.size())
+ str << " ...\n";
+ }
+ 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(colonColon()) << '\'';
+ 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(colonColon()) << '\'';
+ break;
+ }
+ if (!className.isEmpty())
+ str << " (class: " << className << ')';
+}
+
+QString msgNoEnumTypeEntry(const EnumModelItem &enumItem,
+ const QString &className)
+{
+ QString result;
+ QTextStream str(&result);
+ msgFormatEnumType(str, enumItem, className);
+ str << " does not have a type entry";
+ return result;
+}
+
+QString msgNoEnumTypeConflict(const EnumModelItem &enumItem,
+ const QString &className,
+ const TypeEntry *t)
+{
+ QString result;
+ QDebug debug(&result); // Use the debug operator for TypeEntry::Type
+ debug.noquote();
+ debug.nospace();
+ msgFormatEnumType(debug, enumItem, className);
+ debug << " is not an enum (type: " << t->type() << ')';
+ 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 QLatin1String("unmatched return type '")
+ + functionItem->type().toString()
+ + QLatin1String("': ") + why;
+}
+
+QString msgSkippingFunction(const FunctionModelItem &functionItem,
+ const QString &signature, const QString &why)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "skipping ";
+ if (functionItem->isAbstract())
+ str << "abstract ";
+ str << "function '" << signature << "', " << why;
+ if (functionItem->isAbstract()) {
+ str << "\nThis will lead to compilation errors due to not "
+ "being able to instantiate the wrapper.";
+ }
+ return result;
+}
+
+QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason)
+{
+ return function + QLatin1String(": Cannot use parameter ")
+ + QString::number(i + 1) + QLatin1String(" as an array: ") + reason;
+}
+
+QString msgUnableToTranslateType(const QString &t, const QString &why)
+{
+ return QLatin1String("Unable to translate type \"")
+ + t + QLatin1String("\": ") + why;
+}
+
+QString msgUnableToTranslateType(const TypeInfo &typeInfo,
+ const QString &why)
+{
+ return msgUnableToTranslateType(typeInfo.toString(), why);
+}
+
+QString msgCannotFindTypeEntry(const QString &t)
+{
+ return QLatin1String("Cannot find type entry for \"") + t + QLatin1String("\".");
+}
+
+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;
+}
+
+// abstractmetalang.cpp
+
+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;
+}
+
+// docparser.cpp
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const char *what, const QString &name,
+ const QString &query)
+{
+ QString result;
+ QTextStream(&result) << "Cannot find documentation for " << what
+ << ' ' << name << " in:\n " << QDir::toNativeSeparators(fileName)
+ << "\n using query:\n " << query;
+ return result;
+}
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaFunction *function,
+ const QString &query)
+{
+ const QString name = metaClass->name() + QLatin1String("::")
+ + function->minimalSignature();
+ return msgCannotFindDocumentation(fileName, "function", name, query);
+}
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaEnum *e,
+ const QString &query)
+{
+ return msgCannotFindDocumentation(fileName, "enum",
+ metaClass->name() + QLatin1String("::") + e->name(),
+ query);
+}
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaField *f,
+ const QString &query)
+{
+ return msgCannotFindDocumentation(fileName, "field",
+ metaClass->name() + QLatin1String("::") + f->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 << simplified.leftRef(20) << "...";
+ else
+ str << simplified;
+ str << '"';
+ }
+ }
+ str << "): " << what;
+ return result;
+}
+
+// fileout.cpp
+
+QString msgCannotOpenForReading(const QFile &f)
+{
+ return QStringLiteral("Failed to open file '%1' for reading: %2")
+ .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
+}
+
+QString msgCannotOpenForWriting(const QFile &f)
+{
+ return QStringLiteral("Failed to open file '%1' for writing: %2")
+ .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
+}
+
+// generator.cpp
+
+QString msgCannotUseEnumAsInt(const QString &name)
+{
+ return QLatin1String("Cannot convert the protected scoped enum \"") + name
+ + QLatin1String("\" to type int when generating wrappers for the protected hack. "
+ "Compilation errors may occur when used as a function argument.");
+}
+
+// main.cpp
+
+QString msgLeftOverArguments(const QMap<QString, QString> &remainingArgs)
+{
+ QString message;
+ QTextStream str(&message);
+ str << "shiboken: Called with wrong arguments:";
+ for (auto it = remainingArgs.cbegin(), end = remainingArgs.cend(); it != end; ++it) {
+ str << ' ' << it.key();
+ if (!it.value().isEmpty())
+ str << ' ' << it.value();
+ }
+ str << "\nCommand line: " << QCoreApplication::arguments().join(QLatin1Char(' '));
+ return message;
+}
+
+QString msgInvalidVersion(const QString &package, const QString &version)
+{
+ return QLatin1String("Invalid version \"") + version
+ + QLatin1String("\" specified for package ") + package + QLatin1Char('.');
+}
+
+QString msgCyclicDependency(const QString &funcName, const QString &graphName,
+ const QVector<const AbstractMetaFunction *> &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) << "\".";
+ if (const int count = involvedConversions.size()) {
+ str << " Implicit conversions (" << count << "): ";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ str << ", \"";
+ str << involvedConversions.at(i)->signature() << '"';
+ if (const AbstractMetaClass *c = involvedConversions.at(i)->implementingClass())
+ str << '(' << c->name() << ')';
+ }
+ }
+ return result;
+}
+
+// shibokengenerator.cpp
+
+QString msgUnknownOperator(const AbstractMetaFunction* func)
+{
+ QString result = QLatin1String("Unknown operator: \"") + func->originalName()
+ + QLatin1Char('"');
+ if (const AbstractMetaClass *c = func->implementingClass())
+ result += QLatin1String(" in class: ") + 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 AbstractMetaClass *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 QLatin1String("Unable to build meta type for \"")
+ + s + QLatin1String("\": ");
+}
+
+QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type)
+{
+ return where + QLatin1String(": Could not find a minimal constructor for type '")
+ + type + QLatin1String("'. This will result in a compilation error.");
+}
+
+// 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;
+ case TypeRejection::Invalid:
+ break;
+ }
+ return result;
+}
+
+// qtdocgenerator.cpp
+
+QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &message)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "While handling <";
+ const QStringRef currentTag = reader.name();
+ if (currentTag.isEmpty())
+ str << tag;
+ else
+ str << currentTag;
+ str << "> in " << context << ", line "<< reader.lineNumber()
+ << ": " << message;
+ return result;
+}
+
+QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &location,
+ const QString &identifier, const QString &fallback)
+{
+ QString message = QLatin1String("Falling back to \"")
+ + QDir::toNativeSeparators(fallback) + QLatin1String("\" for \"")
+ + location + QLatin1Char('"');
+ if (!identifier.isEmpty())
+ message += QLatin1String(" [") + identifier + QLatin1Char(']');
+ return msgTagWarning(reader, context, tag, message);
+}
diff --git a/sources/shiboken2/ApiExtractor/messages.h b/sources/shiboken2/ApiExtractor/messages.h
new file mode 100644
index 000000000..539332aef
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/messages.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MESSAGES_H
+#define MESSAGES_H
+
+#include "abstractmetalang_typedefs.h"
+#include "parser/codemodel_fwd.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+class TypeEntry;
+class TypeInfo;
+struct TypeRejection;
+
+QT_FORWARD_DECLARE_CLASS(QDir)
+QT_FORWARD_DECLARE_CLASS(QFile)
+QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
+
+QString msgNoFunctionForModification(const QString &signature,
+ const QString &originalSignature,
+ const QString &className,
+ const QStringList &possibleSignatures,
+ const AbstractMetaFunctionList &allFunctions);
+
+QString msgNoEnumTypeEntry(const EnumModelItem &enumItem,
+ const QString &className);
+
+
+QString msgNoEnumTypeConflict(const EnumModelItem &enumItem,
+ const QString &className,
+ const TypeEntry *t);
+
+QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n,
+ const QString &why);
+
+QString msgUnmatchedReturnType(const FunctionModelItem &functionItem,
+ const QString &why);
+
+QString msgSkippingFunction(const FunctionModelItem &functionItem,
+ const QString &signature, const QString &why);
+
+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 msgCannotTranslateTemplateArgument(int i,
+ const TypeInfo &typeInfo,
+ const QString &why);
+
+QString msgDisallowThread(const AbstractMetaFunction *f);
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const char *what, const QString &name,
+ const QString &query);
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaFunction *function,
+ const QString &query);
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaEnum *e,
+ const QString &query);
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *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 msgCannotUseEnumAsInt(const QString &name);
+
+QString msgLeftOverArguments(const QMap<QString, QString> &remainingArgs);
+
+QString msgInvalidVersion(const QString &package, const QString &version);
+
+QString msgCyclicDependency(const QString &funcName, const QString &graphName,
+ const QVector<const AbstractMetaFunction *> &involvedConversions);
+
+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);
+
+QString msgRejectReason(const TypeRejection &r, const QString &needle = QString());
+
+QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &message);
+
+QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &location,
+ const QString &identifier, const QString &fallback);
+
+#endif // MESSAGES_H
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp
index d862692dd..173f6dd23 100644
--- a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp
@@ -29,11 +29,15 @@
#include "codemodel.h"
+
+#include <clangparser/clangutils.h>
+
#include <algorithm>
#include <functional>
#include <iostream>
#include <QDebug>
#include <QDir>
+#include <QtCore/QStack>
// Predicate to find an item by name in a list of QSharedPointer<Item>
template <class T> class ModelItemNamePredicate : public std::unary_function<bool, QSharedPointer<T> >
@@ -140,16 +144,18 @@ TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs)
__result.setVolatile(__result.isVolatile() || __rhs.isVolatile());
if (__rhs.referenceType() > __result.referenceType())
__result.setReferenceType(__rhs.referenceType());
- __result.setIndirections(__result.indirections() + __rhs.indirections());
+ __result.m_indirections.append(__rhs.m_indirections);
__result.setArrayElements(__result.arrayElements() + __rhs.arrayElements());
+ __result.m_instantiations.append(__rhs.m_instantiations);
return __result;
}
bool TypeInfo::isVoid() const
{
- return m_indirections == 0 && m_referenceType == NoReference
+ return m_indirections.isEmpty() && m_referenceType == NoReference
&& m_arguments.isEmpty() && m_arrayElements.isEmpty()
+ && m_instantiations.isEmpty()
&& m_qualifiedName.size() == 1
&& m_qualifiedName.constFirst() == QLatin1String("void");
}
@@ -193,19 +199,76 @@ TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, Cod
return otherType;
}
+// Handler for clang::parseTemplateArgumentList() that populates
+// TypeInfo::m_instantiations
+class TypeInfoTemplateArgumentHandler :
+ public std::binary_function<void, int, const QStringRef &>
+{
+public:
+ explicit TypeInfoTemplateArgumentHandler(TypeInfo *t)
+ {
+ m_parseStack.append(t);
+ }
+
+ void operator()(int level, const QStringRef &name)
+ {
+ if (level > m_parseStack.size()) {
+ Q_ASSERT(!top()->m_instantiations.isEmpty());
+ m_parseStack.push(&top()->m_instantiations.back());
+ }
+ while (level < m_parseStack.size())
+ m_parseStack.pop();
+ TypeInfo instantiation;
+ instantiation.setQualifiedName(qualifiedName(name));
+ top()->addInstantiation(instantiation);
+ }
+
+private:
+ TypeInfo *top() const { return m_parseStack.back(); }
+
+ static QStringList qualifiedName(const QStringRef &name)
+ {
+ QStringList result;
+ const QVector<QStringRef> nameParts = name.split(QLatin1String("::"));
+ result.reserve(nameParts.size());
+ for (const QStringRef &p : nameParts)
+ result.append(p.toString());
+ return result;
+ }
+
+ QStack<TypeInfo *> m_parseStack;
+};
+
+QPair<int, int> TypeInfo::parseTemplateArgumentList(const QString &l, int from)
+{
+ return clang::parseTemplateArgumentList(l, clang::TemplateArgumentHandler(TypeInfoTemplateArgumentHandler(this)), from);
+}
+
QString TypeInfo::toString() const
{
QString tmp;
-
- tmp += m_qualifiedName.join(QLatin1String("::"));
if (isConstant())
- tmp += QLatin1String(" const");
+ tmp += QLatin1String("const ");
if (isVolatile())
- tmp += QLatin1String(" volatile");
+ tmp += QLatin1String("volatile ");
- if (indirections())
- tmp += QString(indirections(), QLatin1Char('*'));
+ tmp += m_qualifiedName.join(QLatin1String("::"));
+
+ if (const int instantiationCount = m_instantiations.size()) {
+ tmp += QLatin1Char('<');
+ for (int i = 0; i < instantiationCount; ++i) {
+ if (i)
+ tmp += QLatin1String(", ");
+ tmp += m_instantiations.at(i).toString();
+ }
+ if (tmp.endsWith(QLatin1Char('>')))
+ tmp += QLatin1Char(' ');
+ tmp += QLatin1Char('>');
+ }
+
+ for (Indirection i : m_indirections)
+ tmp.append(indirectionKeyword(i));
switch (referenceType()) {
case NoReference:
@@ -238,20 +301,6 @@ QString TypeInfo::toString() const
return tmp;
}
-QStringList TypeInfo::instantiationName() const
-{
- QStringList result = m_qualifiedName;
- if (const int argumentCount = m_arguments.size()) {
- QString &last = result.last();
- for (int i = 0; i < argumentCount; ++i) {
- last += i ? QLatin1String(", ") : QLatin1String("< ");
- last += m_arguments.at(i).toString();
- }
- last += QLatin1String(" >");
- }
- return result;
-}
-
bool TypeInfo::operator==(const TypeInfo &other) const
{
if (arrayElements().count() != other.arrayElements().count())
@@ -269,7 +318,73 @@ bool TypeInfo::operator==(const TypeInfo &other) const
return flags == other.flags
&& m_qualifiedName == other.m_qualifiedName
- && (!m_functionPointer || m_arguments == other.m_arguments);
+ && (!m_functionPointer || m_arguments == other.m_arguments)
+ && m_instantiations == other.m_instantiations;
+}
+
+QString TypeInfo::indirectionKeyword(Indirection i)
+{
+ return i == Indirection::Pointer
+ ? QStringLiteral("*") : QStringLiteral("*const");
+}
+
+static inline QString constQualifier() { return QStringLiteral("const"); }
+static inline QString volatileQualifier() { return QStringLiteral("volatile"); }
+
+bool TypeInfo::stripLeadingConst(QString *s)
+{
+ return stripLeadingQualifier(constQualifier(), s);
+}
+
+bool TypeInfo::stripLeadingVolatile(QString *s)
+{
+ return stripLeadingQualifier(volatileQualifier(), s);
+}
+
+bool TypeInfo::stripLeadingQualifier(const QString &qualifier, QString *s)
+{
+ // "const int x"
+ const int 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;
+}
+
+// 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 TypeInfo::isStdType() const
+{
+ return m_qualifiedName.size() > 1
+ && m_qualifiedName.constFirst() == QLatin1String("std");
+}
+
+static inline bool discardStdType(const QString &name)
+{
+ return name == QLatin1String("allocator") || name == QLatin1String("less");
+}
+
+void TypeInfo::simplifyStdType()
+{
+ if (isStdType()) {
+ if (m_qualifiedName.at(1).startsWith(QLatin1String("__")))
+ m_qualifiedName.removeAt(1);
+ for (int t = m_instantiations.size() - 1; t >= 0; --t) {
+ if (m_instantiations.at(t).isStdType()) {
+ if (discardStdType(m_instantiations.at(t).m_qualifiedName.constLast()))
+ m_instantiations.removeAt(t);
+ else
+ m_instantiations[t].simplifyStdType();
+ }
+ }
+ }
}
#ifndef QT_NO_DEBUG_STREAM
@@ -292,8 +407,11 @@ void TypeInfo::formatDebug(QDebug &d) const
d << ", [const]";
if (m_volatile)
d << ", [volatile]";
- if (m_indirections)
- d << ", indirections=" << m_indirections;
+ if (!m_indirections.isEmpty()) {
+ d << ", indirections=";
+ for (auto i : m_indirections)
+ d << ' ' << TypeInfo::indirectionKeyword(i);
+ }
switch (m_referenceType) {
case NoReference:
break;
@@ -304,6 +422,11 @@ void TypeInfo::formatDebug(QDebug &d) const
d << ", [rvalref]";
break;
}
+ if (!m_instantiations.isEmpty()) {
+ d << ", template<";
+ formatSequence(d, m_instantiations.begin(), m_instantiations.end());
+ d << '>';
+ }
if (m_functionPointer) {
d << ", function ptr(";
formatSequence(d, m_arguments.begin(), m_arguments.end());
@@ -358,9 +481,7 @@ _CodeModelItem::_CodeModelItem(CodeModel *model, const QString &name, int kind)
{
}
-_CodeModelItem::~_CodeModelItem()
-{
-}
+_CodeModelItem::~_CodeModelItem() = default;
int _CodeModelItem::kind() const
{
@@ -532,9 +653,7 @@ QDebug operator<<(QDebug d, const _CodeModelItem *t)
#endif // !QT_NO_DEBUG_STREAM
// ---------------------------------------------------------------------------
-_ClassModelItem::~_ClassModelItem()
-{
-}
+_ClassModelItem::~_ClassModelItem() = default;
TemplateParameterList _ClassModelItem::templateParameters() const
{
@@ -624,9 +743,7 @@ FunctionModelItem _ScopeModelItem::declaredFunction(FunctionModelItem item)
return FunctionModelItem();
}
-_ScopeModelItem::~_ScopeModelItem()
-{
-}
+_ScopeModelItem::~_ScopeModelItem() = default;
void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration)
{
@@ -835,11 +952,9 @@ void _ArgumentModelItem::formatDebug(QDebug &d) const
}
#endif // !QT_NO_DEBUG_STREAM
// ---------------------------------------------------------------------------
-_FunctionModelItem::~_FunctionModelItem()
-{
-}
+_FunctionModelItem::~_FunctionModelItem() = default;
-bool _FunctionModelItem::isSimilar(FunctionModelItem other) const
+bool _FunctionModelItem::isSimilar(const FunctionModelItem &other) const
{
if (name() != other->name())
return false;
@@ -871,7 +986,7 @@ ArgumentList _FunctionModelItem::arguments() const
return m_arguments;
}
-void _FunctionModelItem::addArgument(ArgumentModelItem item)
+void _FunctionModelItem::addArgument(const ArgumentModelItem& item)
{
m_arguments.append(item);
}
@@ -896,6 +1011,21 @@ void _FunctionModelItem::setVariadics(bool isVariadics)
m_isVariadics = isVariadics;
}
+bool _FunctionModelItem::isNoExcept() const
+{
+ return m_exceptionSpecification == ExceptionSpecification::NoExcept;
+}
+
+ExceptionSpecification _FunctionModelItem::exceptionSpecification() const
+{
+ return m_exceptionSpecification;
+}
+
+void _FunctionModelItem::setExceptionSpecification(ExceptionSpecification e)
+{
+ m_exceptionSpecification = e;
+}
+
bool _FunctionModelItem::isDeleted() const
{
return m_isDeleted;
@@ -991,7 +1121,7 @@ void _FunctionModelItem::setInvokable(bool isInvokable)
void _FunctionModelItem::formatDebug(QDebug &d) const
{
_MemberModelItem::formatDebug(d);
- d << ", type=" << m_functionType;
+ d << ", type=" << m_functionType << ", exspec=" << int(m_exceptionSpecification);
if (m_isDeleted)
d << " [deleted!]";
if (m_isInline)
@@ -1091,9 +1221,7 @@ void _EnumModelItem::formatDebug(QDebug &d) const
#endif // !QT_NO_DEBUG_STREAM
// ---------------------------------------------------------------------------
-_EnumeratorModelItem::~_EnumeratorModelItem()
-{
-}
+_EnumeratorModelItem::~_EnumeratorModelItem() = default;
QString _EnumeratorModelItem::stringValue() const
{
@@ -1114,9 +1242,7 @@ void _EnumeratorModelItem::formatDebug(QDebug &d) const
#endif // !QT_NO_DEBUG_STREAM
// ---------------------------------------------------------------------------
-_TemplateParameterModelItem::~_TemplateParameterModelItem()
-{
-}
+_TemplateParameterModelItem::~_TemplateParameterModelItem() = default;
TypeInfo _TemplateParameterModelItem::type() const
{
@@ -1164,9 +1290,7 @@ CodeModel::AccessPolicy _MemberModelItem::accessPolicy() const
return m_accessPolicy;
}
-_MemberModelItem::~_MemberModelItem()
-{
-}
+_MemberModelItem::~_MemberModelItem() = default;
void _MemberModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy)
{
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h
index ac1fe26c1..7bd82bd1d 100644
--- a/sources/shiboken2/ApiExtractor/parser/codemodel.h
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h
@@ -36,6 +36,7 @@
#include "enumvalue.h"
#include <QtCore/QHash>
+#include <QtCore/QPair>
#include <QtCore/QSet>
#include <QtCore/QString>
#include <QtCore/QStringList>
@@ -100,6 +101,8 @@ class TypeInfo
{
friend class TypeParser;
public:
+ typedef QVector<Indirection> Indirections;
+
TypeInfo() : flags(0), m_referenceType(NoReference) {}
QStringList qualifiedName() const
@@ -137,14 +140,16 @@ public:
ReferenceType referenceType() const { return m_referenceType; }
void setReferenceType(ReferenceType r) { m_referenceType = r; }
- int indirections() const
- {
- return m_indirections;
- }
+ Indirections indirectionsV() const { return m_indirections; }
+ void setIndirectionsV(const Indirections &i) { m_indirections = i; }
+ void addIndirection(Indirection i) { m_indirections.append(i); }
+
+ // "Legacy", rename?
+ int indirections() const { return m_indirections.size(); }
void setIndirections(int indirections)
{
- m_indirections = indirections;
+ m_indirections = Indirections(indirections, Indirection::Pointer);
}
bool isFunctionPointer() const
@@ -165,6 +170,8 @@ public:
m_arrayElements = arrayElements;
}
+ void addArrayElement(const QString &a) { m_arrayElements.append(a); }
+
QVector<TypeInfo> arguments() const { return m_arguments; }
void setArguments(const QVector<TypeInfo> &arguments);
@@ -174,6 +181,15 @@ public:
m_arguments.append(arg);
}
+ QVector<TypeInfo> instantiations() const { return m_instantiations; }
+ void setInstantiations(const QVector<TypeInfo> &i) { m_instantiations = i; }
+ void addInstantiation(const TypeInfo &i) { m_instantiations.append(i); }
+ void clearInstantiations() { m_instantiations.clear(); }
+
+ bool isStdType() const;
+
+ QPair<int, int> parseTemplateArgumentList(const QString &l, int from = 0);
+
bool operator==(const TypeInfo &other) const;
bool operator!=(const TypeInfo &other) const
@@ -185,8 +201,6 @@ public:
QString toString() const;
- QStringList instantiationName() const;
-
static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs);
static TypeInfo resolveType(TypeInfo const &__type, CodeModelItem __scope);
@@ -194,12 +208,24 @@ public:
void formatDebug(QDebug &d) const;
#endif
+ static QString indirectionKeyword(Indirection i);
+
+ static bool stripLeadingConst(QString *s);
+ static bool stripLeadingVolatile(QString *s);
+ static bool stripLeadingQualifier(const QString &qualifier, QString *s);
+
+ void simplifyStdType();
+
private:
+ friend class TypeInfoTemplateArgumentHandler;
+
static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, CodeModelItem __scope);
QStringList m_qualifiedName;
QStringList m_arrayElements;
QVector<TypeInfo> m_arguments;
+ QVector<TypeInfo> m_instantiations;
+ Indirections m_indirections;
union {
uint flags;
@@ -208,8 +234,7 @@ private:
uint m_constant: 1;
uint m_volatile: 1;
uint m_functionPointer: 1;
- uint m_indirections: 6;
- uint m_padding: 23;
+ uint m_padding: 29;
};
};
@@ -547,7 +572,7 @@ public:
ArgumentList arguments() const;
- void addArgument(ArgumentModelItem item);
+ void addArgument(const ArgumentModelItem& item);
CodeModel::FunctionType functionType() const;
void setFunctionType(CodeModel::FunctionType functionType);
@@ -582,7 +607,13 @@ public:
bool isVariadics() const;
void setVariadics(bool isVariadics);
- bool isSimilar(FunctionModelItem other) const;
+
+ bool isSimilar(const FunctionModelItem &other) const;
+
+ bool isNoExcept() const;
+
+ ExceptionSpecification exceptionSpecification() const;
+ void setExceptionSpecification(ExceptionSpecification e);
#ifndef QT_NO_DEBUG_STREAM
void formatDebug(QDebug &d) const override;
@@ -606,6 +637,7 @@ private:
};
uint m_flags;
};
+ ExceptionSpecification m_exceptionSpecification = ExceptionSpecification::Unknown;
};
class _VariableModelItem: public _MemberModelItem
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h
index b8a10ba93..1713ba42f 100644
--- a/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h
@@ -41,4 +41,17 @@ enum EnumKind {
EnumClass // C++ 11 : enum class Foo { value1, value2 }
};
+enum class Indirection
+{
+ Pointer, // int *
+ ConstPointer // int *const
+};
+
+enum class ExceptionSpecification
+{
+ Unknown,
+ NoExcept,
+ Throws
+};
+
#endif // CODEMODEL_ENUMS_H
diff --git a/sources/shiboken2/ApiExtractor/parser/enumvalue.h b/sources/shiboken2/ApiExtractor/parser/enumvalue.h
index 4905e89ba..ea30c39bb 100644
--- a/sources/shiboken2/ApiExtractor/parser/enumvalue.h
+++ b/sources/shiboken2/ApiExtractor/parser/enumvalue.h
@@ -49,6 +49,7 @@ public:
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; }
void setValue(qint64 v);
void setUnsignedValue(quint64 v);
diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.cpp b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
index b0058d6ea..809760450 100644
--- a/sources/shiboken2/ApiExtractor/qtdocparser.cpp
+++ b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
@@ -28,6 +28,7 @@
#include "qtdocparser.h"
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typesystem.h"
diff --git a/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt
index 860a37d9d..e100ef493 100644
--- a/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt
+++ b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt
@@ -4,13 +4,18 @@ find_package(Qt5Test)
find_package(Qt5Xml)
find_package(Qt5XmlPatterns)
+set(CMAKE_AUTORCC ON)
+
macro(declare_test testname)
# gone: qt4_automoc("${testname}.cpp")
- if (EXISTS "${testname}.h")
- add_executable(${testname} "${testname}.h ${testname}.cpp")
- else ()
- add_executable(${testname} "${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})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${apiextractor_SOURCE_DIR}
@@ -35,8 +40,6 @@ declare_test(testabstractmetatype)
declare_test(testaddfunction)
declare_test(testarrayargument)
declare_test(testcodeinjection)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/utf8code.txt"
- "${CMAKE_CURRENT_BINARY_DIR}/utf8code.txt" COPYONLY)
declare_test(testcontainer)
declare_test(testconversionoperator)
declare_test(testconversionruletag)
@@ -68,7 +71,5 @@ declare_test(testvoidarg)
declare_test(testtyperevision)
if (NOT DISABLE_DOCSTRINGS)
declare_test(testmodifydocumentation)
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/a.xml"
- "${CMAKE_CURRENT_BINARY_DIR}/a.xml" COPYONLY)
endif()
diff --git a/sources/shiboken2/ApiExtractor/tests/injectedcode.txt b/sources/shiboken2/ApiExtractor/tests/injectedcode.txt
new file mode 100644
index 000000000..872898810
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/injectedcode.txt
@@ -0,0 +1,5 @@
+// Bla
+// @snippet label
+code line
+// @snippet label
+// Bla
diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp
index 7f1361a7d..fc67ebba5 100644
--- a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp
@@ -31,6 +31,37 @@
#include "testutil.h"
#include <abstractmetalang.h>
#include <typesystem.h>
+#include <parser/codemodel.h>
+#include <typeparser.h>
+
+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()
{
@@ -72,7 +103,8 @@ void TestAbstractMetaType::testApiVersionSupported()
<function signature='justAtest2()' since='1.1'/>\n\
<function signature='justAtest3()'/>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "1.0"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, QLatin1String("1.0")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
@@ -90,7 +122,8 @@ void TestAbstractMetaType::testApiVersionNotSupported()
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, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h
index b2aa7544f..b39a27a54 100644
--- a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h
+++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h
@@ -35,6 +35,8 @@ class TestAbstractMetaType : public QObject
{
Q_OBJECT
private slots:
+ void parsing_data();
+ void parsing();
void testConstCharPtrType();
void testCharType();
void testTypedef();
diff --git a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
index 2a953243e..db49942c9 100644
--- a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
@@ -366,7 +366,8 @@ void TestAddFunction::testAddFunctionWithApiVersion()
<inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
</add-function>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaFunctionList globalFuncs = builder->globalFunctions();
QCOMPARE(globalFuncs.count(), 1);
diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
index 7bbde3bd4..9f71b495a 100644
--- a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
@@ -34,19 +34,43 @@
#include <abstractmetalang.h>
#include <typesystem.h>
-void TestCodeInjections::testReadFileUtf8()
+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[] = {NULL};
QCoreApplication app(argc, argv);
- QString filePath = QDir::currentPath();
+
+ QString attribute = QLatin1String("file='") + filePath + QLatin1Char('\'');
+ if (!snippet.isEmpty())
+ attribute += QLatin1String(" snippet='") + snippet + QLatin1Char('\'');
+
QString xmlCode = QLatin1String("\
<typesystem package=\"Foo\">\n\
<value-type name='A'>\n\
- <conversion-rule file='") + filePath + QLatin1String("/utf8code.txt'/>\n\
- <inject-code class='target' file='") + filePath
- + QLatin1String("/utf8code.txt'/>\n\
+ <conversion-rule ") + attribute + QLatin1String("/>\n\
+ <inject-code class='target' ") + attribute + QLatin1String("/>\n\
</value-type>\n\
<value-type name='A::B'/>\n\
</typesystem>\n");
@@ -56,10 +80,9 @@ void TestCodeInjections::testReadFileUtf8()
const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
QCOMPARE(classA->typeEntry()->codeSnips().count(), 1);
QString code = classA->typeEntry()->codeSnips().first().code();
- QString utf8Data = QString::fromUtf8("\xC3\xA1\xC3\xA9\xC3\xAD\xC3\xB3\xC3\xBA");
- QVERIFY(code.indexOf(utf8Data) != -1);
+ QVERIFY(code.indexOf(expected) != -1);
code = classA->typeEntry()->conversionRule();
- QVERIFY(code.indexOf(utf8Data) != -1);
+ QVERIFY(code.indexOf(expected) != -1);
}
void TestCodeInjections::testInjectWithValidApiVersion()
@@ -74,7 +97,8 @@ void TestCodeInjections::testInjectWithValidApiVersion()
</value-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "1.0"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("1.0")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
@@ -93,7 +117,8 @@ void TestCodeInjections::testInjectWithInvalidApiVersion()
</value-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h
index bd5e7ece1..1ac873970 100644
--- a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h
+++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h
@@ -37,7 +37,8 @@ class TestCodeInjections : public QObject
{
Q_OBJECT
private slots:
- void testReadFileUtf8();
+ void testReadFile_data();
+ void testReadFile();
void testInjectWithValidApiVersion();
void testInjectWithInvalidApiVersion();
};
diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.qrc b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.qrc
new file mode 100644
index 000000000..fd7616bd2
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource>
+ <file>utf8code.txt</file>
+ <file>injectedcode.txt</file>
+ </qresource>
+</RCC>
diff --git a/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp
index b46c23f56..6abebb922 100644
--- a/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp
@@ -70,7 +70,8 @@ void TestDropTypeEntries::testDropEntries()
droppedEntries << QLatin1String("Foo.ObjectB") << QLatin1String("Foo.NamespaceA.InnerClassA");
droppedEntries << QLatin1String("Foo.NamespaceB") << QLatin1String("Foo.EnumB") << QLatin1String("Foo.funcB()");
droppedEntries << QLatin1String("Foo.NamespaceA.InnerNamespaceA");
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, Q_NULLPTR, droppedEntries));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false,
+ QString(), droppedEntries));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
@@ -129,7 +130,8 @@ static const char* xmlCode2 = "\
void TestDropTypeEntries::testDropEntryWithChildTags()
{
QStringList droppedEntries(QLatin1String("Foo.ValueA"));
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false, Q_NULLPTR, droppedEntries));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false,
+ QString(), droppedEntries));
QVERIFY(!builder.isNull());
QVERIFY(!AbstractMetaClass::findClass(builder->classes(), QLatin1String("ValueA")));
}
diff --git a/sources/shiboken2/ApiExtractor/tests/testenum.cpp b/sources/shiboken2/ApiExtractor/tests/testenum.cpp
index 87f2608a1..ebdcf8d81 100644
--- a/sources/shiboken2/ApiExtractor/tests/testenum.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testenum.cpp
@@ -104,7 +104,8 @@ void TestEnum::testEnumWithApiVersion()
</value-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
QCOMPARE(classes.count(), 1);
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
index 7911a5eb1..f615befb4 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
@@ -60,7 +60,7 @@ R"(<typesystem package="Foo">
QCOMPARE(docMods[1].code().trimmed(), QLatin1String("<para>Some changed contents here</para>"));
QCOMPARE(docMods[1].signature(), QString());
QtDocParser docParser;
- docParser.setDocumentationDataDirectory(QDir::currentPath());
+ docParser.setDocumentationDataDirectory(QLatin1String(":"));
docParser.fillDocumentation(classA);
const QString actualDocSimplified = classA->documentation().value().simplified();
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.qrc b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.qrc
new file mode 100644
index 000000000..76b1bfc61
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource>
+ <file>a.xml</file>
+ </qresource>
+</RCC>
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
index d0a0c9c7a..af24689fe 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
@@ -136,7 +136,8 @@ void TestModifyFunction::invalidateAfterUse()
</object-type>\n\
<object-type name='E' />\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
@@ -208,7 +209,8 @@ void TestModifyFunction::testWithApiVersion()
</modify-function>\n\
</object-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
@@ -220,6 +222,61 @@ void TestModifyFunction::testWithApiVersion()
QVERIFY(func->ownership(func->ownerClass(), TypeSystem::TargetLangCode, 0) != TypeSystem::CppOwnership);
}
+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, QLatin1String("0.1")));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+
+ // Nothing specified, true
+ const AbstractMetaFunction *f1 = classA->findFunction(QLatin1String("f1"));
+ QVERIFY(f1);
+ QVERIFY(f1->allowThread());
+
+ // 'auto' specified, should be true for nontrivial function
+ const AbstractMetaFunction *f2 = classA->findFunction(QLatin1String("f2"));
+ QVERIFY(f2);
+ QVERIFY(f2->allowThread());
+
+ // 'no' specified, should be false
+ const AbstractMetaFunction *f3 = classA->findFunction(QLatin1String("f3"));
+ QVERIFY(f3);
+ QVERIFY(!f3->allowThread());
+
+ // Nothing specified, should be false for simple getter
+ const AbstractMetaFunction *getter1 = classA->findFunction(QLatin1String("getter1"));
+ QVERIFY(getter1);
+ QVERIFY(!getter1->allowThread());
+
+ // Forced to true simple getter
+ const AbstractMetaFunction *getter2 = classA->findFunction(QLatin1String("getter2"));
+ QVERIFY(getter2);
+ QVERIFY(getter2->allowThread()); // Forced to true simple getter
+}
+
void TestModifyFunction::testGlobalFunctionModification()
{
const char* cppCode ="\
@@ -258,4 +315,42 @@ void TestModifyFunction::testGlobalFunctionModification()
QCOMPARE(arg->defaultValueExpression(), QLatin1String("A()"));
}
+void TestModifyFunction::testExceptionSpecification()
+{
+ const char cppCode[] = R"CPP(
+struct A {
+ void unspecified();
+ void nonThrowing() noexcept;
+ void throwing() throw(int);
+};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <primitive-type name='int'/>
+ <object-type name='A'>
+ <modify-function signature='throwing()' exception-handling='auto-on'/>
+ </object-type>
+</typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A"));
+ QVERIFY(classA);
+
+ const AbstractMetaFunction *f = classA->findFunction(QStringLiteral("unspecified"));
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Unknown);
+ QVERIFY(!f->generateExceptionHandling());
+
+ f = classA->findFunction(QStringLiteral("nonThrowing"));
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::NoExcept);
+ QVERIFY(!f->generateExceptionHandling());
+
+ f = classA->findFunction(QStringLiteral("throwing"));
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Throws);
+ QVERIFY(f->generateExceptionHandling());
+}
+
QTEST_APPLESS_MAIN(TestModifyFunction)
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
index f116b5124..494f31991 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
@@ -37,10 +37,12 @@ class TestModifyFunction : public QObject
private slots:
void testOwnershipTransfer();
void testWithApiVersion();
+ void testAllowThread();
void testRenameArgument_data();
void testRenameArgument();
void invalidateAfterUse();
void testGlobalFunctionModification();
+ void testExceptionSpecification();
};
#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp
index 11cda3317..38099c455 100644
--- a/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp
@@ -82,7 +82,8 @@ void TestRefCountTag::testWithApiVersion()
</object-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
index 8d869e3f9..b1b171bae 100644
--- a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
@@ -28,6 +28,7 @@
#include "testtemplates.h"
#include <QtTest/QTest>
+#include <QtCore/QTextStream>
#include <QTemporaryFile>
#include "testutil.h"
#include <abstractmetalang.h>
@@ -438,4 +439,122 @@ typedef Vector<int> IntVector;
QCOMPARE(otherMethod->type()->cppSignature(), QLatin1String("Vector<int >"));
}
+// 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.isNull());
+ AbstractMetaClassList classes = builder->classes();
+
+ const AbstractMetaClass *optional = AbstractMetaClass::findClass(classes, QLatin1String("Optional"));
+ QVERIFY(optional);
+
+ // Find the typedef'ed class
+ const AbstractMetaClass *optionalInt =
+ AbstractMetaClass::findClass(classes, QLatin1String("IntOptional"));
+ QVERIFY(optionalInt);
+ QCOMPARE(optionalInt->templateBaseClass(), optional);
+
+ // Find the class typedef'ed in the typesystem XML
+ const AbstractMetaClass *xmlOptionalInt =
+ AbstractMetaClass::findClass(classes, QLatin1String("XmlIntOptional"));
+ QVERIFY(xmlOptionalInt);
+ QCOMPARE(xmlOptionalInt->templateBaseClass(), optional);
+
+ // Check whether the value() method now has an 'int' return
+ const AbstractMetaFunction *valueMethod =
+ optionalInt->findFunction(QLatin1String("value"));
+ QVERIFY(valueMethod);
+ QCOMPARE(valueMethod->type()->cppSignature(), QLatin1String("int"));
+
+ // ditto for typesystem XML
+ const AbstractMetaFunction *xmlValueMethod =
+ xmlOptionalInt->findFunction(QLatin1String("value"));
+ QVERIFY(xmlValueMethod);
+ QCOMPARE(xmlValueMethod->type()->cppSignature(), QLatin1String("int"));
+
+ // Check whether the m_value field is of type 'int'
+ const AbstractMetaField *valueField =
+ optionalInt->findField(QLatin1String("m_value"));
+ QVERIFY(valueField);
+ QCOMPARE(valueField->type()->cppSignature(), QLatin1String("int"));
+
+ // ditto for typesystem XML
+ const AbstractMetaField *xmlValueField =
+ xmlOptionalInt->findField(QLatin1String("m_value"));
+ QVERIFY(xmlValueField);
+ QCOMPARE(xmlValueField->type()->cppSignature(), QLatin1String("int"));
+}
+
QTEST_APPLESS_MAIN(TestTemplates)
diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.h b/sources/shiboken2/ApiExtractor/tests/testtemplates.h
index 3e1565933..df3de18b9 100644
--- a/sources/shiboken2/ApiExtractor/tests/testtemplates.h
+++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.h
@@ -46,6 +46,8 @@ private slots:
void testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration();
void testTypedefOfInstantiationOfTemplateClass();
void testContainerTypeIncompleteArgument();
+ void testTemplateTypeDefs_data();
+ void testTemplateTypeDefs();
};
#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp
index 1ec7ce025..a7e88e437 100644
--- a/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp
@@ -31,6 +31,7 @@
#include "testutil.h"
#include <abstractmetalang.h>
#include <typesystem.h>
+#include <typedatabase.h>
void TestTypeRevision::testRevisionAttr()
{
@@ -49,21 +50,55 @@ void TestTypeRevision::testRevisionAttr()
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
const AbstractMetaClass *rev0 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_0"));
- QCOMPARE(getTypeRevision(rev0->typeEntry()), 0);
+ QCOMPARE(rev0->typeEntry()->revision(), 0);
const AbstractMetaClass *rev1 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_1"));
- QCOMPARE(getTypeRevision(rev1->typeEntry()), 1);
+ QCOMPARE(rev1->typeEntry()->revision(), 1);
AbstractMetaClass *rev2 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_2"));
- QCOMPARE(getTypeRevision(rev2->typeEntry()), 2);
+ QCOMPARE(rev2->typeEntry()->revision(), 2);
AbstractMetaEnum* rev3 = rev2->findEnum(QLatin1String("Rev_3"));
- QCOMPARE(getTypeRevision(rev3->typeEntry()), 3);
+ QCOMPARE(rev3->typeEntry()->revision(), 3);
FlagsTypeEntry* rev4 = rev3->typeEntry()->flags();
- QCOMPARE(getTypeRevision(rev4), 4);
+ QCOMPARE(rev4->revision(), 4);
AbstractMetaEnum* rev5 = rev2->findEnum(QLatin1String("Rev_5"));
- QCOMPARE(getTypeRevision(rev5->typeEntry()), 5);
- QCOMPARE(getTypeRevision(rev5->typeEntry()->flags()), 5);
+ const EnumTypeEntry *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;
+}
+
+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"/>
+ <value-type name="Bar20" since="2.0"/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, version));
+ QVERIFY(!builder.isNull());
+
+ QCOMPARE(builder->classes().size(), expectedClassCount);
}
QTEST_APPLESS_MAIN(TestTypeRevision)
diff --git a/sources/shiboken2/ApiExtractor/tests/testtyperevision.h b/sources/shiboken2/ApiExtractor/tests/testtyperevision.h
index 4dfa241e3..3832c3883 100644
--- a/sources/shiboken2/ApiExtractor/tests/testtyperevision.h
+++ b/sources/shiboken2/ApiExtractor/tests/testtyperevision.h
@@ -37,6 +37,8 @@ class TestTypeRevision : public QObject
private slots:
void testRevisionAttr();
+ void testVersion_data();
+ void testVersion();
};
#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testutil.h b/sources/shiboken2/ApiExtractor/tests/testutil.h
index 6152793f5..c6ad19d7e 100644
--- a/sources/shiboken2/ApiExtractor/tests/testutil.h
+++ b/sources/shiboken2/ApiExtractor/tests/testutil.h
@@ -40,20 +40,23 @@ namespace TestUtil
{
static AbstractMetaBuilder *parse(const char *cppCode, const char *xmlCode,
bool silent = true,
- const char *apiVersion = Q_NULLPTR,
+ const QString &apiVersion = QString(),
const QStringList &dropTypeEntries = QStringList())
{
ReportHandler::setSilent(silent);
TypeDatabase* td = TypeDatabase::instance(true);
- if (apiVersion && !td->setApiVersion(QLatin1String("*"), QLatin1String(apiVersion)))
- return Q_NULLPTR;
+ if (apiVersion.isEmpty())
+ TypeDatabase::clearApiVersions();
+ else if (!td->setApiVersion(QLatin1String("*"), apiVersion))
+ return nullptr;
td->setDropTypeEntries(dropTypeEntries);
QBuffer buffer;
// parse typesystem
buffer.setData(xmlCode);
if (!buffer.open(QIODevice::ReadOnly))
return Q_NULLPTR;
- td->parseFile(&buffer);
+ if (!td->parseFile(&buffer))
+ return nullptr;
buffer.close();
// parse C++ code
QTemporaryFile tempSource(QDir::tempPath() + QLatin1String("/st_XXXXXX_main.cpp"));
diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp
index 9529de40a..4cb6cdd8a 100644
--- a/sources/shiboken2/ApiExtractor/typedatabase.cpp
+++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp
@@ -166,64 +166,66 @@ ContainerTypeEntry* TypeDatabase::findContainerType(const QString &name) const
return 0;
}
-FunctionTypeEntry* TypeDatabase::findFunctionType(const QString& name) const
+static bool inline useType(const TypeEntry *t)
{
- TypeEntry* entry = findType(name);
- if (entry && entry->type() == TypeEntry::FunctionType)
- return static_cast<FunctionTypeEntry*>(entry);
- return 0;
+ return !t->isPrimitive()
+ || static_cast<const PrimitiveTypeEntry *>(t)->preferredTargetLangType();
}
-TypeEntry* TypeDatabase::findType(const QString& name) const
+FunctionTypeEntry* TypeDatabase::findFunctionType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry &&
- (!entry->isPrimitive() || static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())) {
- return entry;
- }
+ if (entry->type() == TypeEntry::FunctionType && useType(entry))
+ return static_cast<FunctionTypeEntry*>(entry);
}
return 0;
}
-TypeEntryList TypeDatabase::findTypes(const QString &name) const
+const TypeSystemTypeEntry *TypeDatabase::findTypeSystemType(const QString &name) const
{
- return m_entries.value(name);
+ const auto entries = findTypes(name);
+ for (const TypeEntry *entry : entries) {
+ if (entry->type() == TypeEntry::TypeSystemType)
+ return static_cast<const TypeSystemTypeEntry *>(entry);
+ }
+ return nullptr;
}
-SingleTypeEntryHash TypeDatabase::entries() const
+TypeEntry* TypeDatabase::findType(const QString& name) const
{
- TypeEntryHash entries = allEntries();
-
- SingleTypeEntryHash returned;
- for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it)
- returned.insert(it.key(), findType(it.key()));
+ const auto entries = findTypes(name);
+ for (TypeEntry *entry : entries) {
+ if (useType(entry))
+ return entry;
+ }
+ return nullptr;
+}
- return returned;
+TypeEntryMultiMapConstIteratorRange TypeDatabase::findTypes(const QString &name) const
+{
+ const auto range = m_entries.equal_range(name);
+ return {range.first, range.second};
}
PrimitiveTypeEntryList TypeDatabase::primitiveTypes() const
{
- TypeEntryHash entries = allEntries();
PrimitiveTypeEntryList returned;
- for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
- for (TypeEntry *typeEntry : it.value()) {
- if (typeEntry->isPrimitive())
- returned.append(static_cast<PrimitiveTypeEntry *>(typeEntry));
- }
+ for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it) {
+ TypeEntry *typeEntry = it.value();
+ if (typeEntry->isPrimitive())
+ returned.append(static_cast<PrimitiveTypeEntry *>(typeEntry));
}
return returned;
}
ContainerTypeEntryList TypeDatabase::containerTypes() const
{
- TypeEntryHash entries = allEntries();
ContainerTypeEntryList returned;
- for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
- for (TypeEntry *typeEntry : it.value()) {
- if (typeEntry->isContainer())
- returned.append(static_cast<ContainerTypeEntry *>(typeEntry));
- }
+ for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it) {
+ TypeEntry *typeEntry = it.value();
+ if (typeEntry->isContainer())
+ returned.append(static_cast<ContainerTypeEntry *>(typeEntry));
}
return returned;
}
@@ -263,6 +265,8 @@ static inline QString msgRejectReason(const TypeRejection &r, const QString &nee
str << " matches class \"" << r.className.pattern() << "\" and \"" << needle
<< "\" matches \"" << r.pattern.pattern() << '"';
break;
+ case TypeRejection::Invalid:
+ break;
}
return result;
}
@@ -303,9 +307,52 @@ bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumN
return findRejection(m_rejections, TypeRejection::Enum, className, enumName, reason);
}
-void TypeDatabase::addType(TypeEntry *e)
+TypeEntry *TypeDatabase::resolveTypeDefEntry(TypedefEntry *typedefEntry,
+ QString *errorMessage)
+{
+ QString sourceName = typedefEntry->sourceType();
+ const int lessThanPos = sourceName.indexOf(QLatin1Char('<'));
+ if (lessThanPos != -1)
+ sourceName.truncate(lessThanPos);
+ ComplexTypeEntry *source = nullptr;
+ for (TypeEntry *e : findTypes(sourceName)) {
+ switch (e->type()) {
+ case TypeEntry::BasicValueType:
+ case TypeEntry::ContainerType:
+ case TypeEntry::InterfaceType:
+ case TypeEntry::ObjectType:
+ case TypeEntry::SmartPointerType:
+ source = dynamic_cast<ComplexTypeEntry *>(e);
+ Q_ASSERT(source);
+ break;
+ default:
+ break;
+ }
+ }
+ if (!source) {
+ if (errorMessage)
+ *errorMessage = QLatin1String("Unable to resolve typedef \"")
+ + typedefEntry->sourceType() + QLatin1Char('"');
+ return nullptr;
+ }
+
+ ComplexTypeEntry *result = static_cast<ComplexTypeEntry *>(source->clone());
+ result->useAsTypedef(typedefEntry);
+ typedefEntry->setSource(source);
+ typedefEntry->setTarget(result);
+ m_typedefEntries.insert(typedefEntry->qualifiedCppName(), typedefEntry);
+ return result;
+}
+
+bool TypeDatabase::addType(TypeEntry *e, QString *errorMessage)
{
- m_entries[e->qualifiedCppName()].append(e);
+ if (e->type() == TypeEntry::TypedefType) {
+ e = resolveTypeDefEntry(static_cast<TypedefEntry *>(e), errorMessage);
+ if (Q_UNLIKELY(!e))
+ return false;
+ }
+ m_entries.insert(e->qualifiedCppName(), e);
+ return true;
}
bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName,
@@ -339,7 +386,7 @@ FlagsTypeEntry* TypeDatabase::findFlagsType(const QString &name) const
fte = m_flagsEntries.value(name);
if (!fte) {
//last hope, search for flag without scope inside of flags hash
- for (SingleTypeEntryHash::const_iterator it = m_flagsEntries.cbegin(), end = m_flagsEntries.cend(); it != end; ++it) {
+ for (auto it = m_flagsEntries.cbegin(), end = m_flagsEntries.cend(); it != end; ++it) {
if (it.key().endsWith(name)) {
fte = it.value();
break;
@@ -427,12 +474,13 @@ bool TypeDatabase::addSuppressedWarning(const QString &warning, QString *errorMe
pattern.append(QLatin1Char('$'));
}
- const QRegularExpression expression(pattern);
+ QRegularExpression expression(pattern);
if (!expression.isValid()) {
*errorMessage = QLatin1String("Invalid message pattern \"") + warning
+ QLatin1String("\": ") + expression.errorString();
return false;
}
+ expression.setPatternOptions(expression.patternOptions() | QRegularExpression::MultilineOption);
m_suppressedWarnings.append(expression);
return true;
@@ -518,16 +566,21 @@ bool TypeDatabase::parseFile(QIODevice* device, bool generate)
{
QXmlStreamReader reader(device);
Handler handler(this, generate);
- return handler.parse(reader);
+ const bool result = handler.parse(reader);
+ if (!result)
+ qCWarning(lcShiboken, "%s", qPrintable(handler.errorString()));
+ return result;
}
PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
-
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry && entry->isPrimitive() && static_cast<PrimitiveTypeEntry*>(entry)->preferredTargetLangType())
- return static_cast<PrimitiveTypeEntry*>(entry);
+ if (entry->isPrimitive()) {
+ PrimitiveTypeEntry *pe = static_cast<PrimitiveTypeEntry *>(entry);
+ if (pe->preferredTargetLangType())
+ return pe;
+ }
}
return 0;
@@ -535,9 +588,9 @@ PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString& name) const
ComplexTypeEntry* TypeDatabase::findComplexType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry && entry->isComplex())
+ if (entry->isComplex() && useType(entry))
return static_cast<ComplexTypeEntry*>(entry);
}
return 0;
@@ -545,9 +598,9 @@ ComplexTypeEntry* TypeDatabase::findComplexType(const QString& name) const
ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry && entry->isObject())
+ if (entry && entry->isObject() && useType(entry))
return static_cast<ObjectTypeEntry*>(entry);
}
return 0;
@@ -555,9 +608,9 @@ ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const
NamespaceTypeEntry* TypeDatabase::findNamespaceType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry && entry->isNamespace())
+ if (entry->isNamespace() && useType(entry))
return static_cast<NamespaceTypeEntry*>(entry);
}
return 0;
@@ -574,75 +627,64 @@ void TypeDatabase::setDropTypeEntries(QStringList dropTypeEntries)
m_dropTypeEntries.sort();
}
-// Using std::pair to save some memory
-// the pair means (revision, typeIndex)
-// This global variable exists only because we can't break the ABI
-typedef QHash<const TypeEntry*, std::pair<int, int> > TypeRevisionMap;
-Q_GLOBAL_STATIC(TypeRevisionMap, typeEntryFields);
static bool computeTypeIndexes = true;
static int maxTypeIndex;
-int getTypeRevision(const TypeEntry* typeEntry)
+static bool typeEntryLessThan(const TypeEntry* t1, const TypeEntry* t2)
{
- return typeEntryFields()->value(typeEntry).first;
-}
-
-void setTypeRevision(TypeEntry* typeEntry, int revision)
-{
- (*typeEntryFields())[typeEntry].first = revision;
- computeTypeIndexes = true;
-}
-
-static bool compareTypeEntriesByName(const TypeEntry* t1, const TypeEntry* t2)
-{
- return t1->qualifiedCppName() < t2->qualifiedCppName();
+ if (t1->revision() < t2->revision())
+ return true;
+ return t1->revision() == t2->revision()
+ && t1->qualifiedCppName() < t2->qualifiedCppName();
}
static void _computeTypeIndexes()
{
TypeDatabase* tdb = TypeDatabase::instance();
- typedef QMap<int, TypeEntryList> GroupedTypeEntries;
- GroupedTypeEntries groupedEntries;
+
+ TypeEntryList list;
// Group type entries by revision numbers
- const TypeEntryHash &allEntries = tdb->allEntries();
- for (TypeEntryHash::const_iterator tit = allEntries.cbegin(), end = allEntries.cend(); tit != end; ++tit) {
- for (TypeEntry *entry : tit.value()) {
- if (entry->isPrimitive()
- || entry->isContainer()
- || entry->isFunction()
- || !entry->generateCode()
- || entry->isEnumValue()
- || entry->isVarargs()
- || entry->isTypeSystem()
- || entry->isVoid()
- || entry->isCustom())
- continue;
- groupedEntries[getTypeRevision(entry)] << entry;
- }
- }
+ const auto &allEntries = tdb->entries();
+ list.reserve(allEntries.size());
+ for (auto tit = allEntries.cbegin(), end = allEntries.cend(); tit != end; ++tit) {
+ TypeEntry *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;
- GroupedTypeEntries::iterator it = groupedEntries.begin();
- for (; it != groupedEntries.end(); ++it) {
- // Remove duplicates
- TypeEntryList::iterator newEnd = std::unique(it.value().begin(), it.value().end());
- it.value().erase(newEnd, it.value().end());
- // Sort the type entries by name
- qSort(it.value().begin(), newEnd, compareTypeEntriesByName);
-
- for (TypeEntry *entry : qAsConst(it.value())) {
- (*typeEntryFields())[entry].second = maxTypeIndex++;
- }
- }
+ for (TypeEntry *e : qAsConst(list))
+ e->setSbkIndex(maxTypeIndex++);
computeTypeIndexes = false;
}
-int getTypeIndex(const TypeEntry* typeEntry)
+void TypeEntry::setRevision(int r)
+{
+ if (m_revision != r) {
+ m_revision = r;
+ computeTypeIndexes = true;
+ }
+}
+
+int TypeEntry::sbkIndex() const
{
if (computeTypeIndexes)
_computeTypeIndexes();
- return typeEntryFields()->value(typeEntry).second;
+ return m_sbkIndex;
}
int getMaxTypeIndex()
@@ -652,6 +694,11 @@ int getMaxTypeIndex()
return maxTypeIndex;
}
+void TypeDatabase::clearApiVersions()
+{
+ apiVersions()->clear();
+}
+
bool TypeDatabase::setApiVersion(const QString& packageWildcardPattern, const QString &version)
{
const QString packagePattern = wildcardToRegExp(packageWildcardPattern.trimmed());
@@ -673,9 +720,11 @@ bool TypeDatabase::setApiVersion(const QString& packageWildcardPattern, const QS
}
bool TypeDatabase::checkApiVersion(const QString &package,
- const QVersionNumber &versionNumber) const
+ const QVersionNumber &versionNumber)
{
const ApiVersions &versions = *apiVersions();
+ if (versions.isEmpty()) // Nothing specified: use latest.
+ return true;
for (int i = 0, size = versions.size(); i < size; ++i) {
if (versions.at(i).first.match(package).hasMatch())
return versions.at(i).second >= versionNumber;
@@ -684,33 +733,104 @@ bool TypeDatabase::checkApiVersion(const QString &package,
}
#ifndef QT_NO_DEBUG_STREAM
+
+#define FORMAT_BOOL(name, var) \
+ if (var) \
+ d << ", [" << name << ']';
+
+#define FORMAT_NONEMPTY_STRING(name, var) \
+ if (!var.isEmpty()) \
+ d << ", " << name << "=\"" << var << '"';
+
+#define FORMAT_LIST_SIZE(name, var) \
+ if (!var.isEmpty()) \
+ d << ", " << var.size() << ' ' << name;
+
+void TypeEntry::formatDebug(QDebug &d) const
+{
+ const QString cppName = qualifiedCppName();
+ d << '"' << m_name << '"';
+ if (m_name != cppName)
+ d << "\", cppName=\"" << cppName << '"';
+ d << ", type=" << m_type << ", codeGeneration=0x"
+ << hex << m_codeGeneration << dec;
+ FORMAT_NONEMPTY_STRING("package", m_targetLangPackage)
+ FORMAT_BOOL("stream", m_stream)
+ FORMAT_LIST_SIZE("codeSnips", m_codeSnips)
+ FORMAT_NONEMPTY_STRING("conversionRule", m_conversionRule)
+ if (!m_version.isNull() && m_version > QVersionNumber(0, 0))
+ d << ", version=" << m_version;
+ if (m_revision)
+ d << ", revision=" << m_revision;
+ if (m_sbkIndex)
+ d << ", sbkIndex=" << m_sbkIndex;
+ if (m_include.isValid())
+ d << ", include=" << m_include;
+ if (const int count = m_extraIncludes.size()) {
+ d << ", extraIncludes[" << count << "]=";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ d << ", ";
+ d << m_extraIncludes.at(i);
+ }
+ }
+}
+
+void ComplexTypeEntry::formatDebug(QDebug &d) const
+{
+ TypeEntry::formatDebug(d);
+ FORMAT_NONEMPTY_STRING("targetLangName", m_targetLangName)
+ FORMAT_BOOL("QObject", m_qobject)
+ FORMAT_BOOL("polymorphicBase", m_polymorphicBase)
+ FORMAT_BOOL("genericClass", m_genericClass)
+ FORMAT_BOOL("deleteInMainThread", m_deleteInMainThread)
+ if (m_typeFlags != 0)
+ d << ", typeFlags=" << m_typeFlags;
+ d << ", copyableFlag=" << m_copyableFlag
+ << ", except=" << int(m_exceptionHandling);
+ FORMAT_NONEMPTY_STRING("defaultSuperclass", m_defaultSuperclass)
+ FORMAT_NONEMPTY_STRING("polymorphicIdValue", m_polymorphicIdValue)
+ FORMAT_NONEMPTY_STRING("lookupName", m_lookupName)
+ FORMAT_NONEMPTY_STRING("targetType", m_targetType)
+ FORMAT_NONEMPTY_STRING("hash", m_hashFunction)
+ FORMAT_LIST_SIZE("addedFunctions", m_addedFunctions)
+ FORMAT_LIST_SIZE("functionMods", m_functionMods)
+ FORMAT_LIST_SIZE("fieldMods", m_fieldMods)
+}
+
+void TypedefEntry::formatDebug(QDebug &d) const
+{
+ ComplexTypeEntry::formatDebug(d);
+ d << ", sourceType=\"" << m_sourceType << '"'
+ << ", source=" << m_source << ", target=" << m_target;
+}
+
+void EnumTypeEntry::formatDebug(QDebug &d) const
+{
+ TypeEntry::formatDebug(d);
+ FORMAT_NONEMPTY_STRING("package", m_packageName)
+ FORMAT_NONEMPTY_STRING("qualifier", m_qualifier)
+ FORMAT_NONEMPTY_STRING("targetLangName", m_targetLangName)
+ if (m_flags)
+ d << ", flags=(" << m_flags << ')';
+}
+
+void ContainerTypeEntry::formatDebug(QDebug &d) const
+{
+ ComplexTypeEntry::formatDebug(d);
+ d << ", type=" << m_type << ",\"" << typeName() << '"';
+}
+
QDebug operator<<(QDebug d, const TypeEntry *te)
{
QDebugStateSaver saver(d);
d.noquote();
d.nospace();
d << "TypeEntry(";
- if (te) {
- const QString name = te->name();
- const QString cppName = te->qualifiedCppName();
- d << '"' << name << '"';
- if (name != cppName)
- d << "\", cppName=\"" << cppName << '"';
- d << ", type=" << te->type();
- if (te->include().isValid())
- d << ", include=" << te->include();
- const IncludeList &extraIncludes = te->extraIncludes();
- if (const int count = extraIncludes.size()) {
- d << ", extraIncludes[" << count << "]=";
- for (int i = 0; i < count; ++i) {
- if (i)
- d << ", ";
- d << extraIncludes.at(i);
- }
- }
- } else {
+ if (te)
+ te->formatDebug(d);
+ else
d << '0';
- }
d << ')';
return d;
}
@@ -732,25 +852,14 @@ QDebug operator<<(QDebug d, const TemplateEntry *te)
void TypeDatabase::formatDebug(QDebug &d) const
{
- typedef TypeEntryHash::ConstIterator Eit;
- typedef SingleTypeEntryHash::ConstIterator Sit;
- typedef TemplateEntryHash::ConstIterator TplIt;
d << "TypeDatabase("
<< "entries[" << m_entries.size() << "]=";
- for (Eit it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it) {
- const int count = it.value().size();
- d << '"' << it.key() << "\" [" << count << "]: (";
- for (int t = 0; t < count; ++t) {
- if (t)
- d << ", ";
- d << it.value().at(t);
- }
- d << ")\n";
- }
+ for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it)
+ d << " " << it.value() << '\n';
if (!m_templates.isEmpty()) {
d << "templates[" << m_templates.size() << "]=(";
- const TplIt begin = m_templates.cbegin();
- for (TplIt it = begin, end = m_templates.cend(); it != end; ++it) {
+ const auto begin = m_templates.cbegin();
+ for (auto it = begin, end = m_templates.cend(); it != end; ++it) {
if (it != begin)
d << ", ";
d << it.value();
@@ -759,8 +868,8 @@ void TypeDatabase::formatDebug(QDebug &d) const
}
if (!m_flagsEntries.isEmpty()) {
d << "flags[" << m_flagsEntries.size() << "]=(";
- const Sit begin = m_flagsEntries.cbegin();
- for (Sit it = begin, end = m_flagsEntries.cend(); it != end; ++it) {
+ const auto begin = m_flagsEntries.cbegin();
+ for (auto it = begin, end = m_flagsEntries.cend(); it != end; ++it) {
if (it != begin)
d << ", ";
d << it.value();
diff --git a/sources/shiboken2/ApiExtractor/typedatabase.h b/sources/shiboken2/ApiExtractor/typedatabase.h
index 2e7b009c2..247d74362 100644
--- a/sources/shiboken2/ApiExtractor/typedatabase.h
+++ b/sources/shiboken2/ApiExtractor/typedatabase.h
@@ -54,13 +54,12 @@ struct TypeRejection;
QT_FORWARD_DECLARE_CLASS(QDebug)
-void setTypeRevision(TypeEntry* typeEntry, int revision);
-int getTypeRevision(const TypeEntry* typeEntry);
-int getTypeIndex(const TypeEntry* typeEntry);
int getMaxTypeIndex();
class ContainerTypeEntry;
class PrimitiveTypeEntry;
+class TypeSystemTypeEntry;
+
class TypeDatabase
{
TypeDatabase();
@@ -91,12 +90,12 @@ public:
NamespaceTypeEntry* findNamespaceType(const QString& name) const;
ContainerTypeEntry* findContainerType(const QString& name) const;
FunctionTypeEntry* findFunctionType(const QString& name) const;
+ const TypeSystemTypeEntry *findTypeSystemType(const QString &name) const;
TypeEntry* findType(const QString& name) const;
- TypeEntryHash allEntries() const { return m_entries; }
-
- SingleTypeEntryHash entries() const;
+ const TypeEntryMultiMap &entries() const { return m_entries; }
+ const TypedefEntryMap &typedefEntries() const { return m_typedefEntries; }
PrimitiveTypeEntryList primitiveTypes() const;
@@ -115,7 +114,7 @@ public:
bool isReturnTypeRejected(const QString& className, const QString& typeName,
QString *reason = nullptr) const;
- void addType(TypeEntry* e);
+ bool addType(TypeEntry* e, QString *errorMessage = nullptr);
FlagsTypeEntry* findFlagsType(const QString& name) const;
void addFlagsType(FlagsTypeEntry* fte);
@@ -147,9 +146,10 @@ public:
bool parseFile(QIODevice* device, bool generate = true);
- bool setApiVersion(const QString& package, const QString& version);
+ static bool setApiVersion(const QString& package, const QString& version);
+ static void clearApiVersions();
- bool checkApiVersion(const QString &package, const QVersionNumber &version) const;
+ static bool checkApiVersion(const QString &package, const QVersionNumber &version);
bool hasDroppedTypeEntries() const { return !m_dropTypeEntries.isEmpty(); }
@@ -163,12 +163,14 @@ public:
void formatDebug(QDebug &d) const;
#endif
private:
- TypeEntryList findTypes(const QString &name) const;
+ TypeEntryMultiMapConstIteratorRange findTypes(const QString &name) const;
+ TypeEntry *resolveTypeDefEntry(TypedefEntry *typedefEntry, QString *errorMessage);
bool m_suppressWarnings;
- TypeEntryHash m_entries;
- SingleTypeEntryHash m_flagsEntries;
- TemplateEntryHash m_templates;
+ TypeEntryMultiMap m_entries;
+ TypeEntryMap m_flagsEntries;
+ TypedefEntryMap m_typedefEntries;
+ TemplateEntryMap m_templates;
QVector<QRegularExpression> m_suppressedWarnings;
AddedFunctionList m_globalUserFunctions;
diff --git a/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h b/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h
index 083602322..fbbbabe43 100644
--- a/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h
+++ b/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h
@@ -29,7 +29,7 @@
#ifndef TYPEDATABASE_TYPEDEFS_H
#define TYPEDATABASE_TYPEDEFS_H
-#include <QtCore/QHash>
+#include <QtCore/QMultiMap>
#include <QtCore/QString>
#include <QtCore/QVector>
@@ -37,11 +37,28 @@ class ContainerTypeEntry;
class PrimitiveTypeEntry;
class TemplateEntry;
class TypeEntry;
+class TypedefEntry;
typedef QVector<TypeEntry *> TypeEntryList;
-typedef QHash<QString, TypeEntryList> TypeEntryHash;
-typedef QHash<QString, TypeEntry *> SingleTypeEntryHash;
-typedef QHash<QString, TemplateEntry *> TemplateEntryHash;
+typedef QMap<QString, TemplateEntry *> TemplateEntryMap;
+
+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;
+};
+
+typedef QMultiMap<QString, TypeEntry *> TypeEntryMultiMap;
+typedef QMultiMapConstIteratorRange<QString, TypeEntry *> TypeEntryMultiMapConstIteratorRange;
+
+typedef QMap<QString, TypeEntry *> TypeEntryMap;
+typedef QMap<QString, TypedefEntry *> TypedefEntryMap;
typedef QVector<const ContainerTypeEntry *> ContainerTypeEntryList;
typedef QVector<const PrimitiveTypeEntry *> PrimitiveTypeEntryList;
diff --git a/sources/shiboken2/ApiExtractor/typeparser.cpp b/sources/shiboken2/ApiExtractor/typeparser.cpp
index 02c85421b..c440fb66d 100644
--- a/sources/shiboken2/ApiExtractor/typeparser.cpp
+++ b/sources/shiboken2/ApiExtractor/typeparser.cpp
@@ -49,13 +49,14 @@ public:
GreaterThanToken,
ConstToken,
+ VolatileToken,
Identifier,
NoToken,
InvalidToken
};
Scanner(const QString &s)
- : m_pos(0), m_length(s.length()), m_chars(s.constData())
+ : m_pos(0), m_length(s.length()), m_tokenStart(-1), m_chars(s.constData())
{
}
@@ -137,13 +138,30 @@ Scanner::Token Scanner::nextToken(QString *errorMessage)
}
}
- if (tok == Identifier && m_pos - m_tokenStart == 5) {
- if (m_chars[m_tokenStart] == QLatin1Char('c')
- && m_chars[m_tokenStart + 1] == QLatin1Char('o')
- && m_chars[m_tokenStart + 2] == QLatin1Char('n')
- && m_chars[m_tokenStart + 3] == QLatin1Char('s')
- && m_chars[m_tokenStart + 4] == QLatin1Char('t'))
- tok = ConstToken;
+ if (tok == Identifier) {
+ switch (m_pos - m_tokenStart) {
+ case 5:
+ if (m_chars[m_tokenStart] == QLatin1Char('c')
+ && m_chars[m_tokenStart + 1] == QLatin1Char('o')
+ && m_chars[m_tokenStart + 2] == QLatin1Char('n')
+ && m_chars[m_tokenStart + 3] == QLatin1Char('s')
+ && m_chars[m_tokenStart + 4] == QLatin1Char('t')) {
+ tok = ConstToken;
+ }
+ break;
+ case 8:
+ if (m_chars[m_tokenStart] == QLatin1Char('v')
+ && m_chars[m_tokenStart + 1] == QLatin1Char('o')
+ && m_chars[m_tokenStart + 2] == QLatin1Char('l')
+ && m_chars[m_tokenStart + 3] == QLatin1Char('a')
+ && m_chars[m_tokenStart + 4] == QLatin1Char('t')
+ && m_chars[m_tokenStart + 5] == QLatin1Char('i')
+ && m_chars[m_tokenStart + 6] == QLatin1Char('l')
+ && m_chars[m_tokenStart + 7] == QLatin1Char('e')) {
+ tok = VolatileToken;
+ }
+ break;
+ }
}
return tok;
@@ -167,6 +185,7 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
bool colon_prefix = false;
bool in_array = false;
QString array;
+ bool seenStar = false;
Scanner::Token tok = scanner.nextToken(errorMessage);
while (tok != Scanner::NoToken) {
@@ -191,7 +210,8 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
switch (tok) {
case Scanner::StarToken:
- ++stack.top()->m_indirections;
+ seenStar = true;
+ stack.top()->addIndirection(Indirection::Pointer);
break;
case Scanner::AmpersandToken:
@@ -212,14 +232,14 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
}
break;
case Scanner::LessThanToken:
- stack.top()->m_arguments << TypeInfo();
- stack.push(&stack.top()->m_arguments.last());
+ stack.top()->m_instantiations << TypeInfo();
+ stack.push(&stack.top()->m_instantiations.last());
break;
case Scanner::CommaToken:
stack.pop();
- stack.top()->m_arguments << TypeInfo();
- stack.push(&stack.top()->m_arguments.last());
+ stack.top()->m_instantiations << TypeInfo();
+ stack.push(&stack.top()->m_instantiations.last());
break;
case Scanner::GreaterThanToken:
@@ -231,7 +251,16 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
break;
case Scanner::ConstToken:
- stack.top()->m_constant = true;
+ if (seenStar) { // "int *const": Last indirection is const.
+ Q_ASSERT(!stack.top()->m_indirections.isEmpty());
+ *stack.top()->m_indirections.rbegin() = Indirection::ConstPointer;
+ } else {
+ stack.top()->m_constant = true;
+ }
+ break;
+
+ case Scanner::VolatileToken:
+ stack.top()->m_volatile = true;
break;
case Scanner::OpenParenToken: // function pointers not supported
diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp
index 8e0e4437a..2c7f5eeaa 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.cpp
+++ b/sources/shiboken2/ApiExtractor/typesystem.cpp
@@ -35,29 +35,68 @@
#include <QtCore/QFileInfo>
#include <QtCore/QRegularExpression>
#include <QtCore/QSet>
+#include <QtCore/QStringView>
+#include <QtCore/QStringAlgorithms>
#include <QtCore/QXmlStreamAttributes>
#include <QtCore/QXmlStreamReader>
+#include <algorithm>
+
+const char *TARGET_CONVERSION_RULE_FLAG = "0";
+const char *NATIVE_CONVERSION_RULE_FLAG = "1";
+
static QString strings_Object = QLatin1String("Object");
static QString strings_String = QLatin1String("String");
static QString strings_char = QLatin1String("char");
static QString strings_jchar = QLatin1String("jchar");
static QString strings_jobject = QLatin1String("jobject");
+static inline QString allowThreadAttribute() { return QStringLiteral("allow-thread"); }
static inline QString colonColon() { return QStringLiteral("::"); }
+static inline QString copyableAttribute() { return QStringLiteral("copyable"); }
+static inline QString accessAttribute() { return QStringLiteral("access"); }
+static inline QString actionAttribute() { return QStringLiteral("action"); }
static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); }
static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); }
static inline QString textAttribute() { return QStringLiteral("text"); }
static inline QString nameAttribute() { return QStringLiteral("name"); }
static inline QString sinceAttribute() { return QStringLiteral("since"); }
+static inline QString defaultSuperclassAttribute() { return QStringLiteral("default-superclass"); }
+static inline QString deleteInMainThreadAttribute() { return QStringLiteral("delete-in-main-thread"); }
+static inline QString deprecatedAttribute() { return QStringLiteral("deprecated"); }
+static inline QString exceptionHandlingAttribute() { return QStringLiteral("exception-handling"); }
+static inline QString extensibleAttribute() { return QStringLiteral("extensible"); }
static inline QString flagsAttribute() { return QStringLiteral("flags"); }
+static inline QString forceAbstractAttribute() { return QStringLiteral("force-abstract"); }
+static inline QString forceIntegerAttribute() { return QStringLiteral("force-integer"); }
+static inline QString formatAttribute() { return QStringLiteral("format"); }
static inline QString classAttribute() { return QStringLiteral("class"); }
-static inline QString functionNameAttribute() { return QStringLiteral("function-name"); }
-static inline QString fieldNameAttribute() { return QStringLiteral("field-name"); }
-static inline QString enumNameAttribute() { return QStringLiteral("enum-name"); }
-static inline QString argumentTypeAttribute() { return QStringLiteral("argument-type"); }
-static inline QString returnTypeAttribute() { return QStringLiteral("return-type"); }
+static inline QString generateAttribute() { return QStringLiteral("generate"); }
+static inline QString genericClassAttribute() { return QStringLiteral("generic-class"); }
+static inline QString indexAttribute() { return QStringLiteral("index"); }
+static inline QString invalidateAfterUseAttribute() { return QStringLiteral("invalidate-after-use"); }
+static inline QString locationAttribute() { return QStringLiteral("location"); }
+static inline QString modifiedTypeAttribute() { return QStringLiteral("modified-type"); }
+static inline QString modifierAttribute() { return QStringLiteral("modifier"); }
+static inline QString ownershipAttribute() { return QStringLiteral("owner"); }
+static inline QString packageAttribute() { return QStringLiteral("package"); }
+static inline QString positionAttribute() { return QStringLiteral("position"); }
+static inline QString preferredConversionAttribute() { return QStringLiteral("preferred-conversion"); }
+static inline QString preferredTargetLangTypeAttribute() { return QStringLiteral("preferred-target-lang-type"); }
+static inline QString removeAttribute() { return QStringLiteral("remove"); }
+static inline QString renameAttribute() { return QStringLiteral("rename"); }
+static inline QString readAttribute() { return QStringLiteral("read"); }
+static inline QString writeAttribute() { return QStringLiteral("write"); }
+static inline QString replaceAttribute() { return QStringLiteral("replace"); }
+static inline QString toAttribute() { return QStringLiteral("to"); }
+static inline QString signatureAttribute() { return QStringLiteral("signature"); }
+static inline QString snippetAttribute() { return QStringLiteral("snippet"); }
+static inline QString staticAttribute() { return QStringLiteral("static"); }
+static inline QString threadAttribute() { return QStringLiteral("thread"); }
+static inline QString sourceAttribute() { return QStringLiteral("source"); }
+static inline QString streamAttribute() { return QStringLiteral("stream"); }
static inline QString xPathAttribute() { return QStringLiteral("xpath"); }
+static inline QString virtualSlotAttribute() { return QStringLiteral("virtual-slot"); }
static inline QString enumIdentifiedByValueAttribute() { return QStringLiteral("identified-by-value"); }
static inline QString noAttributeValue() { return QStringLiteral("no"); }
@@ -90,105 +129,317 @@ static bool setRejectionRegularExpression(const QString &patternIn,
return true;
}
-static bool addRejection(TypeDatabase *database, const QHash<QString, QString> &attributes,
- QString *errorMessage)
+// Extract a snippet from a file within annotation "// @snippet label".
+static QString extractSnippet(const QString &code, const QString &snippetLabel)
{
- typedef QPair<QString, TypeRejection::MatchType> AttributeMatchTypePair;
+ if (snippetLabel.isEmpty())
+ return code;
+ const QString pattern = QStringLiteral(R"(^\s*//\s*@snippet\s+)")
+ + QRegularExpression::escape(snippetLabel)
+ + QStringLiteral(R"(\s*$)");
+ const QRegularExpression snippetRe(pattern);
+ Q_ASSERT(snippetRe.isValid());
- TypeRejection rejection;
+ bool useLine = false;
+ QString result;
+ const auto lines = code.splitRef(QLatin1Char('\n'));
+ for (const QStringRef &line : lines) {
+ if (snippetRe.match(line).hasMatch()) {
+ useLine = !useLine;
+ if (!useLine)
+ break; // End of snippet reached
+ } else if (useLine)
+ result += line.toString() + QLatin1Char('\n');
+ }
+ return result;
+}
- const QString className = attributes.value(classAttribute());
- if (!setRejectionRegularExpression(className, &rejection.className, errorMessage))
- return false;
+template <class EnumType, Qt::CaseSensitivity cs = Qt::CaseInsensitive>
+struct EnumLookup
+{
+ QStringView name;
+ EnumType value;
+};
+
+template <class EnumType, Qt::CaseSensitivity cs>
+bool operator==(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
+{
+ return e1.name.compare(e2.name, cs) == 0;
+}
+
+template <class EnumType, Qt::CaseSensitivity cs>
+bool operator<(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
+{
+ return e1.name.compare(e2.name, cs) < 0;
+}
+
+// Helper macros to define lookup functions that take a QStringView needle
+// and an optional default return value.
+#define ENUM_LOOKUP_BEGIN(EnumType, caseSensitivity, functionName, defaultReturnValue) \
+static EnumType functionName(QStringView needle, EnumType defaultValue = defaultReturnValue) \
+{ \
+ typedef EnumLookup<EnumType, caseSensitivity> HaystackEntry; \
+ static const HaystackEntry haystack[] =
+
+#define ENUM_LOOKUP_LINEAR_SEARCH() \
+ const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
+ const auto it = std::find(haystack, end, HaystackEntry{needle, defaultValue}); \
+ return it != end ? it->value : defaultValue; \
+}
- static const AttributeMatchTypePair attributeMatchTypeMapping[] =
- {{functionNameAttribute(), TypeRejection::Function},
- {fieldNameAttribute(), TypeRejection::Field},
- {enumNameAttribute(), TypeRejection::Enum},
- {argumentTypeAttribute(), TypeRejection::ArgumentType},
- {returnTypeAttribute(), TypeRejection::ReturnType}
+#define ENUM_LOOKUP_BINARY_SEARCH() \
+ const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
+ const HaystackEntry needleEntry{needle, defaultValue}; \
+ const auto lb = std::lower_bound(haystack, end, needleEntry); \
+ return lb != end && *lb == needleEntry ? lb->value : defaultValue; \
+}
+
+ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive,
+ allowThreadFromAttribute, TypeSystem::AllowThread::Unspecified)
+ {
+ {QStringViewLiteral("yes"), TypeSystem::AllowThread::Allow},
+ {QStringViewLiteral("true"), TypeSystem::AllowThread::Allow},
+ {QStringViewLiteral("auto"), TypeSystem::AllowThread::Auto},
+ {QStringViewLiteral("no"), TypeSystem::AllowThread::Disallow},
+ {QStringViewLiteral("false"), TypeSystem::AllowThread::Disallow},
};
+ENUM_LOOKUP_LINEAR_SEARCH()
- // Search for non-empty attribute (function, field, enum)
- const auto aend = attributes.cend();
- for (const AttributeMatchTypePair &mapping : attributeMatchTypeMapping) {
- const auto it = attributes.constFind(mapping.first);
- if (it != aend && !it.value().isEmpty()) {
- if (!setRejectionRegularExpression(it.value(), &rejection.pattern, errorMessage))
- return false;
- rejection.matchType = mapping.second;
- database->addRejection(rejection);
- return true;
- }
- }
+ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive,
+ languageFromAttribute, TypeSystem::NoLanguage)
+ {
+ {QStringViewLiteral("all"), TypeSystem::All}, // sorted!
+ {QStringViewLiteral("constructors"), TypeSystem::Constructors},
+ {QStringViewLiteral("destructor-function"), TypeSystem::DestructorFunction},
+ {QStringViewLiteral("interface"), TypeSystem::Interface},
+ {QStringViewLiteral("library-initializer"), TypeSystem::PackageInitializer},
+ {QStringViewLiteral("native"), TypeSystem::NativeCode}, // em algum lugar do cpp
+ {QStringViewLiteral("shell"), TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe
+ {QStringViewLiteral("shell-declaration"), TypeSystem::ShellDeclaration},
+ {QStringViewLiteral("target"), TypeSystem::TargetLangCode} // em algum lugar do cpp
+ };
+ENUM_LOOKUP_BINARY_SEARCH()
- // Special case: When all fields except class are empty, completely exclude class
- if (className == QLatin1String("*")) {
- *errorMessage = QLatin1String("bad reject entry, neither 'class', 'function-name'"
- " nor 'field' specified");
- return false;
+ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive,
+ ownershipFromFromAttribute, TypeSystem::InvalidOwnership)
+ {
+ {QStringViewLiteral("target"), TypeSystem::TargetLangOwnership},
+ {QStringViewLiteral("c++"), TypeSystem::CppOwnership},
+ {QStringViewLiteral("default"), TypeSystem::DefaultOwnership}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive,
+ addedFunctionAccessFromAttribute, AddedFunction::InvalidAccess)
+ {
+ {QStringViewLiteral("public"), AddedFunction::Public},
+ {QStringViewLiteral("protected"), AddedFunction::Protected},
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(Modification::Modifiers, Qt::CaseSensitive,
+ modifierFromAttribute, Modification::InvalidModifier)
+ {
+ {QStringViewLiteral("private"), Modification::Private},
+ {QStringViewLiteral("public"), Modification::Public},
+ {QStringViewLiteral("protected"), Modification::Protected},
+ {QStringViewLiteral("friendly"), Modification::Friendly},
+ {QStringViewLiteral("rename"), Modification::Rename},
+ {QStringViewLiteral("final"), Modification::Final},
+ {QStringViewLiteral("non-final"), Modification::NonFinal}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive,
+ referenceCountFromAttribute, ReferenceCount::Invalid)
+ {
+ {QStringViewLiteral("add"), ReferenceCount::Add},
+ {QStringViewLiteral("add-all"), ReferenceCount::AddAll},
+ {QStringViewLiteral("remove"), ReferenceCount::Remove},
+ {QStringViewLiteral("set"), ReferenceCount::Set},
+ {QStringViewLiteral("ignore"), ReferenceCount::Ignore}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive,
+ argumentOwnerActionFromAttribute, ArgumentOwner::Invalid)
+ {
+ {QStringViewLiteral("add"), ArgumentOwner::Add},
+ {QStringViewLiteral("remove"), ArgumentOwner::Remove}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive,
+ codeSnipPositionFromAttribute, TypeSystem::CodeSnipPositionInvalid)
+ {
+ {QStringViewLiteral("beginning"), TypeSystem::CodeSnipPositionBeginning},
+ {QStringViewLiteral("end"), TypeSystem::CodeSnipPositionEnd},
+ {QStringViewLiteral("declaration"), TypeSystem::CodeSnipPositionDeclaration},
+ {QStringViewLiteral("prototype-initialization"), TypeSystem::CodeSnipPositionPrototypeInitialization},
+ {QStringViewLiteral("constructor-initialization"), TypeSystem::CodeSnipPositionConstructorInitialization},
+ {QStringViewLiteral("constructor"), TypeSystem::CodeSnipPositionConstructor}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive,
+ locationFromAttribute, Include::InvalidInclude)
+ {
+ {QStringViewLiteral("global"), Include::IncludePath},
+ {QStringViewLiteral("local"), Include::LocalPath},
+ {QStringViewLiteral("target"), Include::TargetLangImport}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive,
+ docModificationFromAttribute, TypeSystem::DocModificationInvalid)
+ {
+ {QStringViewLiteral("append"), TypeSystem::DocModificationAppend},
+ {QStringViewLiteral("prepend"), TypeSystem::DocModificationPrepend},
+ {QStringViewLiteral("replace"), TypeSystem::DocModificationReplace}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(ContainerTypeEntry::Type, Qt::CaseSensitive,
+ containerTypeFromAttribute, ContainerTypeEntry::NoContainer)
+ {
+ {QStringViewLiteral("list"), ContainerTypeEntry::ListContainer},
+ {QStringViewLiteral("string-list"), ContainerTypeEntry::StringListContainer},
+ {QStringViewLiteral("linked-list"), ContainerTypeEntry::LinkedListContainer},
+ {QStringViewLiteral("vector"), ContainerTypeEntry::VectorContainer},
+ {QStringViewLiteral("stack"), ContainerTypeEntry::StackContainer},
+ {QStringViewLiteral("queue"), ContainerTypeEntry::QueueContainer},
+ {QStringViewLiteral("set"), ContainerTypeEntry::SetContainer},
+ {QStringViewLiteral("map"), ContainerTypeEntry::MapContainer},
+ {QStringViewLiteral("multi-map"), ContainerTypeEntry::MultiMapContainer},
+ {QStringViewLiteral("hash"), ContainerTypeEntry::HashContainer},
+ {QStringViewLiteral("multi-hash"), ContainerTypeEntry::MultiHashContainer},
+ {QStringViewLiteral("pair"), ContainerTypeEntry::PairContainer}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive,
+ typeRejectionFromAttribute, TypeRejection::Invalid)
+ {
+ {QStringViewLiteral("class"), TypeRejection::ExcludeClass},
+ {QStringViewLiteral("function-name"), TypeRejection::Function},
+ {QStringViewLiteral("field-name"), TypeRejection::Field},
+ {QStringViewLiteral("enum-name"), TypeRejection::Enum },
+ {QStringViewLiteral("argument-type"), TypeRejection::ArgumentType},
+ {QStringViewLiteral("return-type"), TypeRejection::ReturnType}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive,
+ exceptionHandlingFromAttribute, TypeSystem::ExceptionHandling::Unspecified)
+{
+ {QStringViewLiteral("no"), TypeSystem::ExceptionHandling::Off},
+ {QStringViewLiteral("false"), TypeSystem::ExceptionHandling::Off},
+ {QStringViewLiteral("auto-off"), TypeSystem::ExceptionHandling::AutoDefaultToOff},
+ {QStringViewLiteral("auto-on"), TypeSystem::ExceptionHandling::AutoDefaultToOn},
+ {QStringViewLiteral("yes"), TypeSystem::ExceptionHandling::On},
+ {QStringViewLiteral("true"), TypeSystem::ExceptionHandling::On},
+};
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive,
+ elementFromTag, StackElement::None)
+ {
+ {QStringViewLiteral("access"), StackElement::Access}, // sorted!
+ {QStringViewLiteral("add-conversion"), StackElement::AddConversion},
+ {QStringViewLiteral("add-function"), StackElement::AddFunction},
+ {QStringViewLiteral("argument-map"), StackElement::ArgumentMap},
+ {QStringViewLiteral("array"), StackElement::Array},
+ {QStringViewLiteral("container-type"), StackElement::ContainerTypeEntry},
+ {QStringViewLiteral("conversion-rule"), StackElement::ConversionRule},
+ {QStringViewLiteral("custom-constructor"), StackElement::CustomMetaConstructor},
+ {QStringViewLiteral("custom-destructor"), StackElement::CustomMetaDestructor},
+ {QStringViewLiteral("custom-type"), StackElement::CustomTypeEntry},
+ {QStringViewLiteral("define-ownership"), StackElement::DefineOwnership},
+ {QStringViewLiteral("enum-type"), StackElement::EnumTypeEntry},
+ {QStringViewLiteral("extra-includes"), StackElement::ExtraIncludes},
+ {QStringViewLiteral("function"), StackElement::FunctionTypeEntry},
+ {QStringViewLiteral("include"), StackElement::Include},
+ {QStringViewLiteral("inject-code"), StackElement::InjectCode},
+ {QStringViewLiteral("inject-documentation"), StackElement::InjectDocumentation},
+ {QStringViewLiteral("insert-template"), StackElement::TemplateInstanceEnum},
+ {QStringViewLiteral("interface-type"), StackElement::InterfaceTypeEntry},
+ {QStringViewLiteral("load-typesystem"), StackElement::LoadTypesystem},
+ {QStringViewLiteral("modify-argument"), StackElement::ModifyArgument},
+ {QStringViewLiteral("modify-documentation"), StackElement::ModifyDocumentation},
+ {QStringViewLiteral("modify-field"), StackElement::ModifyField},
+ {QStringViewLiteral("modify-function"), StackElement::ModifyFunction},
+ {QStringViewLiteral("namespace-type"), StackElement::NamespaceTypeEntry},
+ {QStringViewLiteral("native-to-target"), StackElement::NativeToTarget},
+ {QStringViewLiteral("no-null-pointer"), StackElement::NoNullPointers},
+ {QStringViewLiteral("object-type"), StackElement::ObjectTypeEntry},
+ {QStringViewLiteral("parent"), StackElement::ParentOwner},
+ {QStringViewLiteral("primitive-type"), StackElement::PrimitiveTypeEntry},
+ {QStringViewLiteral("reference-count"), StackElement::ReferenceCount},
+ {QStringViewLiteral("reject-enum-value"), StackElement::RejectEnumValue},
+ {QStringViewLiteral("rejection"), StackElement::Rejection},
+ {QStringViewLiteral("remove"), StackElement::Removal},
+ {QStringViewLiteral("remove-argument"), StackElement::RemoveArgument},
+ {QStringViewLiteral("remove-default-expression"), StackElement::RemoveDefaultExpression},
+ {QStringViewLiteral("rename"), StackElement::Rename},
+ {QStringViewLiteral("replace"), StackElement::Replace},
+ {QStringViewLiteral("replace-default-expression"), StackElement::ReplaceDefaultExpression},
+ {QStringViewLiteral("replace-type"), StackElement::ReplaceType},
+ {QStringViewLiteral("smart-pointer-type"), StackElement::SmartPointerTypeEntry},
+ {QStringViewLiteral("suppress-warning"), StackElement::SuppressedWarning},
+ {QStringViewLiteral("target-to-native"), StackElement::TargetToNative},
+ {QStringViewLiteral("template"), StackElement::Template},
+ {QStringViewLiteral("typedef-type"), StackElement::TypedefTypeEntry},
+ {QStringViewLiteral("typesystem"), StackElement::Root},
+ {QStringViewLiteral("value-type"), StackElement::ValueTypeEntry},
+ };
+ENUM_LOOKUP_BINARY_SEARCH()
+
+static int indexOfAttribute(const QXmlStreamAttributes &atts,
+ QStringView name)
+{
+ for (int i = 0, size = atts.size(); i < size; ++i) {
+ if (atts.at(i).qualifiedName() == name)
+ return i;
}
- rejection.matchType = TypeRejection::ExcludeClass;
- database->addRejection(rejection);
- return true;
+ return -1;
+}
+
+static QString msgMissingAttribute(const QString &a)
+{
+ return QLatin1String("Required attribute '") + a
+ + QLatin1String("' missing.");
+}
+
+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(const QStringRef &tag, const QXmlStreamAttributes &attributes)
+{
+ QString result;
+ QTextStream str(&result);
+ str << attributes.size() << " attributes(s) unused on <" << tag << ">: ";
+ for (int i = 0, size = attributes.size(); i < size; ++i) {
+ if (i)
+ str << ", ";
+ str << attributes.at(i);
+ }
+ return result;
+}
-Handler::Handler(TypeDatabase* database, bool generate)
- : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
-{
- m_currentEnum = 0;
- m_current = 0;
- m_currentDroppedEntry = 0;
- m_currentDroppedEntryDepth = 0;
- m_ignoreDepth = 0;
-
- tagNames.insert(QLatin1String("rejection"), StackElement::Rejection);
- tagNames.insert(QLatin1String("custom-type"), StackElement::CustomTypeEntry);
- tagNames.insert(QLatin1String("primitive-type"), StackElement::PrimitiveTypeEntry);
- tagNames.insert(QLatin1String("container-type"), StackElement::ContainerTypeEntry);
- tagNames.insert(QLatin1String("object-type"), StackElement::ObjectTypeEntry);
- tagNames.insert(QLatin1String("value-type"), StackElement::ValueTypeEntry);
- tagNames.insert(QLatin1String("interface-type"), StackElement::InterfaceTypeEntry);
- tagNames.insert(QLatin1String("namespace-type"), StackElement::NamespaceTypeEntry);
- tagNames.insert(QLatin1String("enum-type"), StackElement::EnumTypeEntry);
- tagNames.insert(QLatin1String("smart-pointer-type"), StackElement::SmartPointerTypeEntry);
- tagNames.insert(QLatin1String("function"), StackElement::FunctionTypeEntry);
- tagNames.insert(QLatin1String("extra-includes"), StackElement::ExtraIncludes);
- tagNames.insert(QLatin1String("include"), StackElement::Include);
- tagNames.insert(QLatin1String("inject-code"), StackElement::InjectCode);
- tagNames.insert(QLatin1String("modify-function"), StackElement::ModifyFunction);
- tagNames.insert(QLatin1String("modify-field"), StackElement::ModifyField);
- tagNames.insert(QLatin1String("access"), StackElement::Access);
- tagNames.insert(QLatin1String("remove"), StackElement::Removal);
- tagNames.insert(QLatin1String("rename"), StackElement::Rename);
- tagNames.insert(QLatin1String("typesystem"), StackElement::Root);
- tagNames.insert(QLatin1String("custom-constructor"), StackElement::CustomMetaConstructor);
- tagNames.insert(QLatin1String("custom-destructor"), StackElement::CustomMetaDestructor);
- tagNames.insert(QLatin1String("argument-map"), StackElement::ArgumentMap);
- tagNames.insert(QLatin1String("suppress-warning"), StackElement::SuppressedWarning);
- tagNames.insert(QLatin1String("load-typesystem"), StackElement::LoadTypesystem);
- tagNames.insert(QLatin1String("define-ownership"), StackElement::DefineOwnership);
- tagNames.insert(QLatin1String("replace-default-expression"), StackElement::ReplaceDefaultExpression);
- tagNames.insert(QLatin1String("reject-enum-value"), StackElement::RejectEnumValue);
- tagNames.insert(QLatin1String("replace-type"), StackElement::ReplaceType);
- tagNames.insert(QLatin1String("conversion-rule"), StackElement::ConversionRule);
- tagNames.insert(QLatin1String("native-to-target"), StackElement::NativeToTarget);
- tagNames.insert(QLatin1String("target-to-native"), StackElement::TargetToNative);
- tagNames.insert(QLatin1String("add-conversion"), StackElement::AddConversion);
- tagNames.insert(QLatin1String("modify-argument"), StackElement::ModifyArgument);
- tagNames.insert(QLatin1String("remove-argument"), StackElement::RemoveArgument);
- tagNames.insert(QLatin1String("remove-default-expression"), StackElement::RemoveDefaultExpression);
- tagNames.insert(QLatin1String("template"), StackElement::Template);
- tagNames.insert(QLatin1String("insert-template"), StackElement::TemplateInstanceEnum);
- tagNames.insert(QLatin1String("replace"), StackElement::Replace);
- tagNames.insert(QLatin1String("no-null-pointer"), StackElement::NoNullPointers);
- tagNames.insert(QLatin1String("reference-count"), StackElement::ReferenceCount);
- tagNames.insert(QLatin1String("parent"), StackElement::ParentOwner);
- tagNames.insert(QLatin1String("array"), StackElement::Array);
- tagNames.insert(QLatin1String("inject-documentation"), StackElement::InjectDocumentation);
- tagNames.insert(QLatin1String("modify-documentation"), StackElement::ModifyDocumentation);
- tagNames.insert(QLatin1String("add-function"), StackElement::AddFunction);
+Handler::Handler(TypeDatabase *database, bool generate) :
+ m_database(database),
+ m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
+{
}
static QString readerFileName(const QXmlStreamReader &reader)
@@ -197,22 +448,72 @@ static QString readerFileName(const QXmlStreamReader &reader)
return file != nullptr ? file->fileName() : QString();
}
-static QString msgReaderError(const QXmlStreamReader &reader, const QString &what)
+static QString msgReaderMessage(const QXmlStreamReader &reader,
+ const char *type,
+ const QString &what)
{
QString message;
QTextStream str(&message);
- str << "Error: ";
+ str << type << ": ";
const QString fileName = readerFileName(reader);
- if (!fileName.isEmpty())
- str << "file=" << QDir::toNativeSeparators(fileName) << ", ";
- str << "line=" << reader.lineNumber() << ", column=" << reader.columnNumber()
- << ", message=" << what;
+ if (fileName.isEmpty())
+ str << "<stdin>:";
+ else
+ str << QDir::toNativeSeparators(fileName) << ':';
+ str << reader.lineNumber() << ':' << reader.columnNumber()
+ << ": " << what;
return message;
}
-static QString msgReaderError(const QXmlStreamReader &reader)
+static QString msgReaderWarning(const QXmlStreamReader &reader, const QString &what)
{
- return msgReaderError(reader, reader.errorString());
+ return msgReaderMessage(reader, "Warning", what);
+}
+
+static QString msgReaderError(const QXmlStreamReader &reader, const QString &what)
+{
+ return msgReaderMessage(reader, "Error", what);
+}
+
+static QString msgUnimplementedElementWarning(const QXmlStreamReader &reader,
+ const QStringRef &name)
+{
+ const QString message = QLatin1String("The element \"") +
+ name + QLatin1String("\" is not implemented.");
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static QString msgUnimplementedAttributeWarning(const QXmlStreamReader &reader,
+ const QStringRef &name)
+{
+ const QString message = QLatin1String("The attribute \"") +
+ name + QLatin1String("\" is not implemented.");
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static inline QString msgUnimplementedAttributeWarning(const QXmlStreamReader &reader,
+ const QXmlStreamAttribute &attribute)
+{
+ return msgUnimplementedAttributeWarning(reader, attribute.qualifiedName());
+}
+
+static QString
+ msgUnimplementedAttributeValueWarning(const QXmlStreamReader &reader,
+ QStringView name, QStringView 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 QXmlStreamReader &reader,
+ const QXmlStreamAttribute &attribute)
+{
+ return msgUnimplementedAttributeValueWarning(reader,
+ attribute.qualifiedName(),
+ attribute.value());
}
static QString msgInvalidVersion(const QStringRef &version, const QString &package = QString())
@@ -226,6 +527,53 @@ static QString msgInvalidVersion(const QStringRef &version, const QString &packa
return result;
}
+static bool addRejection(TypeDatabase *database, QXmlStreamAttributes *attributes,
+ QString *errorMessage)
+{
+ const int classIndex = indexOfAttribute(*attributes, classAttribute());
+ if (classIndex == -1) {
+ *errorMessage = msgMissingAttribute(classAttribute());
+ return false;
+ }
+
+ TypeRejection rejection;
+ const QString className = attributes->takeAt(classIndex).value().toString();
+ if (!setRejectionRegularExpression(className, &rejection.className, errorMessage))
+ return false;
+
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ const TypeRejection::MatchType type = typeRejectionFromAttribute(name);
+ switch (type) {
+ 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 = type;
+ database->addRejection(rejection);
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Special case: When all fields except class are empty, completely exclude class
+ if (className == QLatin1String("*")) {
+ *errorMessage = QLatin1String("bad reject entry, neither 'class', 'function-name'"
+ " nor 'field' specified");
+ return false;
+ }
+ rejection.matchType = TypeRejection::ExcludeClass;
+ database->addRejection(rejection);
+ return true;
+}
+
bool Handler::parse(QXmlStreamReader &reader)
{
m_error.clear();
@@ -238,10 +586,10 @@ bool Handler::parse(QXmlStreamReader &reader)
switch (reader.readNext()) {
case QXmlStreamReader::NoToken:
case QXmlStreamReader::Invalid:
- qCWarning(lcShiboken).noquote().nospace() << msgReaderError(reader);
+ m_error = msgReaderError(reader, reader.errorString());
return false;
case QXmlStreamReader::StartElement:
- if (!startElement(reader.name(), reader.attributes())) {
+ if (!startElement(reader)) {
m_error = msgReaderError(reader, m_error);
return false;
}
@@ -271,22 +619,6 @@ bool Handler::parse(QXmlStreamReader &reader)
return true;
}
-void Handler::fetchAttributeValues(const QString &name, const QXmlStreamAttributes &atts,
- QHash<QString, QString> *acceptedAttributes)
-{
- Q_ASSERT(acceptedAttributes);
-
- for (int i = 0; i < atts.length(); ++i) {
- const QString key = atts.at(i).name().toString().toLower();
- if (!acceptedAttributes->contains(key)) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("Unknown attribute for '%1': '%2'").arg(name, key);
- } else {
- acceptedAttributes->insert(key, atts.at(i).value().toString());
- }
- }
-}
-
bool Handler::endElement(const QStringRef &localName)
{
if (m_ignoreDepth) {
@@ -416,14 +748,18 @@ bool Handler::endElement(const QStringRef &localName)
break;
}
- if (m_current->type == StackElement::Root
- || m_current->type == StackElement::NamespaceTypeEntry
- || m_current->type == StackElement::InterfaceTypeEntry
- || m_current->type == StackElement::ObjectTypeEntry
- || m_current->type == StackElement::ValueTypeEntry
- || m_current->type == StackElement::PrimitiveTypeEntry) {
- StackElementContext* context = m_contextStack.pop();
- delete context;
+ switch (m_current->type) {
+ case StackElement::Root:
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::PrimitiveTypeEntry:
+ case StackElement::TypedefTypeEntry:
+ delete m_contextStack.pop();
+ break;
+ default:
+ break;
}
StackElement *child = m_current;
@@ -551,8 +887,9 @@ bool Handler::importFileElement(const QXmlStreamAttributes &atts)
return true;
}
-static bool convertBoolean(const QString &value, const QString &attributeName, bool defaultValue)
+static bool convertBoolean(QStringView value, const QString &attributeName, bool defaultValue)
{
+#ifdef QTBUG_69389_FIXED
if (value.compare(trueAttributeValue(), Qt::CaseInsensitive) == 0
|| value.compare(yesAttributeValue(), Qt::CaseInsensitive) == 0) {
return true;
@@ -561,28 +898,47 @@ static bool convertBoolean(const QString &value, const QString &attributeName, b
|| value.compare(noAttributeValue(), Qt::CaseInsensitive) == 0) {
return false;
}
+#else
+ if (QtPrivate::compareStrings(value, trueAttributeValue(), Qt::CaseInsensitive) == 0
+ || QtPrivate::compareStrings(value, yesAttributeValue(), Qt::CaseInsensitive) == 0) {
+ return true;
+ }
+ if (QtPrivate::compareStrings(value, falseAttributeValue(), Qt::CaseInsensitive) == 0
+ || QtPrivate::compareStrings(value, noAttributeValue(), Qt::CaseInsensitive) == 0) {
+ return false;
+ }
+#endif
const QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
- .arg(value, attributeName,
+ .arg(value)
+ .arg(attributeName,
defaultValue ? yesAttributeValue() : noAttributeValue());
qCWarning(lcShiboken).noquote().nospace() << warn;
return defaultValue;
}
-static bool convertRemovalAttribute(const QString& removalAttribute, Modification& mod, QString& errorMsg)
+static bool convertRemovalAttribute(QStringView remove, Modification& mod, QString& errorMsg)
{
- QString remove = removalAttribute.toLower();
- if (!remove.isEmpty()) {
- if (remove == QLatin1String("all")) {
- mod.removal = TypeSystem::All;
- } else if (remove == QLatin1String("target")) {
- mod.removal = TypeSystem::TargetLangAndNativeCode;
- } else {
- errorMsg = QString::fromLatin1("Bad removal type '%1'").arg(remove);
- return false;
- }
+ if (remove.isEmpty())
+ return true;
+#ifdef QTBUG_69389_FIXED
+ if (remove.compare(QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) {
+#else
+ if (QtPrivate::compareStrings(remove, QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) {
+#endif
+ mod.removal = TypeSystem::All;
+ return true;
}
- return true;
+#ifdef QTBUG_69389_FIXED
+ if (remove.compare(QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) {
+#else
+ if (QtPrivate::compareStrings(remove, QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) {
+#endif
+ mod.removal = TypeSystem::TargetLangAndNativeCode;
+ return true;
+ }
+ errorMsg = QString::fromLatin1("Bad removal type '%1'").arg(remove);
+ return false;
}
static void getNamePrefixRecursive(StackElement* element, QStringList& names)
@@ -615,98 +971,1439 @@ static QString checkSignatureError(const QString& signature, const QString& tag)
return QString();
}
-void Handler::addFlags(const QString &name, QString flagName,
- const QHash<QString, QString> &attributes,
- const QVersionNumber &since)
+void Handler::applyCommonAttributes(TypeEntry *type, QXmlStreamAttributes *attributes) const
+{
+ type->setCodeGeneration(m_generate);
+ const int revisionIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("revision"));
+ if (revisionIndex != -1)
+ type->setRevision(attributes->takeAt(revisionIndex).value().toInt());
+}
+
+FlagsTypeEntry *
+ Handler::parseFlagsEntry(const QXmlStreamReader &,
+ EnumTypeEntry *enumEntry,
+ const QString &name, QString flagName,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+
{
FlagsTypeEntry *ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + name + QLatin1Char('>'), since);
- ftype->setOriginator(m_currentEnum);
+ ftype->setOriginator(enumEntry);
+ ftype->setTargetLangPackage(enumEntry->targetLangPackage());
// Try to get the guess the qualified flag name
const int lastSepPos = name.lastIndexOf(colonColon());
if (lastSepPos >= 0 && !flagName.contains(colonColon()))
flagName.prepend(name.left(lastSepPos + 2));
ftype->setOriginalName(flagName);
- ftype->setCodeGeneration(m_generate);
+ applyCommonAttributes(ftype, attributes);
QString n = ftype->originalName();
QStringList lst = n.split(colonColon());
- if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != m_currentEnum->targetLangQualifier()) {
+ const QString &targetLangQualifier = enumEntry->targetLangQualifier();
+ if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != targetLangQualifier) {
qCWarning(lcShiboken).noquote().nospace()
<< QStringLiteral("enum %1 and flags %2 differ in qualifiers")
- .arg(m_currentEnum->targetLangQualifier(), lst.constFirst());
+ .arg(targetLangQualifier, lst.constFirst());
}
ftype->setFlagsName(lst.constLast());
- m_currentEnum->setFlags(ftype);
+ enumEntry->setFlags(ftype);
m_database->addFlagsType(ftype);
m_database->addType(ftype);
- QString revision = attributes.value(QLatin1String("flags-revision"));
- if (revision.isEmpty())
- revision = attributes.value(QLatin1String("revision"));
- setTypeRevision(ftype, revision.toInt());
-}
+ const int revisionIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("flags-revision"));
+ ftype->setRevision(revisionIndex != -1
+ ? attributes->takeAt(revisionIndex).value().toInt()
+ : enumEntry->revision());
+ return ftype;
+}
+
+SmartPointerTypeEntry *
+ Handler::parseSmartPointerEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ QString smartPointerType;
+ QString getter;
+ QString refCountMethodName;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("type")) {
+ smartPointerType = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("getter")) {
+ getter = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("ref-count-method")) {
+ refCountMethodName = attributes->takeAt(i).value().toString();
+ }
+ }
-bool Handler::handleSmartPointerEntry(StackElement *element,
- QHash<QString, QString> &attributes,
- const QString &name,
- const QVersionNumber &since)
-{
- QString smartPointerType = attributes[QLatin1String("type")];
if (smartPointerType.isEmpty()) {
m_error = QLatin1String("No type specified for the smart pointer. Currently supported types: 'shared',");
- return false;
+ return nullptr;
}
if (smartPointerType != QLatin1String("shared")) {
m_error = QLatin1String("Currently only the 'shared' type is supported.");
- return false;
+ return nullptr;
}
- QString getter = attributes[QLatin1String("getter")];
if (getter.isEmpty()) {
m_error = QLatin1String("No function getter name specified for getting the raw pointer held by the smart pointer.");
- return false;
+ return nullptr;
}
- QString refCountMethodName = attributes[QLatin1String("ref-count-method")];
QString signature = getter + QLatin1String("()");
-
signature = TypeDatabase::normalizedSignature(signature);
if (signature.isEmpty()) {
m_error = QLatin1String("No signature for the smart pointer getter found.");
- return false;
+ return nullptr;
}
QString errorString = checkSignatureError(signature,
QLatin1String("smart-pointer-type"));
if (!errorString.isEmpty()) {
m_error = errorString;
- return false;
+ return nullptr;
+ }
+
+ SmartPointerTypeEntry *type =
+ new SmartPointerTypeEntry(name, getter, smartPointerType, refCountMethodName, since);
+ applyCommonAttributes(type, attributes);
+ return type;
+}
+
+PrimitiveTypeEntry *
+ Handler::parsePrimitiveTypeEntry(const QXmlStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name, since);
+ applyCommonAttributes(type, attributes);
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("target-lang-name")) {
+ type->setTargetLangName(attributes->takeAt(i).value().toString());
+ } else if (name == QLatin1String("target-lang-api-name")) {
+ type->setTargetLangApiName(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 == QLatin1String("default-constructor")) {
+ type->setDefaultConstructor(attributes->takeAt(i).value().toString());
+ }
}
- SmartPointerTypeEntry *type = new SmartPointerTypeEntry(name,
- getter,
- smartPointerType,
- refCountMethodName,
- since);
+ if (type->targetLangName().isEmpty())
+ type->setTargetLangName(type->name());
+ if (type->targetLangApiName().isEmpty())
+ type->setTargetLangApiName(type->name());
type->setTargetLangPackage(m_defaultPackage);
- type->setCodeGeneration(m_generate);
- element->entry = type;
+ return type;
+}
+
+ContainerTypeEntry *
+ Handler::parseContainerTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ const int typeIndex = indexOfAttribute(*attributes, QStringViewLiteral("type"));
+ if (typeIndex == -1) {
+ m_error = QLatin1String("no 'type' attribute specified");
+ return nullptr;
+ }
+ const QStringRef typeName = attributes->takeAt(typeIndex).value();
+ ContainerTypeEntry::Type containerType = containerTypeFromAttribute(typeName);
+ if (containerType == ContainerTypeEntry::NoContainer) {
+ m_error = QLatin1String("there is no container of type ") + typeName.toString();
+ return nullptr;
+ }
+ ContainerTypeEntry *type = new ContainerTypeEntry(name, containerType, since);
+ applyCommonAttributes(type, attributes);
+ return type;
+}
+
+EnumTypeEntry *
+ Handler::parseEnumTypeEntry(const QXmlStreamReader &reader,
+ const QString &fullName, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ QString scope;
+ QString name = fullName;
+ const int sep = fullName.lastIndexOf(colonColon());
+ if (sep != -1) {
+ scope = fullName.left(sep);
+ name = fullName.right(fullName.size() - sep - 2);
+ }
+ EnumTypeEntry *entry = new EnumTypeEntry(scope, name, since);
+ applyCommonAttributes(entry, attributes);
+ entry->setTargetLangPackage(m_defaultPackage);
+
+ QString flagNames;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("upper-bound")) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == QLatin1String("lower-bound")) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == forceIntegerAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } 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(QLatin1Char(','));
+ for (const QString &flagName : flagNameList)
+ parseFlagsEntry(reader, entry, fullName, flagName.trimmed(), since, attributes);
+ }
+ return entry;
+}
+
+ObjectTypeEntry *
+ Handler::parseInterfaceTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ ObjectTypeEntry *otype = new ObjectTypeEntry(name, since);
+ applyCommonAttributes(otype, attributes);
+ QString targetLangName = name;
+ bool generate = true;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("target-lang-name")) {
+ targetLangName = attributes->takeAt(i).value().toString();
+ } else if (name == generateAttribute()) {
+ generate = convertBoolean(attributes->takeAt(i).value(),
+ generateAttribute(), true);
+ }
+ }
+
+ InterfaceTypeEntry *itype =
+ new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), since);
+
+ if (generate)
+ itype->setCodeGeneration(m_generate);
+ else
+ itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
+
+ otype->setDesignatedInterface(itype);
+ itype->setOrigin(otype);
+ return otype;
+}
+
+ValueTypeEntry *
+ Handler::parseValueTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ ValueTypeEntry *typeEntry = new ValueTypeEntry(name, since);
+ applyCommonAttributes(typeEntry, attributes);
+ const int defaultCtIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("default-constructor"));
+ if (defaultCtIndex != -1)
+ typeEntry->setDefaultConstructor(attributes->takeAt(defaultCtIndex).value().toString());
+ return typeEntry;
+}
+
+FunctionTypeEntry *
+ Handler::parseFunctionTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ const int signatureIndex = indexOfAttribute(*attributes, signatureAttribute());
+ if (signatureIndex == -1) {
+ m_error = msgMissingAttribute(signatureAttribute());
+ return nullptr;
+ }
+ const QString signature =
+ TypeDatabase::normalizedSignature(attributes->takeAt(signatureIndex).value().toString());
+
+ TypeEntry *existingType = m_database->findType(name);
+
+ if (!existingType) {
+ FunctionTypeEntry *result = new FunctionTypeEntry(name, signature, since);
+ applyCommonAttributes(result, attributes);
+ return result;
+ }
+
+ if (existingType->type() != TypeEntry::FunctionType) {
+ m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.")
+ .arg(name);
+ return nullptr;
+ }
+
+ FunctionTypeEntry *result = reinterpret_cast<FunctionTypeEntry *>(existingType);
+ result->addSignature(signature);
+ return result;
+}
+
+TypedefEntry *
+ Handler::parseTypedefEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (m_current && m_current->type != StackElement::Root
+ && m_current->type != StackElement::NamespaceTypeEntry) {
+ m_error = QLatin1String("typedef entries must be nested in namespaces or type system.");
+ return nullptr;
+ }
+ const int sourceIndex = indexOfAttribute(*attributes, sourceAttribute());
+ if (sourceIndex == -1) {
+ m_error = msgMissingAttribute(sourceAttribute());
+ return nullptr;
+ }
+ const QString sourceType = attributes->takeAt(sourceIndex).value().toString();
+ auto result = new TypedefEntry(name, sourceType, since);
+ applyCommonAttributes(result, attributes);
+ return result;
+}
+
+void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader,
+ ComplexTypeEntry *ctype,
+ QXmlStreamAttributes *attributes) const
+{
+ bool generate = true;
+ ctype->setCopyable(ComplexTypeEntry::Unknown);
+ auto exceptionHandling = m_exceptionHandling;
+
+ QString package = m_defaultPackage;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == streamAttribute()) {
+ ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute(), 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 == QLatin1String("target-lang-name")) {
+ ctype->setTargetLangName(attributes->takeAt(i).value().toString());
+ } else if (name == QLatin1String("polymorphic-base")) {
+ ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
+ } else if (name == QLatin1String("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 v = exceptionHandlingFromAttribute(attribute.value());
+ if (v != TypeSystem::ExceptionHandling::Unspecified) {
+ exceptionHandling = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == QLatin1String("held-type")) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == QLatin1String("hash-function")) {
+ ctype->setHashFunction(attributes->takeAt(i).value().toString());
+ } else if (name == forceAbstractAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == deprecatedAttribute()) {
+ if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
+ } else if (name == deleteInMainThreadAttribute()) {
+ if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false))
+ ctype->setDeleteInMainThread(true);
+ } else if (name == QLatin1String("target-type")) {
+ ctype->setTargetType(attributes->takeAt(i).value().toString());
+ }
+ }
+
+ if (exceptionHandling != TypeSystem::ExceptionHandling::Unspecified)
+ ctype->setExceptionHandling(exceptionHandling);
+
+ // The generator code relies on container's package being empty.
+ if (ctype->type() != TypeEntry::ContainerType)
+ ctype->setTargetLangPackage(package);
+
+ if (InterfaceTypeEntry *di = ctype->designatedInterface())
+ di->setTargetLangPackage(package);
+
+ if (generate)
+ ctype->setCodeGeneration(m_generate);
+ else
+ ctype->setCodeGeneration(TypeEntry::GenerateForSubclass);
+}
+
+bool Handler::parseRenameFunction(const QXmlStreamReader &,
+ QString *name, QXmlStreamAttributes *attributes)
+{
+ QString signature;
+ QString rename;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef 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();
+ } else if (name == renameAttribute()) {
+ rename = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (signature.isEmpty()) {
+ m_error = msgMissingAttribute(signatureAttribute());
+ return false;
+ }
+
+ *name = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
+
+ QString errorString = checkSignatureError(signature, QLatin1String("function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ if (!rename.isEmpty()) {
+ static const QRegularExpression functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$"));
+ Q_ASSERT(functionNameRegExp.isValid());
+ if (!functionNameRegExp.match(rename).hasMatch()) {
+ m_error = QLatin1String("can not rename '") + signature + QLatin1String("', '")
+ + rename + QLatin1String("' is not a valid function name");
+ return false;
+ }
+ FunctionModification mod;
+ if (!mod.setSignature(signature, &m_error))
+ return false;
+ mod.renamedToName = rename;
+ mod.modifiers |= Modification::Rename;
+ m_contextStack.top()->functionMods << mod;
+ }
+ return true;
+}
+
+bool Handler::parseInjectDocumentation(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (!m_current->parent || (m_current->parent->type & validParent) == 0) {
+ m_error = QLatin1String("inject-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type");
+ return false;
+ }
+
+ TypeSystem::DocModificationMode mode = TypeSystem::DocModificationReplace;
+ TypeSystem::Language lang = TypeSystem::NativeCode;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("mode")) {
+ const QStringRef modeName = attributes->takeAt(i).value();
+ mode = docModificationFromAttribute(modeName);
+ if (mode == TypeSystem::DocModificationInvalid) {
+ m_error = QLatin1String("Unknown documentation injection mode: ") + modeName;
+ return false;
+ }
+ } else if (name == formatAttribute()) {
+ const QStringRef format = attributes->takeAt(i).value();
+ lang = languageFromAttribute(format);
+ if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(format);
+ return false;
+ }
+ }
+ }
+
+ QString signature = m_current->type & StackElement::TypeEntryMask
+ ? QString() : m_currentSignature;
+ DocModification mod(mode, signature);
+ mod.setFormat(lang);
+ m_contextStack.top()->docModifications << mod;
+ return true;
+}
+
+bool Handler::parseModifyDocumentation(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (!m_current->parent || (m_current->parent->type & validParent) == 0) {
+ m_error = QLatin1String("modify-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type");
+ return false;
+ }
+
+ const int xpathIndex = indexOfAttribute(*attributes, xPathAttribute());
+ if (xpathIndex == -1) {
+ m_error = msgMissingAttribute(xPathAttribute());
+ return false;
+ }
+
+ const QString xpath = attributes->takeAt(xpathIndex).value().toString();
+ QString signature = (m_current->type & StackElement::TypeEntryMask) ? QString() : m_currentSignature;
+ m_contextStack.top()->docModifications
+ << DocModification(xpath, signature);
+ return true;
+}
+
+// m_exceptionHandling
+TypeSystemTypeEntry *Handler::parseRootElement(const QXmlStreamReader &,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef 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 v = exceptionHandlingFromAttribute(attribute.value());
+ if (v != TypeSystem::ExceptionHandling::Unspecified) {
+ m_exceptionHandling = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ }
+ }
+
+ TypeSystemTypeEntry *moduleEntry =
+ const_cast<TypeSystemTypeEntry *>(m_database->findTypeSystemType(m_defaultPackage));
+ if (!moduleEntry)
+ moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since);
+ moduleEntry->setCodeGeneration(m_generate);
+
+ if ((m_generate == TypeEntry::GenerateForSubclass ||
+ m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty())
+ TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage);
+
+ if (!moduleEntry->qualifiedCppName().isEmpty())
+ m_database->addType(moduleEntry);
+ return moduleEntry;
+}
+
+bool Handler::loadTypesystem(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ QString typeSystemName;
+ bool generateChild = true;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef 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 = QLatin1String("No typesystem name specified");
+ return false;
+ }
+ const bool result =
+ m_database->parseFile(typeSystemName, m_currentPath, generateChild
+ && m_generate == TypeEntry::GenerateAll);
+ if (!result)
+ m_error = QStringLiteral("Failed to parse: '%1'").arg(typeSystemName);
+ return result;
+}
+
+bool Handler::parseRejectEnumValue(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ if (!m_currentEnum) {
+ m_error = QLatin1String("<reject-enum-value> node must be used inside a <enum-type> node");
+ return false;
+ }
+ const int nameIndex = indexOfAttribute(*attributes, nameAttribute());
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ m_currentEnum->addEnumValueRejection(attributes->takeAt(nameIndex).value().toString());
+ return true;
+}
+
+bool Handler::parseReplaceArgumentType(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Type replacement can only be specified for argument modifications");
+ return false;
+ }
+ const int modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute());
+ if (modifiedTypeIndex == -1) {
+ m_error = QLatin1String("Type replacement requires 'modified-type' attribute");
+ return false;
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().modified_type =
+ attributes->takeAt(modifiedTypeIndex).value().toString();
+ return true;
+}
+
+bool Handler::parseCustomConversion(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument
+ && topElement.type != StackElement::ValueTypeEntry
+ && topElement.type != StackElement::PrimitiveTypeEntry
+ && topElement.type != StackElement::ContainerTypeEntry) {
+ m_error = QLatin1String("Conversion rules can only be specified for argument modification, "
+ "value-type, primitive-type or container-type conversion.");
+ return false;
+ }
+
+ QString sourceFile;
+ QString snippetLabel;
+ TypeSystem::Language lang = TypeSystem::NativeCode;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == classAttribute()) {
+ const QStringRef languageAttribute = attributes->takeAt(i).value();
+ lang = languageFromAttribute(languageAttribute);
+ if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(languageAttribute);
+ return false;
+ }
+ } else if (name == QLatin1String("file")) {
+ sourceFile = attributes->takeAt(i).value().toString();
+ } else if (name == snippetAttribute()) {
+ snippetLabel = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (topElement.type == StackElement::ModifyArgument) {
+ CodeSnip snip;
+ snip.language = lang;
+ m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.append(snip);
+ return true;
+ }
+
+ if (topElement.entry->hasConversionRule() || topElement.entry->hasCustomConversion()) {
+ m_error = QLatin1String("Types can have only one conversion rule");
+ return false;
+ }
+
+ // The old conversion rule tag that uses a file containing the conversion
+ // will be kept temporarily for compatibility reasons.
+ if (!sourceFile.isEmpty()) {
+ if (m_generate != TypeEntry::GenerateForSubclass
+ && m_generate != TypeEntry::GenerateNothing) {
+
+ const char* conversionFlag = NATIVE_CONVERSION_RULE_FLAG;
+ if (lang == TypeSystem::TargetLangCode)
+ conversionFlag = TARGET_CONVERSION_RULE_FLAG;
+
+ QFile conversionSource(sourceFile);
+ if (conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ const QString conversionRule =
+ extractSnippet(QString::fromUtf8(conversionSource.readAll()), snippetLabel);
+ topElement.entry->setConversionRule(QLatin1String(conversionFlag) + conversionRule);
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "File containing conversion code for "
+ << topElement.entry->name() << " type does not exist or is not readable: "
+ << sourceFile;
+ }
+ }
+ }
+
+ CustomConversion* customConversion = new CustomConversion(m_current->entry);
+ customConversionsForReview.append(customConversion);
+ return true;
+}
+
+bool Handler::parseAddConversion(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::TargetToNative) {
+ m_error = QLatin1String("Target to Native conversions can only be added inside 'target-to-native' tags.");
+ return false;
+ }
+ QString sourceTypeName;
+ QString typeCheck;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("type"))
+ sourceTypeName = attributes->takeAt(i).value().toString();
+ else if (name == QLatin1String("check"))
+ typeCheck = attributes->takeAt(i).value().toString();
+ }
+ if (sourceTypeName.isEmpty()) {
+ m_error = QLatin1String("Target to Native conversions must specify the input type with the 'type' attribute.");
+ return false;
+ }
+ m_current->entry->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck);
+ m_contextStack.top()->codeSnips << CodeSnip();
+ return true;
+}
+
+static bool parseIndex(const QString &index, int *result, QString *errorMessage)
+{
+ bool ok = false;
+ *result = index.toInt(&ok);
+ if (!ok)
+ *errorMessage = QStringLiteral("Cannot convert '%1' to integer").arg(index);
+ return ok;
+}
+
+static bool parseArgumentIndex(const QString &index, int *result, QString *errorMessage)
+{
+ if (index == QLatin1String("return")) {
+ *result = 0;
+ return true;
+ }
+ if (index == QLatin1String("this")) {
+ *result = -1;
+ return true;
+ }
+ return parseIndex(index, result, errorMessage);
+}
+
+bool Handler::parseModifyArgument(const QXmlStreamReader &,
+ const StackElement &topElement, QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyFunction
+ && topElement.type != StackElement::AddFunction) {
+ m_error = QString::fromLatin1("argument modification requires function"
+ " modification as parent, was %1")
+ .arg(topElement.type, 0, 16);
+ return false;
+ }
+
+ QString index;
+ QString replaceValue;
+ bool resetAfterUse = false;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute()) {
+ index = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("replace-value")) {
+ replaceValue = attributes->takeAt(i).value().toString();
+ } else if (name == invalidateAfterUseAttribute()) {
+ resetAfterUse = convertBoolean(attributes->takeAt(i).value(),
+ invalidateAfterUseAttribute(), false);
+ }
+ }
+
+ if (index.isEmpty()) {
+ m_error = msgMissingAttribute(indexAttribute());
+ return false;
+ }
+
+ int idx;
+ if (!parseArgumentIndex(index, &idx, &m_error))
+ return false;
+
+ if (!replaceValue.isEmpty() && idx) {
+ m_error = QLatin1String("replace-value is only supported for return values (index=0).");
+ return false;
+ }
+
+ ArgumentModification argumentModification = ArgumentModification(idx);
+ argumentModification.replace_value = replaceValue;
+ argumentModification.resetAfterUse = resetAfterUse;
+ m_contextStack.top()->functionMods.last().argument_mods.append(argumentModification);
+ return true;
+}
+
+bool Handler::parseNoNullPointer(const QXmlStreamReader &reader,
+ const StackElement &topElement, QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("no-null-pointer requires argument modification as parent");
+ return false;
+ }
+
+ ArgumentModification &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods.last();
+ lastArgMod.noNullPointers = true;
+
+ const int defaultValueIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("default-value"));
+ if (defaultValueIndex != -1) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(defaultValueIndex);
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, attribute)));
+ }
+ return true;
+}
+
+bool Handler::parseDefineOwnership(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("define-ownership requires argument modification as parent");
+ return false;
+ }
+
+ TypeSystem::Language lang = TypeSystem::TargetLangCode;
+ QString ownership;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == classAttribute()) {
+ const QStringRef className = attributes->takeAt(i).value();
+ lang = languageFromAttribute(className);
+ if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(className);
+ return false;
+ }
+ } else if (name == ownershipAttribute()) {
+ ownership = attributes->takeAt(i).value().toString();
+ }
+ }
+ const TypeSystem::Ownership owner = ownershipFromFromAttribute(ownership);
+ if (owner == TypeSystem::InvalidOwnership) {
+ m_error = QStringLiteral("unsupported owner attribute: '%1'").arg(ownership);
+ return false;
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().ownerships[lang] = owner;
return true;
}
-bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts)
+bool Handler::parseArgumentMap(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::CodeSnipMask)) {
+ m_error = QLatin1String("Argument maps requires code injection as parent");
+ return false;
+ }
+
+ int pos = 1;
+ QString metaName;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute()) {
+ if (!parseIndex(attributes->takeAt(i).value().toString(), &pos, &m_error))
+ return false;
+ if (pos <= 0) {
+ m_error = QStringLiteral("Argument position %1 must be a positive number").arg(pos);
+ return false;
+ }
+ } else if (name == QLatin1String("meta-name")) {
+ metaName = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (metaName.isEmpty())
+ qCWarning(lcShiboken) << "Empty meta name in argument map";
+
+ if (topElement.type == StackElement::InjectCodeInFunction) {
+ m_contextStack.top()->functionMods.last().snips.last().argumentMap[pos] = metaName;
+ } else {
+ qCWarning(lcShiboken) << "Argument maps are only useful for injection of code "
+ "into functions.";
+ }
+ return true;
+}
+
+bool Handler::parseRemoval(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyFunction) {
+ m_error = QLatin1String("Function modification parent required");
+ return false;
+ }
+
+ TypeSystem::Language lang = TypeSystem::All;
+ const int classIndex = indexOfAttribute(*attributes, classAttribute());
+ if (classIndex != -1) {
+ const QStringRef value = attributes->takeAt(classIndex).value();
+ lang = languageFromAttribute(value);
+ if (lang == TypeSystem::TargetLangCode) // "target" means TargetLangAndNativeCode here
+ lang = TypeSystem::TargetLangAndNativeCode;
+ if (lang != TypeSystem::TargetLangAndNativeCode && lang != TypeSystem::All) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(value);
+ return false;
+ }
+ }
+ m_contextStack.top()->functionMods.last().removal = lang;
+ return true;
+}
+
+bool Handler::parseRename(const QXmlStreamReader &reader,
+ StackElement::ElementType type,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyField
+ && topElement.type != StackElement::ModifyFunction
+ && topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Function, field or argument modification parent required");
+ return false;
+ }
+
+ Modification *mod = nullptr;
+ if (topElement.type == StackElement::ModifyFunction)
+ mod = &m_contextStack.top()->functionMods.last();
+ else if (topElement.type == StackElement::ModifyField)
+ mod = &m_contextStack.top()->fieldMods.last();
+
+ Modification::Modifiers modifierFlag = Modification::Rename;
+ if (type == StackElement::Rename) {
+ const int toIndex = indexOfAttribute(*attributes, toAttribute());
+ if (toIndex == -1) {
+ m_error = msgMissingAttribute(toAttribute());
+ return false;
+ }
+ const QString renamed_to = attributes->takeAt(toIndex).value().toString();
+ if (topElement.type == StackElement::ModifyFunction)
+ mod->setRenamedTo(renamed_to);
+ else if (topElement.type == StackElement::ModifyField)
+ mod->setRenamedTo(renamed_to);
+ else
+ m_contextStack.top()->functionMods.last().argument_mods.last().renamed_to = renamed_to;
+ } else {
+ const int modifierIndex = indexOfAttribute(*attributes, modifierAttribute());
+ if (modifierIndex == -1) {
+ m_error = msgMissingAttribute(modifierAttribute());
+ return false;
+ }
+ const QStringRef modifier = attributes->takeAt(modifierIndex).value();
+ modifierFlag = modifierFromAttribute(modifier);
+ if (modifierFlag == Modification::InvalidModifier) {
+ m_error = QStringLiteral("Unknown access modifier: '%1'").arg(modifier);
+ return false;
+ }
+ if (modifierFlag == Modification::Friendly) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader, modifierAttribute(), modifier)));
+ }
+ }
+
+ if (mod)
+ mod->modifiers |= modifierFlag;
+ return true;
+}
+
+bool Handler::parseModifyField(const QXmlStreamReader &reader,
+ QXmlStreamAttributes *attributes)
+{
+ FieldModification fm;
+ fm.modifiers = FieldModification::Readable | FieldModification::Writable;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute()) {
+ fm.name = attributes->takeAt(i).value().toString();
+ } else if (name == removeAttribute()) {
+ if (!convertRemovalAttribute(attributes->takeAt(i).value(), fm, m_error))
+ return false;
+ } else if (name == readAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ if (!convertBoolean(attributes->takeAt(i).value(), readAttribute(), true))
+ fm.modifiers &= ~FieldModification::Readable;
+ } else if (name == writeAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ if (!convertBoolean(attributes->takeAt(i).value(), writeAttribute(), true))
+ fm.modifiers &= ~FieldModification::Writable;
+ }
+ }
+ if (fm.name.isEmpty()) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ m_contextStack.top()->fieldMods << fm;
+ return true;
+}
+
+bool Handler::parseAddFunction(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::Root))) {
+ m_error = QString::fromLatin1("Add function requires a complex type or a root tag as parent"
+ ", was=%1").arg(topElement.type, 0, 16);
+ return false;
+ }
+ QString originalSignature;
+ QString returnType = QLatin1String("void");
+ bool staticFunction = false;
+ QString access;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("signature")) {
+ originalSignature = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("return-type")) {
+ returnType = attributes->takeAt(i).value().toString();
+ } else if (name == staticAttribute()) {
+ staticFunction = convertBoolean(attributes->takeAt(i).value(),
+ staticAttribute(), false);
+ } else if (name == accessAttribute()) {
+ access = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ QString signature = TypeDatabase::normalizedSignature(originalSignature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for the added function");
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, QLatin1String("add-function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ AddedFunction func(signature, returnType);
+ func.setStatic(staticFunction);
+ if (!signature.contains(QLatin1Char('(')))
+ signature += QLatin1String("()");
+ m_currentSignature = signature;
+
+ if (!access.isEmpty()) {
+ const AddedFunction::Access a = addedFunctionAccessFromAttribute(access);
+ if (a == AddedFunction::InvalidAccess) {
+ m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+ return false;
+ }
+ func.setAccess(a);
+ }
+
+ m_contextStack.top()->addedFunctions << func;
+
+ FunctionModification mod;
+ if (!mod.setSignature(m_currentSignature, &m_error))
+ return false;
+ mod.setOriginalSignature(originalSignature);
+ m_contextStack.top()->functionMods << mod;
+ return true;
+}
+
+bool Handler::parseModifyFunction(const QXmlStreamReader &reader,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
+ m_error = QString::fromLatin1("Modify function requires complex type as parent"
+ ", was=%1").arg(topElement.type, 0, 16);
+ return false;
+ }
+
+ QString originalSignature;
+ QString access;
+ QString removal;
+ QString rename;
+ QString association;
+ bool deprecated = false;
+ bool isThread = false;
+ TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+ TypeSystem::AllowThread allowThread = TypeSystem::AllowThread::Unspecified;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("signature")) {
+ originalSignature = attributes->takeAt(i).value().toString();
+ } else if (name == accessAttribute()) {
+ access = attributes->takeAt(i).value().toString();
+ } else if (name == renameAttribute()) {
+ rename = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("associated-to")) {
+ association = attributes->takeAt(i).value().toString();
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == removeAttribute()) {
+ removal = attributes->takeAt(i).value().toString();
+ } else if (name == deprecatedAttribute()) {
+ deprecated = convertBoolean(attributes->takeAt(i).value(),
+ deprecatedAttribute(), false);
+ } else if (name == threadAttribute()) {
+ isThread = convertBoolean(attributes->takeAt(i).value(),
+ threadAttribute(), false);
+ } else if (name == allowThreadAttribute()) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(i);
+ allowThread = allowThreadFromAttribute(attribute.value());
+ if (allowThread == TypeSystem::AllowThread::Unspecified) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ } else if (name == exceptionHandlingAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ exceptionHandling = exceptionHandlingFromAttribute(attribute.value());
+ if (exceptionHandling == TypeSystem::ExceptionHandling::Unspecified) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == virtualSlotAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ }
+ }
+
+ const QString signature = TypeDatabase::normalizedSignature(originalSignature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for modified function");
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, QLatin1String("modify-function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ FunctionModification mod;
+ if (!mod.setSignature(signature, &m_error))
+ return false;
+ mod.setOriginalSignature(originalSignature);
+ mod.setExceptionHandling(exceptionHandling);
+ m_currentSignature = signature;
+
+ if (!access.isEmpty()) {
+ const Modification::Modifiers m = modifierFromAttribute(access);
+ if ((m & (Modification::AccessModifierMask | Modification::FinalMask)) == 0) {
+ m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+ return false;
+ }
+ if (m == Modification::Final || m == Modification::NonFinal) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader,
+ accessAttribute(), access)));
+ }
+ mod.modifiers |= m;
+ }
+
+ if (deprecated)
+ mod.modifiers |= Modification::Deprecated;
+
+ if (!removal.isEmpty() && !convertRemovalAttribute(removal, mod, m_error))
+ return false;
+
+ if (!rename.isEmpty()) {
+ mod.renamedToName = rename;
+ mod.modifiers |= Modification::Rename;
+ }
+
+ if (!association.isEmpty())
+ mod.association = association;
+
+ mod.setIsThread(isThread);
+ if (allowThread != TypeSystem::AllowThread::Unspecified)
+ mod.setAllowThread(allowThread);
+
+ m_contextStack.top()->functionMods << mod;
+ return true;
+}
+
+bool Handler::parseReplaceDefaultExpression(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::ModifyArgument)) {
+ m_error = QLatin1String("Replace default expression only allowed as child of argument modification");
+ return false;
+ }
+ const int withIndex = indexOfAttribute(*attributes, QStringViewLiteral("with"));
+ if (withIndex == -1 || attributes->at(withIndex).value().isEmpty()) {
+ m_error = QLatin1String("Default expression replaced with empty string. Use remove-default-expression instead.");
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().replacedDefaultExpression =
+ attributes->takeAt(withIndex).value().toString();
+ return true;
+}
+
+CustomFunction *
+ Handler::parseCustomMetaConstructor(const QXmlStreamReader &,
+ StackElement::ElementType type,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ QString functionName = topElement.entry->name().toLower()
+ + (type == StackElement::CustomMetaConstructor
+ ? QLatin1String("_create") : QLatin1String("_delete"));
+ QString paramName = QLatin1String("copy");
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute())
+ functionName = attributes->takeAt(i).value().toString();
+ else if (name == QLatin1String("param-name"))
+ paramName = attributes->takeAt(i).value().toString();
+ }
+ CustomFunction *func = new CustomFunction(functionName);
+ func->paramName = paramName;
+ return func;
+}
+
+bool Handler::parseReferenceCount(const QXmlStreamReader &reader,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("reference-count must be child of modify-argument");
+ return false;
+ }
+
+ ReferenceCount rc;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == actionAttribute()) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(i);
+ rc.action = referenceCountFromAttribute(attribute.value());
+ switch (rc.action) {
+ case ReferenceCount::Invalid:
+ m_error = QLatin1String("unrecognized value '") + attribute.value()
+ + QLatin1String("' for action attribute.");
+ return false;
+ case ReferenceCount::AddAll:
+ case ReferenceCount::Ignore:
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader, attribute)));
+ break;
+ default:
+ break;
+ }
+ } else if (name == QLatin1String("variable-name")) {
+ rc.varName = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().referenceCounts.append(rc);
+ return true;
+}
+
+bool Handler::parseParentOwner(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("parent-policy must be child of modify-argument");
+ return false;
+ }
+ ArgumentOwner ao;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef 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 QStringRef action = attributes->takeAt(i).value();
+ ao.action = argumentOwnerActionFromAttribute(action);
+ if (ao.action == ArgumentOwner::Invalid) {
+ m_error = QLatin1String("Invalid parent actionr '") + action + QLatin1String("'.");
+ return false;
+ }
+ }
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao;
+ return true;
+}
+
+bool Handler::parseInjectCode(const QXmlStreamReader &,
+ const StackElement &topElement,
+ StackElement* element, QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::ComplexTypeEntryMask)
+ && (topElement.type != StackElement::AddFunction)
+ && (topElement.type != StackElement::ModifyFunction)
+ && (topElement.type != StackElement::Root)) {
+ m_error = QLatin1String("wrong parent type for code injection");
+ return false;
+ }
+
+ TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionBeginning;
+ TypeSystem::Language lang = TypeSystem::TargetLangCode;
+ QString fileName;
+ QString snippetLabel;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == classAttribute()) {
+ const QStringRef className = attributes->takeAt(i).value();
+ lang = languageFromAttribute(className);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QStringLiteral("Invalid class specifier: '%1'").arg(className);
+ return false;
+ }
+ } else if (name == positionAttribute()) {
+ const QStringRef value = attributes->takeAt(i).value();
+ position = codeSnipPositionFromAttribute(value);
+ if (position == TypeSystem::CodeSnipPositionInvalid) {
+ m_error = QStringLiteral("Invalid position: '%1'").arg(value);
+ return false;
+ }
+ } else if (name == QLatin1String("file")) {
+ fileName = attributes->takeAt(i).value().toString();
+ } else if (name == snippetAttribute()) {
+ snippetLabel = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ CodeSnip snip;
+ snip.position = position;
+ snip.language = lang;
+ bool in_file = false;
+
+ // Handler constructor....
+ if (m_generate != TypeEntry::GenerateForSubclass &&
+ m_generate != TypeEntry::GenerateNothing &&
+ !fileName.isEmpty()) {
+ const QString resolved = m_database->modifiedTypesystemFilepath(fileName, m_currentPath);
+ if (QFile::exists(resolved)) {
+ QFile codeFile(resolved);
+ if (codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ QString content = QLatin1String("// ========================================================================\n"
+ "// START of custom code block [file: ");
+ content += fileName;
+ content += QLatin1String("]\n");
+ content += extractSnippet(QString::fromUtf8(codeFile.readAll()), snippetLabel);
+ content += QLatin1String("\n// END of custom code block [file: ");
+ content += fileName;
+ content += QLatin1String("]\n// ========================================================================\n");
+ snip.addCode(content);
+ in_file = true;
+ }
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "File for inject code not exist: " << QDir::toNativeSeparators(fileName);
+ }
+
+ }
+
+ if (snip.language == TypeSystem::Interface
+ && topElement.type != StackElement::InterfaceTypeEntry) {
+ m_error = QLatin1String("Interface code injections must be direct child of an interface type entry");
+ return false;
+ }
+
+ if (topElement.type == StackElement::ModifyFunction
+ || topElement.type == StackElement::AddFunction) {
+ if (snip.language == TypeSystem::ShellDeclaration) {
+ m_error = QLatin1String("no function implementation in shell declaration in which to inject code");
+ return false;
+ }
+
+ FunctionModification &mod = m_contextStack.top()->functionMods.last();
+ mod.snips << snip;
+ if (in_file)
+ mod.modifiers |= FunctionModification::CodeInjection;
+ element->type = StackElement::InjectCodeInFunction;
+ } else if (topElement.type == StackElement::Root) {
+ element->entry->addCodeSnip(snip);
+ } else if (topElement.type != StackElement::Root) {
+ m_contextStack.top()->codeSnips << snip;
+ }
+ return true;
+}
+
+bool Handler::parseInclude(const QXmlStreamReader &,
+ const StackElement &topElement,
+ TypeEntry *entry, QXmlStreamAttributes *attributes)
+{
+ QString fileName;
+ QString location;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("file-name"))
+ fileName = attributes->takeAt(i).value().toString();
+ else if (name == locationAttribute())
+ location = attributes->takeAt(i).value().toString();
+ }
+ const Include::IncludeType loc = locationFromAttribute(location);
+ if (loc == Include::InvalidInclude) {
+ m_error = QStringLiteral("Location not recognized: '%1'").arg(location);
+ return false;
+ }
+
+ Include inc(loc, fileName);
+ if (topElement.type
+ & (StackElement::ComplexTypeEntryMask | StackElement::PrimitiveTypeEntry)) {
+ entry->setInclude(inc);
+ } else if (topElement.type == StackElement::ExtraIncludes) {
+ entry->addExtraInclude(inc);
+ } else {
+ m_error = QLatin1String("Only supported parent tags are primitive-type, complex types or extra-includes");
+ return false;
+ }
+ if (InterfaceTypeEntry *di = entry->designatedInterface()) {
+ di->setInclude(entry->include());
+ di->setExtraIncludes(entry->extraIncludes());
+ }
+ return true;
+}
+
+TemplateInstance *
+ Handler::parseTemplateInstanceEnum(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::CodeSnipMask) &&
+ (topElement.type != StackElement::Template) &&
+ (topElement.type != StackElement::CustomMetaConstructor) &&
+ (topElement.type != StackElement::CustomMetaDestructor) &&
+ (topElement.type != StackElement::NativeToTarget) &&
+ (topElement.type != StackElement::AddConversion) &&
+ (topElement.type != StackElement::ConversionRule)) {
+ m_error = QLatin1String("Can only insert templates into code snippets, templates, custom-constructors, "\
+ "custom-destructors, conversion-rule, native-to-target or add-conversion tags.");
+ return nullptr;
+ }
+ const int nameIndex = indexOfAttribute(*attributes, nameAttribute());
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return nullptr;
+ }
+ return new TemplateInstance(attributes->takeAt(nameIndex).value().toString());
+}
+
+bool Handler::parseReplace(const QXmlStreamReader &,
+ const StackElement &topElement,
+ StackElement *element, QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::TemplateInstanceEnum) {
+ m_error = QLatin1String("Can only insert replace rules into insert-template.");
+ return false;
+ }
+ QString from;
+ QString to;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("from"))
+ from = attributes->takeAt(i).value().toString();
+ else if (name == toAttribute())
+ to = attributes->takeAt(i).value().toString();
+ }
+ element->parent->value.templateInstance->addReplaceRule(from, to);
+ return true;
+}
+
+bool Handler::startElement(const QXmlStreamReader &reader)
{
if (m_ignoreDepth) {
++m_ignoreDepth;
return true;
}
+ const QStringRef tagName = reader.name();
+ QXmlStreamAttributes attributes = reader.attributes();
+
QVersionNumber since(0, 0);
- const QStringRef sinceSpec = atts.value(sinceAttribute());
- if (!sinceSpec.isNull()) {
+ int index = indexOfAttribute(attributes, sinceAttribute());
+ if (index != -1) {
+ const QStringRef sinceSpec = attributes.takeAt(index).value();
since = QVersionNumber::fromString(sinceSpec.toString());
if (since.isNull()) {
m_error = msgInvalidVersion(sinceSpec, m_defaultPackage);
@@ -722,12 +2419,11 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
}
- const QString tagName = n.toString().toLower();
- if (tagName == QLatin1String("import-file"))
- return importFileElement(atts);
+ if (tagName.compare(QLatin1String("import-file"), Qt::CaseInsensitive) == 0)
+ return importFileElement(attributes);
- const QHash<QString, StackElement::ElementType>::const_iterator tit = tagNames.constFind(tagName);
- if (tit == tagNames.constEnd()) {
+ const StackElement::ElementType elementType = elementFromTag(tagName);
+ if (elementType == StackElement::None) {
m_error = QStringLiteral("Unknown tag name: '%1'").arg(tagName);
return false;
}
@@ -738,92 +2434,48 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
StackElement* element = new StackElement(m_current);
- element->type = tit.value();
+ element->type = elementType;
if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateAll)
customConversionsForReview.clear();
- if (element->type == StackElement::Root
- || element->type == StackElement::NamespaceTypeEntry
- || element->type == StackElement::InterfaceTypeEntry
- || element->type == StackElement::ObjectTypeEntry
- || element->type == StackElement::ValueTypeEntry
- || element->type == StackElement::PrimitiveTypeEntry) {
+ if (element->type == StackElement::CustomMetaConstructor
+ || element->type == StackElement::CustomMetaDestructor) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedElementWarning(reader, tagName)));
+ }
+
+ switch (element->type) {
+ case StackElement::Root:
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::PrimitiveTypeEntry:
+ case StackElement::TypedefTypeEntry:
m_contextStack.push(new StackElementContext());
+ break;
+ default:
+ break;
}
if (element->type & StackElement::TypeEntryMask) {
- QHash<QString, QString> attributes;
- attributes.insert(nameAttribute(), QString());
- attributes.insert(QLatin1String("revision"), QLatin1String("0"));
- attributes.insert(sinceAttribute(), QString()); // dummy for matching allowed attributes
-
- switch (element->type) {
- case StackElement::PrimitiveTypeEntry:
- attributes.insert(QLatin1String("target-lang-name"), QString());
- attributes.insert(QLatin1String("target-lang-api-name"), QString());
- attributes.insert(QLatin1String("preferred-conversion"), yesAttributeValue());
- attributes.insert(QLatin1String("preferred-target-lang-type"), yesAttributeValue());
- attributes.insert(QLatin1String("default-constructor"), QString());
- break;
- case StackElement::ContainerTypeEntry:
- attributes.insert(QLatin1String("type"), QString());
- break;
- case StackElement::SmartPointerTypeEntry:
- attributes.insert(QLatin1String("type"), QString());
- attributes.insert(QLatin1String("getter"), QString());
- attributes.insert(QLatin1String("ref-count-method"), QString());
- break;
- case StackElement::EnumTypeEntry:
- attributes.insert(flagsAttribute(), QString());
- attributes.insert(QLatin1String("flags-revision"), QString());
- attributes.insert(QLatin1String("upper-bound"), QString());
- attributes.insert(QLatin1String("lower-bound"), QString());
- attributes.insert(QLatin1String("force-integer"), noAttributeValue());
- attributes.insert(QLatin1String("extensible"), noAttributeValue());
- attributes.insert(enumIdentifiedByValueAttribute(), QString());
- attributes.insert(classAttribute(), falseAttributeValue());
- break;
- case StackElement::ValueTypeEntry:
- attributes.insert(QLatin1String("default-constructor"), QString());
- Q_FALLTHROUGH();
- case StackElement::ObjectTypeEntry:
- attributes.insert(QLatin1String("force-abstract"), noAttributeValue());
- attributes.insert(QLatin1String("deprecated"), noAttributeValue());
- attributes.insert(QLatin1String("hash-function"), QString());
- attributes.insert(QLatin1String("stream"), noAttributeValue());
- Q_FALLTHROUGH();
- case StackElement::InterfaceTypeEntry:
- attributes[QLatin1String("default-superclass")] = m_defaultSuperclass;
- attributes.insert(QLatin1String("polymorphic-id-expression"), QString());
- attributes.insert(QLatin1String("delete-in-main-thread"), noAttributeValue());
- attributes.insert(QLatin1String("held-type"), QString());
- attributes.insert(QLatin1String("copyable"), QString());
- Q_FALLTHROUGH();
- case StackElement::NamespaceTypeEntry:
- attributes.insert(QLatin1String("target-lang-name"), QString());
- attributes[QLatin1String("package")] = m_defaultPackage;
- attributes.insert(QLatin1String("expense-cost"), QLatin1String("1"));
- attributes.insert(QLatin1String("expense-limit"), QLatin1String("none"));
- attributes.insert(QLatin1String("polymorphic-base"), noAttributeValue());
- attributes.insert(QLatin1String("generate"), yesAttributeValue());
- attributes.insert(QLatin1String("target-type"), QString());
- attributes.insert(QLatin1String("generic-class"), noAttributeValue());
- break;
- case StackElement::FunctionTypeEntry:
- attributes.insert(QLatin1String("signature"), QString());
- attributes.insert(QLatin1String("rename"), QString());
- break;
- default:
- { } // nada
- };
-
- fetchAttributeValues(tagName, atts, &attributes);
- QString name = attributes[nameAttribute()];
+ QString name;
+ if (element->type != StackElement::FunctionTypeEntry) {
+ const int nameIndex = indexOfAttribute(attributes, nameAttribute());
+ if (nameIndex != -1) {
+ name = attributes.takeAt(nameIndex).value().toString();
+ } else if (element->type != StackElement::EnumTypeEntry) { // anonymous enum?
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ }
if (m_database->hasDroppedTypeEntries()) {
QString identifier = getNamePrefix(element) + QLatin1Char('.');
- identifier += (element->type == StackElement::FunctionTypeEntry ? attributes[QLatin1String("signature")] : name);
+ identifier += element->type == StackElement::FunctionTypeEntry
+ ? attributes.value(signatureAttribute()).toString()
+ : name;
if (m_database->shouldDropTypeEntry(identifier)) {
m_currentDroppedEntry = element;
m_currentDroppedEntryDepth = 1;
@@ -837,30 +2489,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
// The top level tag 'function' has only the 'signature' tag
// and we should extract the 'name' value from it.
- if (element->type == StackElement::FunctionTypeEntry) {
- QString signature = attributes[QLatin1String("signature")];
- name = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
- QString errorString = checkSignatureError(signature, QLatin1String("function"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
+ if (element->type == StackElement::FunctionTypeEntry
+ && !parseRenameFunction(reader, &name, &attributes)) {
return false;
- }
- QString rename = attributes[QLatin1String("rename")];
- if (!rename.isEmpty()) {
- static const QRegularExpression functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$"));
- Q_ASSERT(functionNameRegExp.isValid());
- if (!functionNameRegExp.match(rename).hasMatch()) {
- m_error = QLatin1String("can not rename '") + signature + QLatin1String("', '")
- + rename + QLatin1String("' is not a valid function name");
- return false;
- }
- FunctionModification mod;
- if (!mod.setSignature(signature, &m_error))
- return false;
- mod.renamedToName = attributes[QLatin1String("rename")];
- mod.modifiers |= Modification::Rename;
- m_contextStack.top()->functionMods << mod;
- }
}
// We need to be able to have duplicate primitive type entries,
@@ -875,7 +2506,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
if (element->type == StackElement::EnumTypeEntry) {
- const QString identifiedByValue = attributes.value(enumIdentifiedByValueAttribute());
+ const int enumIdentifiedByIndex = indexOfAttribute(attributes, enumIdentifiedByValueAttribute());
+ const QString identifiedByValue = enumIdentifiedByIndex != -1
+ ? attributes.takeAt(enumIdentifiedByIndex).value().toString() : QString();
if (name.isEmpty()) {
name = identifiedByValue;
} else if (!identifiedByValue.isEmpty()) {
@@ -900,281 +2533,92 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
case StackElement::CustomTypeEntry:
element->entry = new TypeEntry(name, TypeEntry::CustomType, since);
break;
- case StackElement::PrimitiveTypeEntry: {
- QString targetLangName = attributes[QLatin1String("target-lang-name")];
- QString targetLangApiName = attributes[QLatin1String("target-lang-api-name")];
- QString preferredConversion = attributes[QLatin1String("preferred-conversion")].toLower();
- QString preferredTargetLangType = attributes[QLatin1String("preferred-target-lang-type")].toLower();
- QString defaultConstructor = attributes[QLatin1String("default-constructor")];
-
- if (targetLangName.isEmpty())
- targetLangName = name;
- if (targetLangApiName.isEmpty())
- targetLangApiName = name;
-
- PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name, since);
- type->setCodeGeneration(m_generate);
- type->setTargetLangName(targetLangName);
- type->setTargetLangApiName(targetLangApiName);
- type->setTargetLangPackage(m_defaultPackage);
- type->setDefaultConstructor(defaultConstructor);
-
- bool preferred;
- preferred = convertBoolean(preferredConversion, QLatin1String("preferred-conversion"), true);
- type->setPreferredConversion(preferred);
- preferred = convertBoolean(preferredTargetLangType,
- QLatin1String("preferred-target-lang-type"), true);
- type->setPreferredTargetLangType(preferred);
-
- element->entry = type;
- }
- break;
-
- case StackElement::ContainerTypeEntry: {
- QString typeName = attributes[QLatin1String("type")];
- ContainerTypeEntry::Type containerType =
- ContainerTypeEntry::containerTypeFromString(typeName);
- if (typeName.isEmpty()) {
- m_error = QLatin1String("no 'type' attribute specified");
+ case StackElement::PrimitiveTypeEntry:
+ element->entry = parsePrimitiveTypeEntry(reader, name, since, &attributes);
+ if (Q_UNLIKELY(!element->entry))
return false;
- } else if (containerType == ContainerTypeEntry::NoContainer) {
- m_error = QLatin1String("there is no container of type ") + typeName;
+ break;
+ case StackElement::ContainerTypeEntry:
+ if (ContainerTypeEntry *ce = parseContainerTypeEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, ce, &attributes);
+ element->entry = ce;
+ } else {
return false;
}
+ break;
- ContainerTypeEntry *type = new ContainerTypeEntry(name, containerType, since);
- type->setCodeGeneration(m_generate);
- element->entry = type;
- }
- break;
-
- case StackElement::SmartPointerTypeEntry: {
- bool result = handleSmartPointerEntry(element, attributes, name, since);
- if (!result)
- return result;
- }
- break;
-
- case StackElement::EnumTypeEntry: {
- QStringList names = name.split(colonColon());
- if (names.size() == 1)
- m_currentEnum = new EnumTypeEntry(QString(), name, since);
- else
- m_currentEnum =
- new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join(colonColon()),
- names.constLast(), since);
- element->entry = m_currentEnum;
- m_currentEnum->setCodeGeneration(m_generate);
- m_currentEnum->setTargetLangPackage(m_defaultPackage);
- m_currentEnum->setUpperBound(attributes[QLatin1String("upper-bound")]);
- m_currentEnum->setLowerBound(attributes[QLatin1String("lower-bound")]);
- m_currentEnum->setForceInteger(convertBoolean(attributes[QLatin1String("force-integer")], QLatin1String("force-integer"), false));
- m_currentEnum->setExtensible(convertBoolean(attributes[QLatin1String("extensible")], QLatin1String("extensible"), false));
-
- // put in the flags parallel...
- const QString flagNames = attributes.value(flagsAttribute());
- if (!flagNames.isEmpty()) {
- const QStringList &flagNameList = flagNames.split(QLatin1Char(','));
- for (const QString &flagName : flagNameList)
- addFlags(name, flagName.trimmed(), attributes, since);
+ case StackElement::SmartPointerTypeEntry:
+ if (SmartPointerTypeEntry *se = parseSmartPointerEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, se, &attributes);
+ element->entry = se;
+ } else {
+ return false;
}
- }
- break;
+ break;
+ case StackElement::EnumTypeEntry:
+ m_currentEnum = parseEnumTypeEntry(reader, name, since, &attributes);
+ if (Q_UNLIKELY(!m_currentEnum))
+ return false;
+ element->entry = m_currentEnum;
+ break;
- case StackElement::InterfaceTypeEntry: {
- ObjectTypeEntry *otype = new ObjectTypeEntry(name, since);
- QString targetLangName = attributes[QLatin1String("target-lang-name")];
- if (targetLangName.isEmpty())
- targetLangName = name;
- InterfaceTypeEntry *itype =
- new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), since);
-
- if (!convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true))
- itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
- else
- itype->setCodeGeneration(m_generate);
- otype->setDesignatedInterface(itype);
- itype->setOrigin(otype);
- element->entry = otype;
- }
- Q_FALLTHROUGH();
- case StackElement::ValueTypeEntry: {
- if (!element->entry) {
- ValueTypeEntry* typeEntry = new ValueTypeEntry(name, since);
- QString defaultConstructor = attributes[QLatin1String("default-constructor")];
- if (!defaultConstructor.isEmpty())
- typeEntry->setDefaultConstructor(defaultConstructor);
- element->entry = typeEntry;
+ case StackElement::InterfaceTypeEntry:
+ if (ObjectTypeEntry *oe = parseInterfaceTypeEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, oe, &attributes);
+ element->entry = oe;
+ } else {
+ return false;
}
-
- Q_FALLTHROUGH();
+ break;
+ case StackElement::ValueTypeEntry:
+ if (ValueTypeEntry *ve = parseValueTypeEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, ve, &attributes);
+ element->entry = ve;
+ } else {
+ return false;
+ }
+ break;
case StackElement::NamespaceTypeEntry:
- if (!element->entry)
- element->entry = new NamespaceTypeEntry(name, since);
-
- Q_FALLTHROUGH();
+ element->entry = new NamespaceTypeEntry(name, since);
+ applyCommonAttributes(element->entry, &attributes);
+ applyComplexTypeAttributes(reader, static_cast<ComplexTypeEntry *>(element->entry), &attributes);
+ break;
case StackElement::ObjectTypeEntry:
- if (!element->entry)
- element->entry = new ObjectTypeEntry(name, since);
-
- element->entry->setStream(attributes[QLatin1String("stream")] == yesAttributeValue());
-
- ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
- ctype->setTargetLangPackage(attributes[QLatin1String("package")]);
- ctype->setDefaultSuperclass(attributes[QLatin1String("default-superclass")]);
- ctype->setGenericClass(convertBoolean(attributes[QLatin1String("generic-class")], QLatin1String("generic-class"), false));
-
- if (!convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true))
- element->entry->setCodeGeneration(TypeEntry::GenerateForSubclass);
- else
- element->entry->setCodeGeneration(m_generate);
-
- QString targetLangName = attributes[QLatin1String("target-lang-name")];
- if (!targetLangName.isEmpty())
- ctype->setTargetLangName(targetLangName);
-
- ctype->setIsPolymorphicBase(convertBoolean(attributes[QLatin1String("polymorphic-base")], QLatin1String("polymorphic-base"), false));
- ctype->setPolymorphicIdValue(attributes[QLatin1String("polymorphic-id-expression")]);
- //Copyable
- if (attributes[QLatin1String("copyable")].isEmpty())
- ctype->setCopyable(ComplexTypeEntry::Unknown);
- else {
- if (convertBoolean(attributes[QLatin1String("copyable")], QLatin1String("copyable"), false))
- ctype->setCopyable(ComplexTypeEntry::CopyableSet);
- else
- ctype->setCopyable(ComplexTypeEntry::NonCopyableSet);
-
- }
-
- if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry)
- ctype->setHashFunction(attributes[QLatin1String("hash-function")]);
-
-
- ctype->setHeldType(attributes[QLatin1String("held-type")]);
-
- if (element->type == StackElement::ObjectTypeEntry
- || element->type == StackElement::ValueTypeEntry) {
- if (convertBoolean(attributes[QLatin1String("force-abstract")], QLatin1String("force-abstract"), false))
- ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
- if (convertBoolean(attributes[QLatin1String("deprecated")], QLatin1String("deprecated"), false))
- ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
- }
-
- if (element->type == StackElement::InterfaceTypeEntry
- || element->type == StackElement::ValueTypeEntry
- || element->type == StackElement::ObjectTypeEntry) {
- if (convertBoolean(attributes[QLatin1String("delete-in-main-thread")], QLatin1String("delete-in-main-thread"), false))
- ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread);
- }
-
- QString targetType = attributes[QLatin1String("target-type")];
- if (!targetType.isEmpty() && element->entry->isComplex())
- static_cast<ComplexTypeEntry *>(element->entry)->setTargetType(targetType);
-
- // ctype->setInclude(Include(Include::IncludePath, ctype->name()));
- ctype = ctype->designatedInterface();
- if (ctype)
- ctype->setTargetLangPackage(attributes[QLatin1String("package")]);
-
- }
- break;
- case StackElement::FunctionTypeEntry: {
- QString signature = attributes[QLatin1String("signature")];
- signature = TypeDatabase::normalizedSignature(signature);
- element->entry = m_database->findType(name);
- if (element->entry) {
- if (element->entry->type() == TypeEntry::FunctionType) {
- reinterpret_cast<FunctionTypeEntry*>(element->entry)->addSignature(signature);
- } else {
- m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.")
- .arg(name);
- return false;
- }
+ element->entry = new ObjectTypeEntry(name, since);
+ applyCommonAttributes(element->entry, &attributes);
+ applyComplexTypeAttributes(reader, static_cast<ComplexTypeEntry *>(element->entry), &attributes);
+ break;
+ case StackElement::FunctionTypeEntry:
+ element->entry = parseFunctionTypeEntry(reader, name, since, &attributes);
+ if (Q_UNLIKELY(!element->entry))
+ return false;
+ break;
+ case StackElement::TypedefTypeEntry:
+ if (TypedefEntry *te = parseTypedefEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, te, &attributes);
+ element->entry = te;
} else {
- element->entry = new FunctionTypeEntry(name, signature, since);
- element->entry->setCodeGeneration(m_generate);
+ return false;
}
- }
- break;
+ break;
default:
Q_ASSERT(false);
};
if (element->entry) {
- m_database->addType(element->entry);
- setTypeRevision(element->entry, attributes[QLatin1String("revision")].toInt());
+ if (!m_database->addType(element->entry, &m_error))
+ return false;
} else {
qCWarning(lcShiboken).noquote().nospace()
<< QStringLiteral("Type: %1 was rejected by typesystem").arg(name);
}
} else if (element->type == StackElement::InjectDocumentation) {
- // check the XML tag attributes
- QHash<QString, QString> attributes;
- attributes.insert(QLatin1String("mode"), QLatin1String("replace"));
- attributes.insert(QLatin1String("format"), QLatin1String("native"));
- attributes.insert(sinceAttribute(), QString()); // dummy for matching allowed attributes
-
- fetchAttributeValues(tagName, atts, &attributes);
-
- const int validParent = StackElement::TypeEntryMask
- | StackElement::ModifyFunction
- | StackElement::ModifyField;
- if (m_current->parent && m_current->parent->type & validParent) {
- QString modeName = attributes[QLatin1String("mode")];
- TypeSystem::DocModificationMode mode;
- if (modeName == QLatin1String("append")) {
- mode = TypeSystem::DocModificationAppend;
- } else if (modeName == QLatin1String("prepend")) {
- mode = TypeSystem::DocModificationPrepend;
- } else if (modeName == QLatin1String("replace")) {
- mode = TypeSystem::DocModificationReplace;
- } else {
- m_error = QLatin1String("Unknow documentation injection mode: ") + modeName;
- return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode;
- languageNames[QLatin1String("native")] = TypeSystem::NativeCode;
- }
-
- QString format = attributes[QLatin1String("format")].toLower();
- TypeSystem::Language lang = languageNames.value(format, TypeSystem::NoLanguage);
- if (lang == TypeSystem::NoLanguage) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(format);
- return false;
- }
-
- QString signature = m_current->type & StackElement::TypeEntryMask ? QString() : m_currentSignature;
- DocModification mod(mode, signature);
- mod.setFormat(lang);
- m_contextStack.top()->docModifications << mod;
- } else {
- m_error = QLatin1String("inject-documentation must be inside modify-function, "
- "modify-field or other tags that creates a type");
+ if (!parseInjectDocumentation(reader, &attributes))
return false;
- }
} else if (element->type == StackElement::ModifyDocumentation) {
- // check the XML tag attributes
- QHash<QString, QString> attributes;
- attributes.insert(xPathAttribute(), QString());
- attributes.insert(sinceAttribute(), QString()); // dummy for matching allowed attributes
- fetchAttributeValues(tagName, atts, &attributes);
-
- const int validParent = StackElement::TypeEntryMask
- | StackElement::ModifyFunction
- | StackElement::ModifyField;
- if (m_current->parent && m_current->parent->type & validParent) {
- QString signature = (m_current->type & StackElement::TypeEntryMask) ? QString() : m_currentSignature;
- m_contextStack.top()->docModifications
- << DocModification(attributes.value(xPathAttribute()), signature);
- } else {
- m_error = QLatin1String("modify-documentation must be inside modify-function, "
- "modify-field or other tags that creates a type");
+ if (!parseModifyDocumentation(reader, &attributes))
return false;
- }
} else if (element->type != StackElement::None) {
bool topLevel = element->type == StackElement::Root
|| element->type == StackElement::SuppressedWarning
@@ -1194,494 +2638,89 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
StackElement topElement = !m_current ? StackElement(0) : *m_current;
element->entry = topElement.entry;
- QHash<QString, QString> attributes;
- attributes.insert(sinceAttribute(), QString()); // dummy for matching allowed attributes
switch (element->type) {
case StackElement::Root:
- attributes.insert(QLatin1String("package"), QString());
- attributes.insert(QLatin1String("default-superclass"), QString());
+ element->entry = parseRootElement(reader, since, &attributes);
+ element->type = StackElement::Root;
break;
case StackElement::LoadTypesystem:
- attributes.insert(nameAttribute(), QString());
- attributes.insert(QLatin1String("generate"), yesAttributeValue());
- break;
- case StackElement::NoNullPointers:
- attributes.insert(QLatin1String("default-value"), QString());
- break;
- case StackElement::SuppressedWarning:
- attributes.insert(textAttribute(), QString());
- break;
- case StackElement::ReplaceDefaultExpression:
- attributes.insert(QLatin1String("with"), QString());
- break;
- case StackElement::DefineOwnership:
- attributes.insert(QLatin1String("class"), QLatin1String("target"));
- attributes.insert(QLatin1String("owner"), QString());
- break;
- case StackElement::AddFunction:
- attributes.insert(QLatin1String("signature"), QString());
- attributes.insert(QLatin1String("return-type"), QLatin1String("void"));
- attributes.insert(QLatin1String("access"), QLatin1String("public"));
- attributes.insert(QLatin1String("static"), noAttributeValue());
- break;
- case StackElement::ModifyFunction:
- attributes.insert(QLatin1String("signature"), QString());
- attributes.insert(QLatin1String("access"), QString());
- attributes.insert(QLatin1String("remove"), QString());
- attributes.insert(QLatin1String("rename"), QString());
- attributes.insert(QLatin1String("deprecated"), noAttributeValue());
- attributes.insert(QLatin1String("associated-to"), QString());
- attributes.insert(QLatin1String("virtual-slot"), noAttributeValue());
- attributes.insert(QLatin1String("thread"), noAttributeValue());
- attributes.insert(QLatin1String("allow-thread"), noAttributeValue());
- break;
- case StackElement::ModifyArgument:
- attributes.insert(QLatin1String("index"), QString());
- attributes.insert(QLatin1String("replace-value"), QString());
- attributes.insert(QLatin1String("invalidate-after-use"), noAttributeValue());
- break;
- case StackElement::ModifyField:
- attributes.insert(nameAttribute(), QString());
- attributes.insert(QLatin1String("write"), trueAttributeValue());
- attributes.insert(QLatin1String("read"), trueAttributeValue());
- attributes.insert(QLatin1String("remove"), QString());
- break;
- case StackElement::Access:
- attributes.insert(QLatin1String("modifier"), QString());
- break;
- case StackElement::Include:
- attributes.insert(QLatin1String("file-name"), QString());
- attributes.insert(QLatin1String("location"), QString());
- break;
- case StackElement::CustomMetaConstructor:
- attributes[nameAttribute()] = topElement.entry->name().toLower() + QLatin1String("_create");
- attributes.insert(QLatin1String("param-name"), QLatin1String("copy"));
+ if (!loadTypesystem(reader, &attributes))
+ return false;
break;
- case StackElement::CustomMetaDestructor:
- attributes[nameAttribute()] = topElement.entry->name().toLower() + QLatin1String("_delete");
- attributes.insert(QLatin1String("param-name"), QLatin1String("copy"));
+ case StackElement::RejectEnumValue:
+ if (!parseRejectEnumValue(reader, &attributes))
+ return false;
break;
case StackElement::ReplaceType:
- attributes.insert(QLatin1String("modified-type"), QString());
- break;
- case StackElement::InjectCode:
- attributes.insert(QLatin1String("class"), QLatin1String("target"));
- attributes.insert(QLatin1String("position"), QLatin1String("beginning"));
- attributes.insert(QLatin1String("file"), QString());
+ if (!parseReplaceArgumentType(reader, topElement, &attributes))
+ return false;
break;
case StackElement::ConversionRule:
- attributes.insert(QLatin1String("class"), QString());
- attributes.insert(QLatin1String("file"), QString());
- break;
- case StackElement::TargetToNative:
- attributes.insert(QLatin1String("replace"), yesAttributeValue());
- break;
- case StackElement::AddConversion:
- attributes.insert(QLatin1String("type"), QString());
- attributes.insert(QLatin1String("check"), QString());
- break;
- case StackElement::RejectEnumValue:
- attributes.insert(nameAttribute(), QString());
- break;
- case StackElement::ArgumentMap:
- attributes.insert(QLatin1String("index"), QLatin1String("1"));
- attributes.insert(QLatin1String("meta-name"), QString());
- break;
- case StackElement::Rename:
- attributes.insert(QLatin1String("to"), QString());
- break;
- case StackElement::Rejection:
- attributes.insert(classAttribute(), QString());
- attributes.insert(functionNameAttribute(), QString());
- attributes.insert(fieldNameAttribute(), QString());
- attributes.insert(enumNameAttribute(), QString());
- attributes.insert(argumentTypeAttribute(), QString());
- attributes.insert(returnTypeAttribute(), QString());
- break;
- case StackElement::Removal:
- attributes.insert(QLatin1String("class"), QLatin1String("all"));
- break;
- case StackElement::Template:
- attributes.insert(nameAttribute(), QString());
- break;
- case StackElement::TemplateInstanceEnum:
- attributes.insert(nameAttribute(), QString());
- break;
- case StackElement::Replace:
- attributes.insert(QLatin1String("from"), QString());
- attributes.insert(QLatin1String("to"), QString());
- break;
- case StackElement::ReferenceCount:
- attributes.insert(QLatin1String("action"), QString());
- attributes.insert(QLatin1String("variable-name"), QString());
- break;
- case StackElement::ParentOwner:
- attributes.insert(QLatin1String("index"), QString());
- attributes.insert(QLatin1String("action"), QString());
- break;
- case StackElement::Array:
- break;
- default:
- { };
- };
-
- if (!attributes.isEmpty())
- fetchAttributeValues(tagName, atts, &attributes);
-
- switch (element->type) {
- case StackElement::Root:
- m_defaultPackage = attributes[QLatin1String("package")];
- m_defaultSuperclass = attributes[QLatin1String("default-superclass")];
- element->type = StackElement::Root;
- {
- TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(
- m_database->findType(m_defaultPackage));
- element->entry = moduleEntry ? moduleEntry : new TypeSystemTypeEntry(m_defaultPackage, since);
- element->entry->setCodeGeneration(m_generate);
- }
-
- if ((m_generate == TypeEntry::GenerateForSubclass ||
- m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty())
- TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage);
-
- if (!element->entry->qualifiedCppName().isEmpty())
- m_database->addType(element->entry);
- break;
- case StackElement::LoadTypesystem: {
- QString name = attributes[nameAttribute()];
- if (name.isEmpty()) {
- m_error = QLatin1String("No typesystem name specified");
- return false;
- }
- bool generateChild = (convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true) && (m_generate == TypeEntry::GenerateAll));
- if (!m_database->parseFile(name, m_currentPath, generateChild)) {
- m_error = QStringLiteral("Failed to parse: '%1'").arg(name);
- return false;
- }
- }
- break;
- case StackElement::RejectEnumValue:
- if (!m_currentEnum) {
- m_error = QLatin1String("<reject-enum-value> node must be used inside a <enum-type> node");
- return false;
- }
- break;
- case StackElement::ReplaceType: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("Type replacement can only be specified for argument modifications");
- return false;
- }
-
- if (attributes[QLatin1String("modified-type")].isEmpty()) {
- m_error = QLatin1String("Type replacement requires 'modified-type' attribute");
+ if (!Handler::parseCustomConversion(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().modified_type = attributes[QLatin1String("modified-type")];
- }
- break;
- case StackElement::ConversionRule: {
- if (topElement.type != StackElement::ModifyArgument
- && topElement.type != StackElement::ValueTypeEntry
- && topElement.type != StackElement::PrimitiveTypeEntry
- && topElement.type != StackElement::ContainerTypeEntry) {
- m_error = QLatin1String("Conversion rules can only be specified for argument modification, "
- "value-type, primitive-type or container-type conversion.");
- return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode;
- languageNames[QLatin1String("native")] = TypeSystem::NativeCode;
- }
-
- QString languageAttribute = attributes[QLatin1String("class")].toLower();
- TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
-
- if (topElement.type == StackElement::ModifyArgument) {
- if (lang == TypeSystem::NoLanguage) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(lang);
- return false;
- }
-
- CodeSnip snip;
- snip.language = lang;
- m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.append(snip);
- } else {
- if (topElement.entry->hasConversionRule() || topElement.entry->hasCustomConversion()) {
- m_error = QLatin1String("Types can have only one conversion rule");
- return false;
- }
-
- // The old conversion rule tag that uses a file containing the conversion
- // will be kept temporarily for compatibility reasons.
- QString sourceFile = attributes[QLatin1String("file")];
- if (!sourceFile.isEmpty()) {
- if (m_generate != TypeEntry::GenerateForSubclass
- && m_generate != TypeEntry::GenerateNothing) {
-
- const char* conversionFlag = NATIVE_CONVERSION_RULE_FLAG;
- if (lang == TypeSystem::TargetLangCode)
- conversionFlag = TARGET_CONVERSION_RULE_FLAG;
-
- QFile conversionSource(sourceFile);
- if (conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) {
- topElement.entry->setConversionRule(QLatin1String(conversionFlag) + QString::fromUtf8(conversionSource.readAll()));
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << "File containing conversion code for "
- << topElement.entry->name() << " type does not exist or is not readable: "
- << sourceFile;
- }
- }
- }
-
- CustomConversion* customConversion = new CustomConversion(static_cast<TypeEntry*>(m_current->entry));
- customConversionsForReview.append(customConversion);
- }
- }
- break;
- case StackElement::NativeToTarget: {
+ break;
+ case StackElement::NativeToTarget:
if (topElement.type != StackElement::ConversionRule) {
m_error = QLatin1String("Native to Target conversion code can only be specified for custom conversion rules.");
return false;
}
m_contextStack.top()->codeSnips << CodeSnip();
- }
- break;
+ break;
case StackElement::TargetToNative: {
if (topElement.type != StackElement::ConversionRule) {
m_error = QLatin1String("Target to Native conversions can only be specified for custom conversion rules.");
return false;
}
- bool replace = attributes[QLatin1String("replace")] == yesAttributeValue();
- static_cast<TypeEntry*>(m_current->entry)->customConversion()->setReplaceOriginalTargetToNativeConversions(replace);
+ const int replaceIndex = indexOfAttribute(attributes, replaceAttribute());
+ const bool replace = replaceIndex == -1
+ || convertBoolean(attributes.takeAt(replaceIndex).value(),
+ replaceAttribute(), true);
+ m_current->entry->customConversion()->setReplaceOriginalTargetToNativeConversions(replace);
}
break;
- case StackElement::AddConversion: {
- if (topElement.type != StackElement::TargetToNative) {
- m_error = QLatin1String("Target to Native conversions can only be added inside 'target-to-native' tags.");
- return false;
- }
- QString sourceTypeName = attributes[QLatin1String("type")];
- if (sourceTypeName.isEmpty()) {
- m_error = QLatin1String("Target to Native conversions must specify the input type with the 'type' attribute.");
- return false;
- }
- QString typeCheck = attributes[QLatin1String("check")];
- static_cast<TypeEntry*>(m_current->entry)->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck);
- m_contextStack.top()->codeSnips << CodeSnip();
- }
- break;
- case StackElement::ModifyArgument: {
- if (topElement.type != StackElement::ModifyFunction
- && topElement.type != StackElement::AddFunction) {
- m_error = QString::fromLatin1("argument modification requires function"
- " modification as parent, was %1")
- .arg(topElement.type, 0, 16);
- return false;
- }
-
- QString index = attributes[QLatin1String("index")];
- if (index == QLatin1String("return"))
- index = QLatin1String("0");
- else if (index == QLatin1String("this"))
- index = QLatin1String("-1");
-
- bool ok = false;
- int idx = index.toInt(&ok);
- if (!ok) {
- m_error = QStringLiteral("Cannot convert '%1' to integer").arg(index);
- return false;
- }
-
- QString replace_value = attributes[QLatin1String("replace-value")];
-
- if (!replace_value.isEmpty() && idx) {
- m_error = QLatin1String("replace-value is only supported for return values (index=0).");
- return false;
- }
-
- ArgumentModification argumentModification = ArgumentModification(idx);
- argumentModification.replace_value = replace_value;
- argumentModification.resetAfterUse = convertBoolean(attributes[QLatin1String("invalidate-after-use")], QLatin1String("invalidate-after-use"), false);
- m_contextStack.top()->functionMods.last().argument_mods.append(argumentModification);
- }
- break;
- case StackElement::NoNullPointers: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("no-null-pointer requires argument modification as parent");
+ case StackElement::AddConversion:
+ if (!parseAddConversion(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().noNullPointers = true;
- if (!m_contextStack.top()->functionMods.last().argument_mods.last().index)
- m_contextStack.top()->functionMods.last().argument_mods.last().nullPointerDefaultValue = attributes[QLatin1String("default-value")];
- else if (!attributes[QLatin1String("default-value")].isEmpty())
- qCWarning(lcShiboken) << "default values for null pointer guards are only effective for return values";
-
- }
- break;
- case StackElement::DefineOwnership: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("define-ownership requires argument modification as parent");
+ break;
+ case StackElement::ModifyArgument:
+ if (!parseModifyArgument(reader, topElement, &attributes))
return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode;
- languageNames[QLatin1String("native")] = TypeSystem::NativeCode;
- }
-
- QString classAttribute = attributes[QLatin1String("class")].toLower();
- TypeSystem::Language lang = languageNames.value(classAttribute, TypeSystem::NoLanguage);
- if (lang == TypeSystem::NoLanguage) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(classAttribute);
+ break;
+ case StackElement::NoNullPointers:
+ if (!parseNoNullPointer(reader, topElement, &attributes))
return false;
- }
-
- static QHash<QString, TypeSystem::Ownership> ownershipNames;
- if (ownershipNames.isEmpty()) {
- ownershipNames[QLatin1String("target")] = TypeSystem::TargetLangOwnership;
- ownershipNames[QLatin1String("c++")] = TypeSystem::CppOwnership;
- ownershipNames[QLatin1String("default")] = TypeSystem::DefaultOwnership;
- }
-
- QString ownershipAttribute = attributes[QLatin1String("owner")].toLower();
- TypeSystem::Ownership owner = ownershipNames.value(ownershipAttribute, TypeSystem::InvalidOwnership);
- if (owner == TypeSystem::InvalidOwnership) {
- m_error = QStringLiteral("unsupported owner attribute: '%1'").arg(ownershipAttribute);
+ break;
+ case StackElement::DefineOwnership:
+ if (!parseDefineOwnership(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().ownerships[lang] = owner;
- }
- break;
+ break;
case StackElement::SuppressedWarning: {
- const QString suppressedWarning = attributes.value(textAttribute());
- if (suppressedWarning.isEmpty()) {
+ const int 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_database->addSuppressedWarning(suppressedWarning, &m_error))
return false;
}
}
break;
- case StackElement::ArgumentMap: {
- if (!(topElement.type & StackElement::CodeSnipMask)) {
- m_error = QLatin1String("Argument maps requires code injection as parent");
- return false;
- }
-
- bool ok;
- int pos = attributes[QLatin1String("index")].toInt(&ok);
- if (!ok) {
- m_error = QStringLiteral("Can't convert position '%1' to integer")
- .arg(attributes[QLatin1String("position")]);
- return false;
- }
-
- if (pos <= 0) {
- m_error = QStringLiteral("Argument position %1 must be a positive number").arg(pos);
- return false;
- }
-
- QString meta_name = attributes[QLatin1String("meta-name")];
- if (meta_name.isEmpty())
- qCWarning(lcShiboken) << "Empty meta name in argument map";
-
-
- if (topElement.type == StackElement::InjectCodeInFunction)
- m_contextStack.top()->functionMods.last().snips.last().argumentMap[pos] = meta_name;
- else {
- qCWarning(lcShiboken) << "Argument maps are only useful for injection of code "
- "into functions.";
- }
- }
- break;
- case StackElement::Removal: {
- if (topElement.type != StackElement::ModifyFunction) {
- m_error = QLatin1String("Function modification parent required");
+ case StackElement::ArgumentMap:
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedElementWarning(reader, tagName)));
+ if (!parseArgumentMap(reader, topElement, &attributes))
return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames.insert(QLatin1String("target"), TypeSystem::TargetLangAndNativeCode);
- languageNames.insert(QLatin1String("all"), TypeSystem::All);
- }
-
- QString languageAttribute = attributes[QLatin1String("class")].toLower();
- TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
- if (lang == TypeSystem::NoLanguage) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(languageAttribute);
+ break;
+ case StackElement::Removal:
+ if (!parseRemoval(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().removal = lang;
- }
- break;
+ break;
case StackElement::Rename:
- case StackElement::Access: {
- if (topElement.type != StackElement::ModifyField
- && topElement.type != StackElement::ModifyFunction
- && topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("Function, field or argument modification parent required");
- return false;
- }
-
- Modification *mod = 0;
- if (topElement.type == StackElement::ModifyFunction)
- mod = &m_contextStack.top()->functionMods.last();
- else if (topElement.type == StackElement::ModifyField)
- mod = &m_contextStack.top()->fieldMods.last();
-
- QString modifier;
- if (element->type == StackElement::Rename) {
- modifier = QLatin1String("rename");
- QString renamed_to = attributes[QLatin1String("to")];
- if (renamed_to.isEmpty()) {
- m_error = QLatin1String("Rename modifier requires 'to' attribute");
- return false;
- }
-
- if (topElement.type == StackElement::ModifyFunction)
- mod->setRenamedTo(renamed_to);
- else if (topElement.type == StackElement::ModifyField)
- mod->setRenamedTo(renamed_to);
- else
- m_contextStack.top()->functionMods.last().argument_mods.last().renamed_to = renamed_to;
- } else
- modifier = attributes[QLatin1String("modifier")].toLower();
-
-
- if (modifier.isEmpty()) {
- m_error = QLatin1String("No access modification specified");
- return false;
- }
-
- static QHash<QString, FunctionModification::Modifiers> modifierNames;
- if (modifierNames.isEmpty()) {
- modifierNames[QLatin1String("private")] = Modification::Private;
- modifierNames[QLatin1String("public")] = Modification::Public;
- modifierNames[QLatin1String("protected")] = Modification::Protected;
- modifierNames[QLatin1String("friendly")] = Modification::Friendly;
- modifierNames[QLatin1String("rename")] = Modification::Rename;
- modifierNames[QLatin1String("final")] = Modification::Final;
- modifierNames[QLatin1String("non-final")] = Modification::NonFinal;
- }
-
- if (!modifierNames.contains(modifier)) {
- m_error = QStringLiteral("Unknown access modifier: '%1'").arg(modifier);
+ case StackElement::Access:
+ if (!parseRename(reader, element->type, topElement, &attributes))
return false;
- }
-
- if (mod)
- mod->modifiers |= modifierNames[modifier];
- }
- break;
+ break;
case StackElement::RemoveArgument:
if (topElement.type != StackElement::ModifyArgument) {
m_error = QLatin1String("Removing argument requires argument modification as parent");
@@ -1691,229 +2730,38 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
m_contextStack.top()->functionMods.last().argument_mods.last().removed = true;
break;
- case StackElement::ModifyField: {
- QString name = attributes[nameAttribute()];
- if (name.isEmpty())
- break;
- FieldModification fm;
- fm.name = name;
- fm.modifiers = 0;
-
- if (!convertRemovalAttribute(attributes[QLatin1String("remove")], fm, m_error))
- return false;
-
- QString read = attributes[QLatin1String("read")];
- QString write = attributes[QLatin1String("write")];
-
- if (read == trueAttributeValue()) fm.modifiers |= FieldModification::Readable;
- if (write == trueAttributeValue()) fm.modifiers |= FieldModification::Writable;
-
- m_contextStack.top()->fieldMods << fm;
- }
- break;
- case StackElement::AddFunction: {
- if (!(topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::Root))) {
- m_error = QString::fromLatin1("Add function requires a complex type or a root tag as parent"
- ", was=%1").arg(topElement.type, 0, 16);
- return false;
- }
- const QString originalSignature = attributes[QLatin1String("signature")];
-
- QString signature = TypeDatabase::normalizedSignature(originalSignature);
- if (signature.isEmpty()) {
- m_error = QLatin1String("No signature for the added function");
- return false;
- }
-
- QString errorString = checkSignatureError(signature, QLatin1String("add-function"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
- return false;
- }
-
- AddedFunction func(signature, attributes[QLatin1String("return-type")]);
- func.setStatic(attributes[QLatin1String("static")] == yesAttributeValue());
- if (!signature.contains(QLatin1Char('(')))
- signature += QLatin1String("()");
- m_currentSignature = signature;
-
- QString access = attributes[QLatin1String("access")].toLower();
- if (!access.isEmpty()) {
- if (access == QLatin1String("protected")) {
- func.setAccess(AddedFunction::Protected);
- } else if (access == QLatin1String("public")) {
- func.setAccess(AddedFunction::Public);
- } else {
- m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
- return false;
- }
- }
-
- m_contextStack.top()->addedFunctions << func;
-
- FunctionModification mod;
- if (!mod.setSignature(m_currentSignature, &m_error))
- return false;
- mod.setOriginalSignature(originalSignature);
- m_contextStack.top()->functionMods << mod;
- }
- break;
- case StackElement::ModifyFunction: {
- if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
- m_error = QString::fromLatin1("Modify function requires complex type as parent"
- ", was=%1").arg(topElement.type, 0, 16);
- return false;
- }
- const QString originalSignature = attributes[QLatin1String("signature")];
-
- const QString signature = TypeDatabase::normalizedSignature(originalSignature);
- if (signature.isEmpty()) {
- m_error = QLatin1String("No signature for modified function");
- return false;
- }
-
- QString errorString = checkSignatureError(signature, QLatin1String("modify-function"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
+ case StackElement::ModifyField:
+ if (!parseModifyField(reader, &attributes))
return false;
- }
-
- FunctionModification mod;
- if (!mod.setSignature(signature, &m_error))
+ break;
+ case StackElement::AddFunction:
+ if (!parseAddFunction(reader, topElement, &attributes))
return false;
- mod.setOriginalSignature(originalSignature);
- m_currentSignature = signature;
-
- QString access = attributes[QLatin1String("access")].toLower();
- if (!access.isEmpty()) {
- if (access == QLatin1String("private"))
- mod.modifiers |= Modification::Private;
- else if (access == QLatin1String("protected"))
- mod.modifiers |= Modification::Protected;
- else if (access == QLatin1String("public"))
- mod.modifiers |= Modification::Public;
- else if (access == QLatin1String("final"))
- mod.modifiers |= Modification::Final;
- else if (access == QLatin1String("non-final"))
- mod.modifiers |= Modification::NonFinal;
- else {
- m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
- return false;
- }
- }
-
- if (convertBoolean(attributes[QLatin1String("deprecated")], QLatin1String("deprecated"), false))
- mod.modifiers |= Modification::Deprecated;
-
- if (!convertRemovalAttribute(attributes[QLatin1String("remove")], mod, m_error))
+ break;
+ case StackElement::ModifyFunction:
+ if (!parseModifyFunction(reader, topElement, &attributes))
return false;
-
- QString rename = attributes[QLatin1String("rename")];
- if (!rename.isEmpty()) {
- mod.renamedToName = rename;
- mod.modifiers |= Modification::Rename;
- }
-
- QString association = attributes[QLatin1String("associated-to")];
- if (!association.isEmpty())
- mod.association = association;
-
- mod.setIsThread(convertBoolean(attributes[QLatin1String("thread")], QLatin1String("thread"), false));
- mod.setAllowThread(convertBoolean(attributes[QLatin1String("allow-thread")], QLatin1String("allow-thread"), false));
-
- mod.modifiers |= (convertBoolean(attributes[QLatin1String("virtual-slot")], QLatin1String("virtual-slot"), false) ? Modification::VirtualSlot : 0);
-
- m_contextStack.top()->functionMods << mod;
- }
- break;
+ break;
case StackElement::ReplaceDefaultExpression:
- if (!(topElement.type & StackElement::ModifyArgument)) {
- m_error = QLatin1String("Replace default expression only allowed as child of argument modification");
- return false;
- }
-
- if (attributes[QLatin1String("with")].isEmpty()) {
- m_error = QLatin1String("Default expression replaced with empty string. Use remove-default-expression instead.");
+ if (!parseReplaceDefaultExpression(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().replacedDefaultExpression = attributes[QLatin1String("with")];
break;
case StackElement::RemoveDefaultExpression:
m_contextStack.top()->functionMods.last().argument_mods.last().removedDefaultExpression = true;
break;
case StackElement::CustomMetaConstructor:
- case StackElement::CustomMetaDestructor: {
- CustomFunction *func = new CustomFunction(attributes[nameAttribute()]);
- func->paramName = attributes[QLatin1String("param-name")];
- element->value.customFunction = func;
- }
- break;
- case StackElement::ReferenceCount: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("reference-count must be child of modify-argument");
- return false;
- }
-
- ReferenceCount rc;
-
- static QHash<QString, ReferenceCount::Action> actions;
- if (actions.isEmpty()) {
- actions[QLatin1String("add")] = ReferenceCount::Add;
- actions[QLatin1String("add-all")] = ReferenceCount::AddAll;
- actions[QLatin1String("remove")] = ReferenceCount::Remove;
- actions[QLatin1String("set")] = ReferenceCount::Set;
- actions[QLatin1String("ignore")] = ReferenceCount::Ignore;
- }
- rc.action = actions.value(attributes[QLatin1String("action")].toLower(), ReferenceCount::Invalid);
- rc.varName = attributes[QLatin1String("variable-name")];
-
- if (rc.action == ReferenceCount::Invalid) {
- m_error = QLatin1String("unrecognized value for action attribute. supported actions:");
- for (QHash<QString, ReferenceCount::Action>::const_iterator it = actions.cbegin(), end = actions.cend(); it != end; ++it)
- m_error += QLatin1Char(' ') + it.key();
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().referenceCounts.append(rc);
- }
- break;
-
- case StackElement::ParentOwner: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("parent-policy must be child of modify-argument");
- return false;
- }
-
- ArgumentOwner ao;
-
- QString index = attributes[QLatin1String("index")];
- if (index == QLatin1String("return"))
- index = QLatin1String("0");
- else if (index == QLatin1String("this"))
- index = QLatin1String("-1");
-
- bool ok = false;
- int idx = index.toInt(&ok);
- if (!ok) {
- m_error = QStringLiteral("Cannot convert '%1' to integer").arg(index);
+ case StackElement::CustomMetaDestructor:
+ element->value.customFunction =
+ parseCustomMetaConstructor(reader, element->type, topElement, &attributes);
+ break;
+ case StackElement::ReferenceCount:
+ if (!parseReferenceCount(reader, topElement, &attributes))
return false;
- }
-
- static QHash<QString, ArgumentOwner::Action> actions;
- if (actions.isEmpty()) {
- actions[QLatin1String("add")] = ArgumentOwner::Add;
- actions[QLatin1String("remove")] = ArgumentOwner::Remove;
- }
-
- ao.action = actions.value(attributes[QLatin1String("action")].toLower(), ArgumentOwner::Invalid);
- if (!ao.action) {
- m_error = QLatin1String("Invalid parent actionr");
+ break;
+ case StackElement::ParentOwner:
+ if (!parseParentOwner(reader, topElement, &attributes))
return false;
- }
- ao.index = idx;
- m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao;
- }
- break;
+ break;
case StackElement::Array:
if (topElement.type != StackElement::ModifyArgument) {
m_error = QLatin1String("array must be child of modify-argument");
@@ -1921,185 +2769,54 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
m_contextStack.top()->functionMods.last().argument_mods.last().array = true;
break;
- case StackElement::InjectCode: {
- if (!(topElement.type & StackElement::ComplexTypeEntryMask)
- && (topElement.type != StackElement::AddFunction)
- && (topElement.type != StackElement::ModifyFunction)
- && (topElement.type != StackElement::Root)) {
- m_error = QLatin1String("wrong parent type for code injection");
- return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode; // em algum lugar do cpp
- languageNames[QLatin1String("native")] = TypeSystem::NativeCode; // em algum lugar do cpp
- languageNames[QLatin1String("shell")] = TypeSystem::ShellCode; // coloca no header, mas antes da declaracao da classe
- languageNames[QLatin1String("shell-declaration")] = TypeSystem::ShellDeclaration; // coloca no header, dentro da declaracao da classe
- languageNames[QLatin1String("library-initializer")] = TypeSystem::PackageInitializer;
- languageNames[QLatin1String("destructor-function")] = TypeSystem::DestructorFunction;
- languageNames[QLatin1String("constructors")] = TypeSystem::Constructors;
- languageNames[QLatin1String("interface")] = TypeSystem::Interface;
- }
-
- QString className = attributes[QLatin1String("class")].toLower();
- if (!languageNames.contains(className)) {
- m_error = QStringLiteral("Invalid class specifier: '%1'").arg(className);
- return false;
- }
-
-
- static QHash<QString, TypeSystem::CodeSnipPosition> positionNames;
- if (positionNames.isEmpty()) {
- positionNames.insert(QLatin1String("beginning"), TypeSystem::CodeSnipPositionBeginning);
- positionNames.insert(QLatin1String("end"), TypeSystem::CodeSnipPositionEnd);
- // QtScript
- positionNames.insert(QLatin1String("declaration"), TypeSystem::CodeSnipPositionDeclaration);
- positionNames.insert(QLatin1String("prototype-initialization"), TypeSystem::CodeSnipPositionPrototypeInitialization);
- positionNames.insert(QLatin1String("constructor-initialization"), TypeSystem::CodeSnipPositionConstructorInitialization);
- positionNames.insert(QLatin1String("constructor"), TypeSystem::CodeSnipPositionConstructor);
- }
-
- QString position = attributes[QLatin1String("position")].toLower();
- if (!positionNames.contains(position)) {
- m_error = QStringLiteral("Invalid position: '%1'").arg(position);
+ case StackElement::InjectCode:
+ if (!parseInjectCode(reader, topElement, element, &attributes))
return false;
- }
-
- CodeSnip snip;
- snip.language = languageNames[className];
- snip.position = positionNames[position];
- bool in_file = false;
-
- QString file_name = attributes[QLatin1String("file")];
-
- //Handler constructor....
- if (m_generate != TypeEntry::GenerateForSubclass &&
- m_generate != TypeEntry::GenerateNothing &&
- !file_name.isEmpty()) {
- const QString resolved = m_database->modifiedTypesystemFilepath(file_name, m_currentPath);
- if (QFile::exists(resolved)) {
- QFile codeFile(resolved);
- if (codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
- QString content = QLatin1String("// ========================================================================\n"
- "// START of custom code block [file: ");
- content += file_name;
- content += QLatin1String("]\n");
- content += QString::fromUtf8(codeFile.readAll());
- content += QLatin1String("\n// END of custom code block [file: ");
- content += file_name;
- content += QLatin1String("]\n// ========================================================================\n");
- snip.addCode(content);
- in_file = true;
- }
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << "File for inject code not exist: " << QDir::toNativeSeparators(file_name);
- }
-
- }
-
- if (snip.language == TypeSystem::Interface && topElement.type != StackElement::InterfaceTypeEntry) {
- m_error = QLatin1String("Interface code injections must be direct child of an interface type entry");
+ break;
+ case StackElement::Include:
+ if (!parseInclude(reader, topElement, element->entry, &attributes))
return false;
- }
-
- if (topElement.type == StackElement::ModifyFunction || topElement.type == StackElement::AddFunction) {
- FunctionModification mod = m_contextStack.top()->functionMods.constLast();
- if (snip.language == TypeSystem::ShellDeclaration) {
- m_error = QLatin1String("no function implementation in shell declaration in which to inject code");
- return false;
- }
-
- m_contextStack.top()->functionMods.last().snips << snip;
- if (in_file)
- m_contextStack.top()->functionMods.last().modifiers |= FunctionModification::CodeInjection;
- element->type = StackElement::InjectCodeInFunction;
- } else if (topElement.type == StackElement::Root) {
- element->entry->addCodeSnip(snip);
- } else if (topElement.type != StackElement::Root) {
- m_contextStack.top()->codeSnips << snip;
- }
-
- }
- break;
- case StackElement::Include: {
- QString location = attributes[QLatin1String("location")].toLower();
-
- static QHash<QString, Include::IncludeType> locationNames;
- if (locationNames.isEmpty()) {
- locationNames[QLatin1String("global")] = Include::IncludePath;
- locationNames[QLatin1String("local")] = Include::LocalPath;
- locationNames[QLatin1String("target")] = Include::TargetLangImport;
- }
-
- if (!locationNames.contains(location)) {
- m_error = QStringLiteral("Location not recognized: '%1'").arg(location);
+ break;
+ case StackElement::Rejection:
+ if (!addRejection(m_database, &attributes, &m_error))
return false;
- }
-
- Include::IncludeType loc = locationNames[location];
- Include inc(loc, attributes[QLatin1String("file-name")]);
-
- ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
- if (topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::PrimitiveTypeEntry)) {
- element->entry->setInclude(inc);
- } else if (topElement.type == StackElement::ExtraIncludes) {
- element->entry->addExtraInclude(inc);
- } else {
- m_error = QLatin1String("Only supported parent tags are primitive-type, complex types or extra-includes");
+ break;
+ case StackElement::Template: {
+ const int nameIndex = indexOfAttribute(attributes, nameAttribute());
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute());
return false;
}
-
- inc = ctype->include();
- IncludeList lst = ctype->extraIncludes();
- ctype = ctype->designatedInterface();
- if (ctype) {
- ctype->setExtraIncludes(lst);
- ctype->setInclude(inc);
- }
+ element->value.templateEntry =
+ new TemplateEntry(attributes.takeAt(nameIndex).value().toString());
}
- break;
- case StackElement::Rejection:
- if (!addRejection(m_database, attributes, &m_error))
- return false;
- break;
- case StackElement::Template:
- element->value.templateEntry = new TemplateEntry(attributes.value(nameAttribute()));
break;
case StackElement::TemplateInstanceEnum:
- if (!(topElement.type & StackElement::CodeSnipMask) &&
- (topElement.type != StackElement::Template) &&
- (topElement.type != StackElement::CustomMetaConstructor) &&
- (topElement.type != StackElement::CustomMetaDestructor) &&
- (topElement.type != StackElement::NativeToTarget) &&
- (topElement.type != StackElement::AddConversion) &&
- (topElement.type != StackElement::ConversionRule)) {
- m_error = QLatin1String("Can only insert templates into code snippets, templates, custom-constructors, "\
- "custom-destructors, conversion-rule, native-to-target or add-conversion tags.");
+ element->value.templateInstance =
+ parseTemplateInstanceEnum(reader, topElement, &attributes);
+ if (!element->value.templateInstance)
return false;
- }
- element->value.templateInstance = new TemplateInstance(attributes.value(nameAttribute()));
break;
case StackElement::Replace:
- if (topElement.type != StackElement::TemplateInstanceEnum) {
- m_error = QLatin1String("Can only insert replace rules into insert-template.");
+ if (!parseReplace(reader, topElement, element, &attributes))
return false;
- }
- element->parent->value.templateInstance->addReplaceRule(attributes[QLatin1String("from")], attributes[QLatin1String("to")]);
break;
default:
break; // nada
};
}
+ if (!attributes.isEmpty()) {
+ const QString message = msgUnusedAttributes(tagName, attributes);
+ qCWarning(lcShiboken, "%s", qPrintable(msgReaderWarning(reader, message)));
+ }
+
m_current = element;
return true;
}
PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &name, const QVersionNumber &vr) :
TypeEntry(name, PrimitiveType, vr),
- m_preferredConversion(true),
m_preferredTargetLangType(true)
{
}
@@ -2120,35 +2837,15 @@ PrimitiveTypeEntry *PrimitiveTypeEntry::basicReferencedTypeEntry() const
return 0;
PrimitiveTypeEntry *baseReferencedTypeEntry = m_referencedTypeEntry->basicReferencedTypeEntry();
- if (baseReferencedTypeEntry)
- return baseReferencedTypeEntry;
- else
- return m_referencedTypeEntry;
-}
-
-bool PrimitiveTypeEntry::preferredConversion() const
-{
- return m_preferredConversion;
+ return baseReferencedTypeEntry ? baseReferencedTypeEntry : m_referencedTypeEntry;
}
-void PrimitiveTypeEntry::setPreferredConversion(bool b)
+TypeEntry *PrimitiveTypeEntry::clone() const
{
- m_preferredConversion = b;
+ return new PrimitiveTypeEntry(*this);
}
-typedef QHash<const PrimitiveTypeEntry*, QString> PrimitiveTypeEntryTargetLangPackageMap;
-Q_GLOBAL_STATIC(PrimitiveTypeEntryTargetLangPackageMap, primitiveTypeEntryTargetLangPackages);
-
-void PrimitiveTypeEntry::setTargetLangPackage(const QString& package)
-{
- primitiveTypeEntryTargetLangPackages()->insert(this, package);
-}
-QString PrimitiveTypeEntry::targetLangPackage() const
-{
- if (!primitiveTypeEntryTargetLangPackages()->contains(this))
- return this->::TypeEntry::targetLangPackage();
- return primitiveTypeEntryTargetLangPackages()->value(this);
-}
+PrimitiveTypeEntry::PrimitiveTypeEntry(const PrimitiveTypeEntry &) = default;
CodeSnipList TypeEntry::codeSnips() const
{
@@ -2186,42 +2883,42 @@ FieldModification ComplexTypeEntry::fieldModification(const QString &name) const
return mod;
}
-QString ComplexTypeEntry::targetLangPackage() const
-{
- return m_package;
-}
-
QString ComplexTypeEntry::targetLangName() const
{
return m_targetLangName.isEmpty() ?
TypeEntry::targetLangName() : m_targetLangName;
}
-// The things we do not to break the ABI...
-typedef QHash<const ComplexTypeEntry*, QString> ComplexTypeEntryDefaultConstructorMap;
-Q_GLOBAL_STATIC(ComplexTypeEntryDefaultConstructorMap, complexTypeEntryDefaultConstructors);
-
void ComplexTypeEntry::setDefaultConstructor(const QString& defaultConstructor)
{
- if (!defaultConstructor.isEmpty())
- complexTypeEntryDefaultConstructors()->insert(this, defaultConstructor);
+ m_defaultConstructor = defaultConstructor;
}
QString ComplexTypeEntry::defaultConstructor() const
{
- if (!complexTypeEntryDefaultConstructors()->contains(this))
- return QString();
- return complexTypeEntryDefaultConstructors()->value(this);
+ return m_defaultConstructor;
}
bool ComplexTypeEntry::hasDefaultConstructor() const
{
- return complexTypeEntryDefaultConstructors()->contains(this);
+ return !m_defaultConstructor.isEmpty();
}
-QString ContainerTypeEntry::targetLangPackage() const
+TypeEntry *ComplexTypeEntry::clone() const
{
- return QString();
+ return new ComplexTypeEntry(*this);
}
+// Take over parameters relevant for typedefs
+void ComplexTypeEntry::useAsTypedef(const ComplexTypeEntry *source)
+{
+ TypeEntry::useAsTypedef(source);
+ m_qualifiedCppName = source->m_qualifiedCppName;
+ m_targetLangName = source->m_targetLangName;
+ m_lookupName = source->m_lookupName;
+ m_targetType = source->m_targetType;
+}
+
+ComplexTypeEntry::ComplexTypeEntry(const ComplexTypeEntry &) = default;
+
QString ContainerTypeEntry::targetLangName() const
{
@@ -2252,13 +2949,17 @@ QString ContainerTypeEntry::qualifiedCppName() const
return ComplexTypeEntry::qualifiedCppName();
}
+TypeEntry *ContainerTypeEntry::clone() const
+{
+ return new ContainerTypeEntry(*this);
+}
+
+ContainerTypeEntry::ContainerTypeEntry(const ContainerTypeEntry &) = default;
+
QString EnumTypeEntry::targetLangQualifier() const
{
TypeEntry *te = TypeDatabase::instance()->findType(m_qualifier);
- if (te)
- return te->targetLangName();
- else
- return m_qualifier;
+ return te ? te->targetLangName() : m_qualifier;
}
QString EnumTypeEntry::qualifiedTargetLangName() const
@@ -2281,26 +2982,25 @@ QString EnumTypeEntry::targetLangApiName() const
return QLatin1String("jint");
}
-bool EnumTypeEntry::preferredConversion() const
-{
- return false;
-}
-
QString FlagsTypeEntry::targetLangApiName() const
{
return QLatin1String("jint");
}
-bool FlagsTypeEntry::preferredConversion() const
+TypeEntry *EnumTypeEntry::clone() const
{
- return false;
+ return new EnumTypeEntry(*this);
}
-QString FlagsTypeEntry::targetLangPackage() const
+EnumTypeEntry::EnumTypeEntry(const EnumTypeEntry &) = default;
+
+TypeEntry *FlagsTypeEntry::clone() const
{
- return m_enum->targetLangPackage();
+ return new FlagsTypeEntry(*this);
}
+FlagsTypeEntry::FlagsTypeEntry(const FlagsTypeEntry &) = default;
+
QString FlagsTypeEntry::qualifiedTargetLangName() const
{
return targetLangPackage() + QLatin1Char('.') + m_enum->targetLangQualifier()
@@ -2320,7 +3020,7 @@ QString fixCppTypeName(const QString &name)
{
if (name == QLatin1String("long long"))
return QLatin1String("qint64");
- else if (name == QLatin1String("unsigned long long"))
+ if (name == QLatin1String("unsigned long long"))
return QLatin1String("quint64");
return name;
}
@@ -2341,11 +3041,9 @@ QString TemplateInstance::expandCode() const
result += code;
result += QLatin1String("\n// TEMPLATE - ") + m_name + QLatin1String(" - END");
return result;
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << "insert-template referring to non-existing template '" << m_name << '\'';
}
-
+ qCWarning(lcShiboken).noquote().nospace()
+ << "insert-template referring to non-existing template '" << m_name << '\'';
return QString();
}
@@ -2361,10 +3059,7 @@ QString CodeSnipAbstract::code() const
QString CodeSnipFragment::code() const
{
- if (m_instance)
- return m_instance->expandCode();
- else
- return m_code;
+ return m_instance ? m_instance->expandCode() : m_code;
}
bool FunctionModification::setSignature(const QString &s, QString *errorMessage)
@@ -2556,11 +3251,12 @@ AddedFunction::TypeInfo AddedFunction::TypeInfo::fromSignature(const QString& si
ComplexTypeEntry::ComplexTypeEntry(const QString &name, TypeEntry::Type t,
const QVersionNumber &vr) :
- TypeEntry(QString(name).replace(QLatin1String(".*::"), QString()), t, vr),
+ TypeEntry(name, t, vr),
m_qualifiedCppName(name),
m_qobject(false),
m_polymorphicBase(false),
- m_genericClass(false)
+ m_genericClass(false),
+ m_deleteInMainThread(false)
{
}
@@ -2578,71 +3274,6 @@ QString ComplexTypeEntry::targetLangApiName() const
{
return strings_jobject;
}
-QString StringTypeEntry::targetLangApiName() const
-{
- return strings_jobject;
-}
-QString StringTypeEntry::targetLangName() const
-{
- return strings_String;
-}
-QString StringTypeEntry::targetLangPackage() const
-{
- return QString();
-}
-
-bool StringTypeEntry::isNativeIdBased() const
-{
- return false;
-}
-
-CharTypeEntry::CharTypeEntry(const QString &name, const QVersionNumber &vr) :
- ValueTypeEntry(name, CharType, vr)
-{
- setCodeGeneration(GenerateNothing);
-}
-
-QString CharTypeEntry::targetLangApiName() const
-{
- return strings_jchar;
-}
-QString CharTypeEntry::targetLangName() const
-{
- return strings_char;
-}
-
-QString CharTypeEntry::targetLangPackage() const
-{
- return QString();
-}
-
-bool CharTypeEntry::isNativeIdBased() const
-{
- return false;
-}
-
-VariantTypeEntry::VariantTypeEntry(const QString &name, const QVersionNumber &vr) :
- ValueTypeEntry(name, VariantType, vr)
-{
-}
-
-QString VariantTypeEntry::targetLangApiName() const
-{
- return strings_jobject;
-}
-QString VariantTypeEntry::targetLangName() const
-{
- return strings_Object;
-}
-QString VariantTypeEntry::targetLangPackage() const
-{
- return QString();
-}
-
-bool VariantTypeEntry::isNativeIdBased() const
-{
- return false;
-}
QString ContainerTypeEntry::typeName() const
{
@@ -2706,10 +3337,6 @@ bool TypeEntry::isCppPrimitive() const
return typeName.contains(QLatin1Char(' ')) || primitiveCppTypes().contains(typeName);
}
-// Again, stuff to avoid ABI breakage.
-typedef QHash<const TypeEntry*, CustomConversion*> TypeEntryCustomConversionMap;
-Q_GLOBAL_STATIC(TypeEntryCustomConversionMap, typeEntryCustomConversionMap);
-
TypeEntry::TypeEntry(const QString &name, TypeEntry::Type t, const QVersionNumber &vr) :
m_name(name),
m_type(t),
@@ -2719,51 +3346,88 @@ TypeEntry::TypeEntry(const QString &name, TypeEntry::Type t, const QVersionNumbe
TypeEntry::~TypeEntry()
{
- if (typeEntryCustomConversionMap()->contains(this)) {
- CustomConversion* customConversion = typeEntryCustomConversionMap()->value(this);
- typeEntryCustomConversionMap()->remove(this);
- delete customConversion;
- }
+ delete m_customConversion;
}
bool TypeEntry::hasCustomConversion() const
{
- return typeEntryCustomConversionMap()->contains(this);
+ return m_customConversion != nullptr;
}
+
void TypeEntry::setCustomConversion(CustomConversion* customConversion)
{
- if (customConversion)
- typeEntryCustomConversionMap()->insert(this, customConversion);
- else if (typeEntryCustomConversionMap()->contains(this))
- typeEntryCustomConversionMap()->remove(this);
+ m_customConversion = customConversion;
}
+
CustomConversion* TypeEntry::customConversion() const
{
- if (typeEntryCustomConversionMap()->contains(this))
- return typeEntryCustomConversionMap()->value(this);
- return 0;
+ return m_customConversion;
+}
+
+TypeEntry *TypeEntry::clone() const
+{
+ return new TypeEntry(*this);
}
+// Take over parameters relevant for typedefs
+void TypeEntry::useAsTypedef(const TypeEntry *source)
+{
+ m_name = source->m_name;
+ m_targetLangPackage = source->m_targetLangPackage;
+ m_codeGeneration = source->m_codeGeneration;
+ m_version = source->m_version;
+}
+
+TypeEntry::TypeEntry(const TypeEntry &) = default;
+
TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &name, const QVersionNumber &vr) :
TypeEntry(name, TypeSystemType, vr)
{
}
+TypeEntry *TypeSystemTypeEntry::clone() const
+{
+ return new TypeSystemTypeEntry(*this);
+}
+
+TypeSystemTypeEntry::TypeSystemTypeEntry(const TypeSystemTypeEntry &) = default;
+
VoidTypeEntry::VoidTypeEntry() :
TypeEntry(QLatin1String("void"), VoidType, QVersionNumber(0, 0))
{
}
+TypeEntry *VoidTypeEntry::clone() const
+{
+ return new VoidTypeEntry(*this);
+}
+
+VoidTypeEntry::VoidTypeEntry(const VoidTypeEntry &) = default;
+
VarargsTypeEntry::VarargsTypeEntry() :
TypeEntry(QLatin1String("..."), VarargsType, QVersionNumber(0, 0))
{
}
+TypeEntry *VarargsTypeEntry::clone() const
+{
+ return new VarargsTypeEntry(*this);
+}
+
+VarargsTypeEntry::VarargsTypeEntry(const VarargsTypeEntry &) = default;
+
TemplateArgumentEntry::TemplateArgumentEntry(const QString &name, const QVersionNumber &vr) :
TypeEntry(name, TemplateArgumentType, vr)
{
}
+TypeEntry *TemplateArgumentEntry::clone() const
+{
+ return new TemplateArgumentEntry(*this);
+}
+
+TemplateArgumentEntry::TemplateArgumentEntry(const TemplateArgumentEntry &) = default;
+
ArrayTypeEntry::ArrayTypeEntry(const TypeEntry *nested_type, const QVersionNumber &vr) :
TypeEntry(QLatin1String("Array"), ArrayType, vr),
m_nestedType(nested_type)
@@ -2778,12 +3442,18 @@ QString ArrayTypeEntry::targetLangName() const
QString ArrayTypeEntry::targetLangApiName() const
{
- if (m_nestedType->isPrimitive())
- return m_nestedType->targetLangApiName() + QLatin1String("Array");
- else
- return QLatin1String("jobjectArray");
+ return m_nestedType->isPrimitive()
+ ? m_nestedType->targetLangApiName() + QLatin1String("Array")
+ : QLatin1String("jobjectArray");
+}
+
+TypeEntry *ArrayTypeEntry::clone() const
+{
+ return new ArrayTypeEntry(*this);
}
+ArrayTypeEntry::ArrayTypeEntry(const ArrayTypeEntry &) = default;
+
EnumTypeEntry::EnumTypeEntry(const QString &nspace, const QString &enumName,
const QVersionNumber &vr) :
TypeEntry(nspace.isEmpty() ? enumName : nspace + QLatin1String("::") + enumName,
@@ -2793,16 +3463,6 @@ EnumTypeEntry::EnumTypeEntry(const QString &nspace, const QString &enumName,
{
}
-QString EnumTypeEntry::targetLangPackage() const
-{
- return m_packageName;
-}
-
-void EnumTypeEntry::setTargetLangPackage(const QString &package)
-{
- m_packageName = package;
-}
-
QString EnumTypeEntry::targetLangName() const
{
return m_targetLangName;
@@ -2817,11 +3477,34 @@ EnumValueTypeEntry::EnumValueTypeEntry(const QString &name, const QString &value
{
}
+TypeEntry *EnumValueTypeEntry::clone() const
+{
+ return new EnumValueTypeEntry(*this);
+}
+
+EnumValueTypeEntry::EnumValueTypeEntry(const EnumValueTypeEntry &) = default;
+
FlagsTypeEntry::FlagsTypeEntry(const QString &name, const QVersionNumber &vr) :
TypeEntry(name, FlagsType, vr)
{
}
+/* A typedef entry allows for specifying template specializations in the
+ * typesystem XML file. */
+TypedefEntry::TypedefEntry(const QString &name, const QString &sourceType,
+ const QVersionNumber &vr) :
+ ComplexTypeEntry(name, TypedefType, vr),
+ m_sourceType(sourceType)
+{
+}
+
+TypeEntry *TypedefEntry::clone() const
+{
+ return new TypedefEntry(*this);
+}
+
+TypedefEntry::TypedefEntry(const TypedefEntry &) = default;
+
ContainerTypeEntry::ContainerTypeEntry(const QString &name, Type type,
const QVersionNumber &vr) :
ComplexTypeEntry(name, ContainerType, vr),
@@ -2842,11 +3525,25 @@ SmartPointerTypeEntry::SmartPointerTypeEntry(const QString &name,
{
}
+TypeEntry *SmartPointerTypeEntry::clone() const
+{
+ return new SmartPointerTypeEntry(*this);
+}
+
+SmartPointerTypeEntry::SmartPointerTypeEntry(const SmartPointerTypeEntry &) = default;
+
NamespaceTypeEntry::NamespaceTypeEntry(const QString &name, const QVersionNumber &vr) :
ComplexTypeEntry(name, NamespaceType, vr)
{
}
+TypeEntry *NamespaceTypeEntry::clone() const
+{
+ return new NamespaceTypeEntry(*this);
+}
+
+NamespaceTypeEntry::NamespaceTypeEntry(const NamespaceTypeEntry &) = default;
+
ValueTypeEntry::ValueTypeEntry(const QString &name, const QVersionNumber &vr) :
ComplexTypeEntry(name, BasicValueType, vr)
{
@@ -2862,35 +3559,17 @@ bool ValueTypeEntry::isNativeIdBased() const
return true;
}
-ValueTypeEntry::ValueTypeEntry(const QString &name, Type t, const QVersionNumber &vr) :
- ComplexTypeEntry(name, t, vr)
+TypeEntry *ValueTypeEntry::clone() const
{
+ return new ValueTypeEntry(*this);
}
-StringTypeEntry::StringTypeEntry(const QString &name, const QVersionNumber &vr) :
- ValueTypeEntry(name, StringType, vr)
-{
- setCodeGeneration(GenerateNothing);
-}
+ValueTypeEntry::ValueTypeEntry(const ValueTypeEntry &) = default;
-/*
-static void injectCode(ComplexTypeEntry *e,
- const char *signature,
- const QByteArray &code,
- const ArgumentMap &args)
+ValueTypeEntry::ValueTypeEntry(const QString &name, Type t, const QVersionNumber &vr) :
+ ComplexTypeEntry(name, t, vr)
{
- CodeSnip snip;
- snip.language = TypeSystem::NativeCode;
- snip.position = CodeSnip::Beginning;
- snip.addCode(QString::fromLatin1(code));
- snip.argumentMap = args;
-
- FunctionModification mod;
- mod.signature = QMetaObject::normalizedSignature(signature);
- mod.snips << snip;
- mod.modifiers = Modification::CodeInjection;
}
-*/
struct CustomConversion::CustomConversionPrivate
{
@@ -3042,6 +3721,13 @@ QString InterfaceTypeEntry::qualifiedCppName() const
return ComplexTypeEntry::qualifiedCppName().left(len);
}
+TypeEntry *InterfaceTypeEntry::clone() const
+{
+ return new InterfaceTypeEntry(*this);
+}
+
+InterfaceTypeEntry::InterfaceTypeEntry(const InterfaceTypeEntry &) = default;
+
FunctionTypeEntry::FunctionTypeEntry(const QString &name, const QString &signature,
const QVersionNumber &vr) :
TypeEntry(name, FunctionType, vr)
@@ -3049,6 +3735,13 @@ FunctionTypeEntry::FunctionTypeEntry(const QString &name, const QString &signatu
addSignature(signature);
}
+TypeEntry *FunctionTypeEntry::clone() const
+{
+ return new FunctionTypeEntry(*this);
+}
+
+FunctionTypeEntry::FunctionTypeEntry(const FunctionTypeEntry &) = default;
+
ObjectTypeEntry::ObjectTypeEntry(const QString &name, const QVersionNumber &vr)
: ComplexTypeEntry(name, ObjectType, vr)
{
@@ -3063,3 +3756,10 @@ bool ObjectTypeEntry::isNativeIdBased() const
{
return true;
}
+
+TypeEntry *ObjectTypeEntry::clone() const
+{
+ return new ObjectTypeEntry(*this);
+}
+
+ObjectTypeEntry::ObjectTypeEntry(const ObjectTypeEntry &) = default;
diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h
index 186c4b24d..721d19f29 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.h
+++ b/sources/shiboken2/ApiExtractor/typesystem.h
@@ -43,8 +43,8 @@
#include <QtCore/QVersionNumber>
//Used to identify the conversion rule to avoid break API
-#define TARGET_CONVERSION_RULE_FLAG "0"
-#define NATIVE_CONVERSION_RULE_FLAG "1"
+extern const char *TARGET_CONVERSION_RULE_FLAG;
+extern const char *NATIVE_CONVERSION_RULE_FLAG;
class Indentor;
@@ -203,12 +203,6 @@ struct ArgumentModification
QString replace_value;
- // The code to be used to construct a return value when noNullPointers is true and
- // the returned value is null. If noNullPointers is true and this string is
- // empty, then the base class implementation will be used (or a default construction
- // if there is no implementation)
- QString nullPointerDefaultValue;
-
// The text of the new default expression of the argument
QString replacedDefaultExpression;
@@ -237,6 +231,7 @@ struct ArgumentModification
struct Modification
{
enum Modifiers {
+ InvalidModifier = 0x0000,
Private = 0x0001,
Protected = 0x0002,
Public = 0x0003,
@@ -253,8 +248,7 @@ struct Modification
CodeInjection = 0x1000,
Rename = 0x2000,
Deprecated = 0x4000,
- ReplaceExpression = 0x8000,
- VirtualSlot = 0x10000 | NonFinal
+ ReplaceExpression = 0x8000
};
bool isAccessModifier() const
@@ -289,10 +283,6 @@ struct Modification
{
return modifiers & NonFinal;
}
- bool isVirtualSlot() const
- {
- return (modifiers & VirtualSlot) == VirtualSlot;
- }
QString accessModifierString() const;
bool isDeprecated() const
@@ -325,6 +315,8 @@ struct Modification
struct FunctionModification: public Modification
{
+ using AllowThread = TypeSystem::AllowThread;
+
bool isCodeInjection() const
{
return modifiers & CodeInjection;
@@ -337,14 +329,9 @@ struct FunctionModification: public Modification
{
return m_thread;
}
- bool allowThread() const
- {
- return m_allowThread;
- }
- void setAllowThread(bool allow)
- {
- m_allowThread = allow;
- }
+
+ AllowThread allowThread() const { return m_allowThread; }
+ void setAllowThread(AllowThread allow) { m_allowThread = allow; }
bool matches(const QString &functionSignature) const
{
@@ -359,6 +346,9 @@ struct FunctionModification: public Modification
void setOriginalSignature(const QString &s) { m_originalSignature = s; }
QString originalSignature() const { return m_originalSignature; }
+ TypeSystem::ExceptionHandling exceptionHandling() const { return m_exceptionHandling; }
+ void setExceptionHandling(TypeSystem::ExceptionHandling e) { m_exceptionHandling = e; }
+
QString toString() const;
QString association;
@@ -371,7 +361,8 @@ private:
QString m_originalSignature;
QRegularExpression m_signaturePattern;
bool m_thread = false;
- bool m_allowThread = false;
+ AllowThread m_allowThread = AllowThread::Unspecified;
+ TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
};
struct FieldModification: public Modification
@@ -398,6 +389,7 @@ struct AddedFunction
{
/// Function access types.
enum Access {
+ InvalidAccess = 0,
Protected = 0x1,
Public = 0x2
};
@@ -532,7 +524,6 @@ class CustomConversion;
class TypeEntry
{
- Q_DISABLE_COPY(TypeEntry)
Q_GADGET
public:
enum Type {
@@ -558,7 +549,8 @@ public:
CustomType,
TargetLangType,
FunctionType,
- SmartPointerType
+ SmartPointerType,
+ TypedefType
};
Q_ENUM(Type)
@@ -670,15 +662,6 @@ public:
return m_type == EnumValue;
}
- virtual bool preferredConversion() const
- {
- return m_preferredConversion;
- }
- virtual void setPreferredConversion(bool b)
- {
- m_preferredConversion = b;
- }
-
bool stream() const
{
return m_stream;
@@ -715,6 +698,11 @@ public:
&& m_codeGeneration != TypeEntry::GenerateNothing;
}
+ int revision() const { return m_revision; }
+ void setRevision(int r); // see typedatabase.cpp
+ int sbkIndex() const;
+ void setSbkIndex(int i) { m_sbkIndex = i; }
+
virtual QString qualifiedCppName() const
{
return m_name;
@@ -747,10 +735,8 @@ public:
}
// The package
- virtual QString targetLangPackage() const
- {
- return QString();
- }
+ QString targetLangPackage() const { return m_targetLangPackage; }
+ void setTargetLangPackage(const QString &p) { m_targetLangPackage = p; }
virtual QString qualifiedTargetLangName() const
{
@@ -889,13 +875,29 @@ public:
bool hasCustomConversion() const;
void setCustomConversion(CustomConversion* customConversion);
CustomConversion* customConversion() const;
+
+ virtual TypeEntry *clone() const;
+
+ void useAsTypedef(const TypeEntry *source);
+
+#ifndef QT_NO_DEBUG_STREAM
+ virtual void formatDebug(QDebug &d) const;
+#endif
+
+protected:
+ TypeEntry(const TypeEntry &);
+
private:
+ TypeEntry &operator=(const TypeEntry &) = delete;
+ TypeEntry &operator=(TypeEntry &&) = delete;
+ TypeEntry(TypeEntry &&) = delete;
+
QString m_name;
+ QString m_targetLangPackage;
Type m_type;
uint m_codeGeneration = GenerateAll;
CustomFunction m_customConstructor;
CustomFunction m_customDestructor;
- bool m_preferredConversion = true;
CodeSnipList m_codeSnips;
DocModificationList m_docModifications;
IncludeList m_extraIncludes;
@@ -904,24 +906,42 @@ private:
QString m_conversionRule;
bool m_stream = false;
QVersionNumber m_version;
+ CustomConversion *m_customConversion = nullptr;
+ int m_revision = 0;
+ int m_sbkIndex = 0;
};
class TypeSystemTypeEntry : public TypeEntry
{
public:
explicit TypeSystemTypeEntry(const QString &name, const QVersionNumber &vr);
+
+ TypeEntry *clone() const override;
+
+protected:
+ TypeSystemTypeEntry(const TypeSystemTypeEntry &);
};
class VoidTypeEntry : public TypeEntry
{
public:
VoidTypeEntry();
+
+ TypeEntry *clone() const override;
+
+protected:
+ VoidTypeEntry(const VoidTypeEntry &);
};
class VarargsTypeEntry : public TypeEntry
{
public:
VarargsTypeEntry();
+
+ TypeEntry *clone() const override;
+
+protected:
+ VarargsTypeEntry(const VarargsTypeEntry &);
};
class TemplateArgumentEntry : public TypeEntry
@@ -938,6 +958,11 @@ public:
m_ordinal = o;
}
+ TypeEntry *clone() const override;
+
+protected:
+ TemplateArgumentEntry(const TemplateArgumentEntry &);
+
private:
int m_ordinal = 0;
};
@@ -959,6 +984,11 @@ public:
QString targetLangName() const override;
QString targetLangApiName() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ ArrayTypeEntry(const ArrayTypeEntry &);
+
private:
const TypeEntry *m_nestedType;
};
@@ -1019,9 +1049,6 @@ public:
*/
PrimitiveTypeEntry* basicReferencedTypeEntry() const;
- bool preferredConversion() const override;
- void setPreferredConversion(bool b) override;
-
bool preferredTargetLangType() const
{
return m_preferredTargetLangType;
@@ -1031,26 +1058,27 @@ public:
m_preferredTargetLangType = b;
}
- void setTargetLangPackage(const QString& package);
- QString targetLangPackage() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ PrimitiveTypeEntry(const PrimitiveTypeEntry &);
+
private:
QString m_targetLangName;
QString m_targetLangApiName;
QString m_defaultConstructor;
- uint m_preferredConversion : 1;
uint m_preferredTargetLangType : 1;
PrimitiveTypeEntry* m_referencedTypeEntry = nullptr;
};
+class EnumValueTypeEntry;
+
class EnumTypeEntry : public TypeEntry
{
public:
explicit EnumTypeEntry(const QString &nspace, const QString &enumName,
const QVersionNumber &vr);
- QString targetLangPackage() const override;
- void setTargetLangPackage(const QString &package);
-
QString targetLangName() const override;
QString targetLangQualifier() const;
QString qualifiedTargetLangName() const override;
@@ -1066,30 +1094,8 @@ public:
m_qualifier = q;
}
- bool preferredConversion() const override;
-
- bool isBoundsChecked() const
- {
- return m_lowerBound.isEmpty() && m_upperBound.isEmpty();
- }
-
- QString upperBound() const
- {
- return m_upperBound;
- }
- void setUpperBound(const QString &bound)
- {
- m_upperBound = bound;
- }
-
- QString lowerBound() const
- {
- return m_lowerBound;
- }
- void setLowerBound(const QString &bound)
- {
- m_lowerBound = bound;
- }
+ const EnumValueTypeEntry *nullValue() const { return m_nullValue; }
+ void setNullValue(const EnumValueTypeEntry *n) { m_nullValue = n; }
void setFlags(FlagsTypeEntry *flags)
{
@@ -1100,15 +1106,6 @@ public:
return m_flags;
}
- bool isExtensible() const
- {
- return m_extensible;
- }
- void setExtensible(bool is)
- {
- m_extensible = is;
- }
-
bool isEnumValueRejected(const QString &name) const
{
return m_rejectedEnums.contains(name);
@@ -1122,33 +1119,27 @@ public:
return m_rejectedEnums;
}
- bool forceInteger() const
- {
- return m_forceInteger;
- }
- void setForceInteger(bool force)
- {
- m_forceInteger = force;
- }
+ TypeEntry *clone() const override;
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ EnumTypeEntry(const EnumTypeEntry &);
private:
QString m_packageName;
QString m_qualifier;
QString m_targetLangName;
-
- QString m_lowerBound;
- QString m_upperBound;
+ const EnumValueTypeEntry *m_nullValue = nullptr;
QStringList m_rejectedEnums;
FlagsTypeEntry *m_flags = nullptr;
-
- bool m_extensible = false;
- bool m_forceInteger = false;
};
// EnumValueTypeEntry is used for resolving integer type templates
-// like array<EnumValue>.
+// 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:
@@ -1156,6 +1147,12 @@ public:
QString value() const { return m_value; }
const EnumTypeEntry* enclosingEnum() const { return m_enclosingEnum; }
+
+ TypeEntry *clone() const override;
+
+protected:
+ EnumValueTypeEntry(const EnumValueTypeEntry &);
+
private:
QString m_value;
const EnumTypeEntry* m_enclosingEnum;
@@ -1169,7 +1166,6 @@ public:
QString qualifiedTargetLangName() const override;
QString targetLangName() const override;
QString targetLangApiName() const override;
- bool preferredConversion() const override;
QString originalName() const
{
@@ -1189,11 +1185,6 @@ public:
m_targetLangName = name;
}
- bool forceInteger() const
- {
- return m_enum->forceInteger();
- }
-
EnumTypeEntry *originator() const
{
return m_enum;
@@ -1203,7 +1194,10 @@ public:
m_enum = e;
}
- QString targetLangPackage() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ FlagsTypeEntry(const FlagsTypeEntry &);
private:
QString m_originalName;
@@ -1216,8 +1210,6 @@ class ComplexTypeEntry : public TypeEntry
{
public:
enum TypeFlag {
- ForceAbstract = 0x1,
- DeleteInMainThread = 0x2,
Deprecated = 0x4
};
typedef QFlags<TypeFlag> TypeFlags;
@@ -1288,12 +1280,6 @@ public:
return m_fieldMods;
}
- QString targetLangPackage() const override;
- void setTargetLangPackage(const QString &package)
- {
- m_package = package;
- }
-
bool isQObject() const
{
return m_qobject;
@@ -1336,15 +1322,6 @@ public:
return m_polymorphicIdValue;
}
- void setHeldType(const QString &value)
- {
- m_heldTypeValue = value;
- }
- QString heldTypeValue() const
- {
- return m_heldTypeValue;
- }
-
QString targetType() const
{
return m_targetType;
@@ -1369,6 +1346,9 @@ public:
m_genericClass = isGeneric;
}
+ bool deleteInMainThread() const { return m_deleteInMainThread; }
+ void setDeleteInMainThread(bool d) { m_deleteInMainThread = d; }
+
CopyableFlag copyable() const
{
return m_copyableFlag;
@@ -1397,15 +1377,28 @@ public:
return m_baseContainerType;
}
+ TypeSystem::ExceptionHandling exceptionHandling() const { return m_exceptionHandling; }
+ void setExceptionHandling(TypeSystem::ExceptionHandling e) { m_exceptionHandling = e; }
+
QString defaultConstructor() const;
void setDefaultConstructor(const QString& defaultConstructor);
bool hasDefaultConstructor() const;
+ TypeEntry *clone() const override;
+
+ void useAsTypedef(const ComplexTypeEntry *source);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ ComplexTypeEntry(const ComplexTypeEntry &);
+
private:
AddedFunctionList m_addedFunctions;
FunctionModificationList m_functionMods;
FieldModificationList m_fieldMods;
- QString m_package;
+ QString m_defaultConstructor;
QString m_defaultSuperclass;
QString m_qualifiedCppName;
QString m_targetLangName;
@@ -1413,9 +1406,9 @@ private:
uint m_qobject : 1;
uint m_polymorphicBase : 1;
uint m_genericClass : 1;
+ uint m_deleteInMainThread : 1;
QString m_polymorphicIdValue;
- QString m_heldTypeValue;
QString m_lookupName;
QString m_targetType;
TypeFlags m_typeFlags;
@@ -1423,6 +1416,38 @@ private:
QString m_hashFunction;
const ComplexTypeEntry* m_baseContainerType = nullptr;
+ // For class functions
+ TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+};
+
+class TypedefEntry : public ComplexTypeEntry
+{
+public:
+ explicit TypedefEntry(const QString &name,
+ const QString &sourceType,
+ const QVersionNumber &vr);
+
+ QString sourceType() const { return m_sourceType; }
+ void setSourceType(const QString &s) { m_sourceType =s; }
+
+ TypeEntry *clone() const override;
+
+ ComplexTypeEntry *source() const { return m_source; }
+ void setSource(ComplexTypeEntry *source) { m_source = source; }
+
+ ComplexTypeEntry *target() const { return m_target; }
+ void setTarget(ComplexTypeEntry *target) { m_target = target; }
+
+#ifndef QT_NO_DEBUG_STREAM
+ virtual void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ TypedefEntry(const TypedefEntry &);
+
+private:
+ QString m_sourceType;
+ ComplexTypeEntry *m_source = nullptr;
+ ComplexTypeEntry *m_target = nullptr;
};
class ContainerTypeEntry : public ComplexTypeEntry
@@ -1455,28 +1480,15 @@ public:
QString typeName() const;
QString targetLangName() const override;
- QString targetLangPackage() const override;
QString qualifiedCppName() const override;
- static Type containerTypeFromString(QString typeName)
- {
- static QHash<QString, Type> m_stringToContainerType;
- if (m_stringToContainerType.isEmpty()) {
- m_stringToContainerType.insert(QLatin1String("list"), ListContainer);
- m_stringToContainerType.insert(QLatin1String("string-list"), StringListContainer);
- m_stringToContainerType.insert(QLatin1String("linked-list"), LinkedListContainer);
- m_stringToContainerType.insert(QLatin1String("vector"), VectorContainer);
- m_stringToContainerType.insert(QLatin1String("stack"), StackContainer);
- m_stringToContainerType.insert(QLatin1String("queue"), QueueContainer);
- m_stringToContainerType.insert(QLatin1String("set"), SetContainer);
- m_stringToContainerType.insert(QLatin1String("map"), MapContainer);
- m_stringToContainerType.insert(QLatin1String("multi-map"), MultiMapContainer);
- m_stringToContainerType.insert(QLatin1String("hash"), HashContainer);
- m_stringToContainerType.insert(QLatin1String("multi-hash"), MultiHashContainer);
- m_stringToContainerType.insert(QLatin1String("pair"), PairContainer);
- }
- return m_stringToContainerType.value(typeName, NoContainer);
- }
+ TypeEntry *clone() const override;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ ContainerTypeEntry(const ContainerTypeEntry &);
private:
Type m_type;
@@ -1501,6 +1513,11 @@ public:
return m_refCountMethodName;
}
+ TypeEntry *clone() const override;
+
+protected:
+ SmartPointerTypeEntry(const SmartPointerTypeEntry &);
+
private:
QString m_getterName;
QString m_smartPointerType;
@@ -1511,6 +1528,11 @@ class NamespaceTypeEntry : public ComplexTypeEntry
{
public:
explicit NamespaceTypeEntry(const QString &name, const QVersionNumber &vr);
+
+ TypeEntry *clone() const override;
+
+protected:
+ NamespaceTypeEntry(const NamespaceTypeEntry &);
};
@@ -1523,48 +1545,13 @@ public:
bool isNativeIdBased() const override;
+ TypeEntry *clone() const override;
+
protected:
explicit ValueTypeEntry(const QString &name, Type t, const QVersionNumber &vr);
+ ValueTypeEntry(const ValueTypeEntry &);
};
-
-class StringTypeEntry : public ValueTypeEntry
-{
-public:
- explicit StringTypeEntry(const QString &name, const QVersionNumber &vr);
-
- QString targetLangApiName() const override;
- QString targetLangName() const override;
- QString targetLangPackage() const override;
-
- bool isNativeIdBased() const override;
-};
-
-class CharTypeEntry : public ValueTypeEntry
-{
-public:
- explicit CharTypeEntry(const QString &name, const QVersionNumber &vr);
-
- QString targetLangApiName() const override;
- QString targetLangName() const override;
- QString targetLangPackage() const override;
-
- bool isNativeIdBased() const override;
-};
-
-class VariantTypeEntry: public ValueTypeEntry
-{
-public:
- explicit VariantTypeEntry(const QString &name, const QVersionNumber &vr);
-
- QString targetLangApiName() const override;
- QString targetLangName() const override;
- QString targetLangPackage() const override;
-
- bool isNativeIdBased() const override;
-};
-
-
class InterfaceTypeEntry : public ComplexTypeEntry
{
public:
@@ -1587,6 +1574,11 @@ public:
bool isNativeIdBased() const override;
QString qualifiedCppName() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ InterfaceTypeEntry(const InterfaceTypeEntry &);
+
private:
ObjectTypeEntry *m_origin;
};
@@ -1611,6 +1603,12 @@ public:
{
return m_signatures.contains(signature);
}
+
+ TypeEntry *clone() const override;
+
+protected:
+ FunctionTypeEntry(const FunctionTypeEntry &);
+
private:
QStringList m_signatures;
};
@@ -1628,6 +1626,11 @@ public:
bool isNativeIdBased() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ ObjectTypeEntry(const ObjectTypeEntry &);
+
private:
InterfaceTypeEntry *m_interface = nullptr;
};
@@ -1641,7 +1644,8 @@ struct TypeRejection
Field, // Match className and field name
Enum, // Match className and enum name
ArgumentType, // Match className and argument type
- ReturnType // Match className and return type
+ ReturnType, // Match className and return type
+ Invalid
};
QRegularExpression className;
diff --git a/sources/shiboken2/ApiExtractor/typesystem_enums.h b/sources/shiboken2/ApiExtractor/typesystem_enums.h
index 6bfc94368..df83429d0 100644
--- a/sources/shiboken2/ApiExtractor/typesystem_enums.h
+++ b/sources/shiboken2/ApiExtractor/typesystem_enums.h
@@ -55,6 +55,13 @@ enum Language {
TargetLangAndNativeCode = TargetLangCode | NativeCode
};
+enum class AllowThread {
+ Allow,
+ Disallow,
+ Auto,
+ Unspecified
+};
+
enum Ownership {
InvalidOwnership,
DefaultOwnership,
@@ -71,14 +78,24 @@ enum CodeSnipPosition {
CodeSnipPositionPrototypeInitialization,
CodeSnipPositionConstructorInitialization,
CodeSnipPositionConstructor,
- CodeSnipPositionAny
+ CodeSnipPositionAny,
+ CodeSnipPositionInvalid
};
enum DocModificationMode {
DocModificationAppend,
DocModificationPrepend,
DocModificationReplace,
- DocModificationXPathReplace
+ DocModificationXPathReplace,
+ DocModificationInvalid
+};
+
+enum class ExceptionHandling {
+ Unspecified,
+ Off,
+ AutoDefaultToOff,
+ AutoDefaultToOn,
+ On
};
} // namespace TypeSystem
diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h
index 882cf3fab..e36df5151 100644
--- a/sources/shiboken2/ApiExtractor/typesystem_p.h
+++ b/sources/shiboken2/ApiExtractor/typesystem_p.h
@@ -55,6 +55,7 @@ class StackElement
FunctionTypeEntry = 0xb,
CustomTypeEntry = 0xc,
SmartPointerTypeEntry = 0xd,
+ TypedefTypeEntry = 0xe,
TypeEntryMask = 0xf,
// Documentation tags
@@ -140,37 +141,114 @@ public:
bool parse(QXmlStreamReader &reader);
+ QString errorString() const { return m_error; }
+
private:
- bool startElement(const QStringRef& localName, const QXmlStreamAttributes& atts);
- bool handleSmartPointerEntry(StackElement *element,
- QHash<QString, QString> &attributes,
- const QString &name,
- const QVersionNumber &since);
+ bool startElement(const QXmlStreamReader &reader);
+ SmartPointerTypeEntry *parseSmartPointerEntry(const QXmlStreamReader &,
+ const QString &name,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes);
bool endElement(const QStringRef& localName);
template <class String> // QString/QStringRef
bool characters(const String &ch);
- void fetchAttributeValues(const QString &name, const QXmlStreamAttributes &atts,
- QHash<QString, QString> *acceptedAttributes);
bool importFileElement(const QXmlStreamAttributes &atts);
- void addFlags(const QString &name, QString flagName,
- const QHash<QString, QString> &attributes,
- const QVersionNumber &since);
+
+ void applyCommonAttributes(TypeEntry *type, QXmlStreamAttributes *attributes) const;
+ PrimitiveTypeEntry *
+ parsePrimitiveTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ ContainerTypeEntry *
+ parseContainerTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ EnumTypeEntry *
+ parseEnumTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ FlagsTypeEntry *
+ parseFlagsEntry(const QXmlStreamReader &, EnumTypeEntry *enumEntry,
+ const QString &name, QString flagName,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ ObjectTypeEntry *
+ parseInterfaceTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ ValueTypeEntry *
+ parseValueTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ FunctionTypeEntry *
+ parseFunctionTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ TypedefEntry *
+ parseTypedefEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ void applyComplexTypeAttributes(const QXmlStreamReader &, ComplexTypeEntry *ctype,
+ QXmlStreamAttributes *) const;
+ bool parseRenameFunction(const QXmlStreamReader &, QString *name,
+ QXmlStreamAttributes *);
+ bool parseInjectDocumentation(const QXmlStreamReader &, QXmlStreamAttributes *);
+ bool parseModifyDocumentation(const QXmlStreamReader &, QXmlStreamAttributes *);
+ TypeSystemTypeEntry *
+ parseRootElement(const QXmlStreamReader &, const QVersionNumber &since,
+ QXmlStreamAttributes *);
+ bool loadTypesystem(const QXmlStreamReader &, QXmlStreamAttributes *);
+ bool parseRejectEnumValue(const QXmlStreamReader &, QXmlStreamAttributes *);
+ bool parseReplaceArgumentType(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseCustomConversion(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseAddConversion(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseModifyArgument(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *attributes);
+ bool parseNoNullPointer(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *attributes);
+ bool parseDefineOwnership(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseArgumentMap(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseRemoval(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseRename(const QXmlStreamReader &, StackElement::ElementType type,
+ const StackElement &topElement, QXmlStreamAttributes *);
+ bool parseModifyField(const QXmlStreamReader &, QXmlStreamAttributes *);
+ bool parseAddFunction(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseModifyFunction(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseReplaceDefaultExpression(const QXmlStreamReader &,
+ const StackElement &topElement, QXmlStreamAttributes *);
+ CustomFunction *
+ parseCustomMetaConstructor(const QXmlStreamReader &,
+ StackElement::ElementType type,
+ const StackElement &topElement, QXmlStreamAttributes *);
+ bool parseReferenceCount(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseParentOwner(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseInjectCode(const QXmlStreamReader &, const StackElement &topElement,
+ StackElement* element, QXmlStreamAttributes *);
+ bool parseInclude(const QXmlStreamReader &, const StackElement &topElement,
+ TypeEntry *entry, QXmlStreamAttributes *);
+ TemplateInstance
+ *parseTemplateInstanceEnum(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseReplace(const QXmlStreamReader &, const StackElement &topElement,
+ StackElement *element, QXmlStreamAttributes *);
TypeDatabase* m_database;
- StackElement* m_current;
- StackElement* m_currentDroppedEntry;
- int m_currentDroppedEntryDepth;
- int m_ignoreDepth;
+ StackElement* m_current = nullptr;
+ StackElement* m_currentDroppedEntry = nullptr;
+ int m_currentDroppedEntryDepth = 0;
+ int m_ignoreDepth = 0;
QString m_defaultPackage;
QString m_defaultSuperclass;
+ TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
QString m_error;
- TypeEntry::CodeGeneration m_generate;
+ const TypeEntry::CodeGeneration m_generate;
- EnumTypeEntry* m_currentEnum;
+ EnumTypeEntry* m_currentEnum = nullptr;
QStack<StackElementContext*> m_contextStack;
- QHash<QString, StackElement::ElementType> tagNames;
QString m_currentSignature;
QString m_currentPath;
};
diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt
index 1af84fca1..12a9b8773 100644
--- a/sources/shiboken2/CMakeLists.txt
+++ b/sources/shiboken2/CMakeLists.txt
@@ -5,8 +5,9 @@ include(CheckIncludeFileCXX)
cmake_minimum_required(VERSION 3.1)
cmake_policy(VERSION 3.1)
-set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules/
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/../cmake_helpers/
${CMAKE_MODULE_PATH})
+include(helpers)
find_package(Qt5 5.7 REQUIRED COMPONENTS Core Xml XmlPatterns)
@@ -158,6 +159,8 @@ list(GET SHIBOKEN_VERSION_OUTPUT 4 shiboken_PRE_RELEASE_VERSION)
set(shiboken2_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}")
set(shiboken2_library_so_version "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}")
+compute_config_py_values(shiboken2_VERSION)
+
## For debugging the PYTHON* variables
message("PYTHONLIBS_FOUND: " ${PYTHONLIBS_FOUND})
message("PYTHON_LIBRARIES: " ${PYTHON_LIBRARIES})
diff --git a/sources/shiboken2/doc/commandlineoptions.rst b/sources/shiboken2/doc/commandlineoptions.rst
index d373561cd..c335fab75 100644
--- a/sources/shiboken2/doc/commandlineoptions.rst
+++ b/sources/shiboken2/doc/commandlineoptions.rst
@@ -37,16 +37,22 @@ Options
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_nonzero:
+
+``--use-isnull-as-nb_nonzero``
+ If a class have an isNull() const method, it will be used to
+ compute the value of boolean casts
+
.. _api-version:
``--api-version=<version>``
Specify the supported api version used to generate the bindings.
-.. _debug-level:
-
-``--debug-level=[sparse|medium|full]``
- Set the debug level.
-
.. _documentation-only:
``--documentation-only``
@@ -63,16 +69,52 @@ Options
``--generation-set``
Generator set to be used (e.g. qtdoc).
-.. _help:
+.. _diff:
-``--help``
- Display this help and exit.
+``--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.
.. _include-paths:
-``--include-paths=<path>[:<path>:...]``
+``-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
+
+.. _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]``
@@ -83,23 +125,57 @@ Options
``--no-suppress-warnings``
Show all warnings.
-.. _output-directory:
-
-``--output-directory=[dir]``
- The directory where the generated files will be written.
-
.. _silent:
``--silent``
Avoid printing any message.
-.. _typesystem-paths:
+.. _debug-level:
-``--typesystem-paths=<path>[:<path>:...]``
- Paths used when searching for type system files.
+``--debug-level=[sparse|medium|full]``
+ Set the debug level.
+
+.. _help:
+
+``--help``
+ Display this help and exit.
.. _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).
diff --git a/sources/shiboken2/generator/CMakeLists.txt b/sources/shiboken2/generator/CMakeLists.txt
index 032118666..fb8058b2d 100644
--- a/sources/shiboken2/generator/CMakeLists.txt
+++ b/sources/shiboken2/generator/CMakeLists.txt
@@ -38,3 +38,33 @@ target_link_libraries(shiboken2
configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
install(TARGETS shiboken2 DESTINATION bin)
+
+set(shiboken_generator_package_name "shiboken2_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}")
+
+# shiboken2 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}")
diff --git a/sources/shiboken2/generator/__init__.py.in b/sources/shiboken2/generator/__init__.py.in
new file mode 100644
index 000000000..4be6a833b
--- /dev/null
+++ b/sources/shiboken2/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/shiboken2/generator/_config.py.in b/sources/shiboken2/generator/_config.py.in
new file mode 100644
index 000000000..985735fa4
--- /dev/null
+++ b/sources/shiboken2/generator/_config.py.in
@@ -0,0 +1,9 @@
+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@
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index 1e2f03932..8b37b44e0 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -28,6 +28,7 @@
#include "generator.h"
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "fileout.h"
#include "apiextractor.h"
@@ -40,8 +41,113 @@
#include <QDebug>
#include <typedatabase.h>
-struct Generator::GeneratorPrivate {
- const ApiExtractor* apiextractor;
+/**
+ * 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::Error:
+ return QLatin1String("#error");
+ case DefaultValue::Boolean:
+ return QLatin1String("false");
+ case DefaultValue::CppScalar:
+ return QLatin1String("0");
+ case DefaultValue::Custom:
+ case DefaultValue::Enum:
+ return m_value;
+ case DefaultValue::Pointer:
+ return QLatin1String("nullptr");
+ case DefaultValue::Void:
+ return QString();
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ return m_value + QLatin1String("()");
+ case DefaultValue::DefaultConstructor:
+ break;
+ }
+ return QLatin1String("{}");
+}
+
+QString DefaultValue::initialization() const
+{
+ switch (m_type) {
+ case DefaultValue::Error:
+ return QLatin1String("#error");
+ case DefaultValue::Boolean:
+ return QLatin1String("{false}");
+ case DefaultValue::CppScalar:
+ return QLatin1String("{0}");
+ case DefaultValue::Custom:
+ return QLatin1String(" = ") + m_value;
+ case DefaultValue::Enum:
+ return QLatin1Char('{') + m_value + QLatin1Char('}');
+ case DefaultValue::Pointer:
+ return QLatin1String("{nullptr}");
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ break;
+ }
+ return QString();
+}
+
+QString DefaultValue::constructorParameter() const
+{
+ switch (m_type) {
+ case DefaultValue::Error:
+ return QLatin1String("#error");
+ case DefaultValue::Boolean:
+ return QLatin1String("false");
+ case DefaultValue::CppScalar:
+ return m_value + QLatin1String("(0)");
+ 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 QLatin1String("static_cast<") + m_value + QLatin1String("*>(nullptr)");
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ break;
+ }
+ return m_value + QLatin1String("()");
+}
+
+struct Generator::GeneratorPrivate
+{
+ const ApiExtractor* apiextractor = nullptr;
QString outDir;
// License comment
QString licenseComment;
@@ -62,20 +168,17 @@ Generator::~Generator()
delete m_d;
}
-bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QString > args)
+bool Generator::setup(const ApiExtractor& extractor)
{
m_d->apiextractor = &extractor;
- TypeEntryHash allEntries = TypeDatabase::instance()->allEntries();
+ const auto &allEntries = TypeDatabase::instance()->entries();
TypeEntry* entryFound = 0;
- for (TypeEntryHash::const_iterator it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
- for (TypeEntry *entry : it.value()) {
- if (entry->type() == TypeEntry::TypeSystemType && entry->generateCode()) {
- entryFound = entry;
- break;
- }
- }
- if (entryFound)
+ for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
+ TypeEntry *entry = it.value();
+ if (entry->type() == TypeEntry::TypeSystemType && entry->generateCode()) {
+ entryFound = entry;
break;
+ }
}
if (entryFound)
m_d->packageName = entryFound->name();
@@ -84,7 +187,7 @@ bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QStrin
collectInstantiatedContainersAndSmartPointers();
- return doSetup(args);
+ return doSetup();
}
QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type)
@@ -197,6 +300,11 @@ Generator::OptionDescriptions Generator::options() const
return OptionDescriptions();
}
+bool Generator::handleOption(const QString & /* key */, const QString & /* value */)
+{
+ return false;
+}
+
AbstractMetaClassList Generator::classes() const
{
return m_d->apiextractor->classes();
@@ -227,24 +335,14 @@ ContainerTypeEntryList Generator::containerTypes() const
return m_d->apiextractor->containerTypes();
}
-const AbstractMetaEnum* Generator::findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const
-{
- return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
-}
-
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const TypeEntry* typeEntry) const
{
return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
}
-const AbstractMetaEnum* Generator::findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const
-{
- return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
-}
-
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const AbstractMetaType* metaType) const
{
- return m_d->apiextractor->findAbstractMetaEnum(metaType);
+ return m_d->apiextractor->findAbstractMetaEnum(metaType->typeEntry());
}
QString Generator::licenseComment() const
@@ -278,21 +376,6 @@ void Generator::setOutputDirectory(const QString &outDir)
m_d->outDir = outDir;
}
-inline void touchFile(const QString &filePath)
-{
- QFile toucher(filePath);
- qint64 size = toucher.size();
- if (!toucher.open(QIODevice::ReadWrite)) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("Failed to touch file '%1'")
- .arg(QDir::toNativeSeparators(filePath));
- return;
- }
- toucher.resize(size+1);
- toucher.resize(size);
- toucher.close();
-}
-
bool Generator::generateFileForContext(GeneratorContext &context)
{
AbstractMetaClass *cls = context.metaClass();
@@ -312,20 +395,7 @@ bool Generator::generateFileForContext(GeneratorContext &context)
generateClass(fileOut.stream, context);
- FileOut::State state = fileOut.done();
- switch (state) {
- case FileOut::Failure:
- return false;
- case FileOut::Unchanged:
- // Even if contents is unchanged, the last file modification time should be updated,
- // so that the build system can rely on the fact the generated file is up-to-date.
- touchFile(filePath);
- break;
- case FileOut::Success:
- break;
- }
-
- return true;
+ return fileOut.done() != FileOut::Failure;
}
QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
@@ -369,9 +439,9 @@ bool Generator::shouldGenerate(const AbstractMetaClass* metaClass) const
return shouldGenerateTypeEntry(metaClass->typeEntry());
}
-void verifyDirectoryFor(const QFile &file)
+void verifyDirectoryFor(const QString &file)
{
- QDir dir = QFileInfo(file).dir();
+ QDir dir = QFileInfo(file).absoluteDir();
if (!dir.exists()) {
if (!dir.mkpath(dir.absolutePath())) {
qCWarning(lcShiboken).noquote().nospace()
@@ -463,7 +533,7 @@ AbstractMetaFunctionList Generator::implicitConversions(const AbstractMetaType*
bool Generator::isObjectType(const TypeEntry* type)
{
if (type->isComplex())
- return Generator::isObjectType((const ComplexTypeEntry*)type);
+ return Generator::isObjectType(static_cast<const ComplexTypeEntry *>(type));
return type->isObject();
}
bool Generator::isObjectType(const ComplexTypeEntry* type)
@@ -557,184 +627,178 @@ QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type)
return QLatin1String("::") + typeName;
}
-QString Generator::minimalConstructor(const AbstractMetaType* type) const
+DefaultValue Generator::minimalConstructor(const AbstractMetaType* type) const
{
if (!type || (type->referenceType() == LValueReference && Generator::isObjectType(type)))
- return QString();
+ return DefaultValue(DefaultValue::Error);
if (type->isContainer()) {
QString ctor = type->cppSignature();
- if (ctor.endsWith(QLatin1Char('*')))
- return QLatin1String("0");
+ if (ctor.endsWith(QLatin1Char('*'))) {
+ ctor.chop(1);
+ return DefaultValue(DefaultValue::Pointer, ctor.trimmed());
+ }
if (ctor.startsWith(QLatin1String("const ")))
ctor.remove(0, sizeof("const ") / sizeof(char) - 1);
if (ctor.endsWith(QLatin1Char('&'))) {
ctor.chop(1);
ctor = ctor.trimmed();
}
- return QLatin1String("::") + ctor + QLatin1String("()");
+ return DefaultValue(DefaultValue::DefaultConstructor, QLatin1String("::") + ctor);
}
if (type->isNativePointer())
- return QLatin1String("static_cast<") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+ return DefaultValue(DefaultValue::Pointer, type->typeEntry()->qualifiedCppName());
if (Generator::isPointer(type))
- return QLatin1String("static_cast< ::") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+ return DefaultValue(DefaultValue::Pointer, QLatin1String("::") + type->typeEntry()->qualifiedCppName());
if (type->typeEntry()->isComplex()) {
- const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(type->typeEntry());
- QString ctor = cType->defaultConstructor();
- if (!ctor.isEmpty())
- return ctor;
- ctor = minimalConstructor(AbstractMetaClass::findClass(classes(), cType));
- if (type->hasInstantiations())
- ctor = ctor.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(type->typeEntry());
+ if (cType->hasDefaultConstructor())
+ return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
+ auto ctor = minimalConstructor(AbstractMetaClass::findClass(classes(), cType));
+ if (ctor.isValid() && type->hasInstantiations()) {
+ QString v = ctor.value();
+ v.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ ctor.setValue(v);
+ }
return ctor;
}
return minimalConstructor(type->typeEntry());
}
-QString Generator::minimalConstructor(const TypeEntry* type) const
+DefaultValue Generator::minimalConstructor(const TypeEntry* type) const
{
if (!type)
- return QString();
+ return DefaultValue(DefaultValue::Error);
if (type->isCppPrimitive()) {
const QString &name = type->qualifiedCppName();
return name == QLatin1String("bool")
- ? QLatin1String("false") : name + QLatin1String("(0)");
+ ? DefaultValue(DefaultValue::Boolean)
+ : DefaultValue(DefaultValue::CppScalar, name);
}
- if (type->isEnum())
- return QLatin1String("static_cast< ::") + type->qualifiedCppName() + QLatin1String(">(0)");
+ if (type->isEnum()) {
+ const auto enumEntry = static_cast<const EnumTypeEntry *>(type);
+ if (const auto *nullValue = enumEntry->nullValue())
+ return DefaultValue(DefaultValue::Enum, nullValue->name());
+ return DefaultValue(DefaultValue::Custom,
+ QLatin1String("static_cast< ::") + type->qualifiedCppName()
+ + QLatin1String(">(0)"));
+ }
- if (type->isFlags())
- return type->qualifiedCppName() + QLatin1String("(0)");
+ if (type->isFlags()) {
+ return DefaultValue(DefaultValue::Custom,
+ type->qualifiedCppName() + QLatin1String("(0)"));
+ }
if (type->isPrimitive()) {
- QString ctor = reinterpret_cast<const PrimitiveTypeEntry*>(type)->defaultConstructor();
+ QString ctor = static_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()
- ? (QLatin1String("::") + type->qualifiedCppName() + QLatin1String("()"))
- : ctor;
+ ? DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues, QLatin1String("::")
+ + type->qualifiedCppName())
+ : DefaultValue(DefaultValue::Custom, ctor);
}
if (type->isComplex())
return minimalConstructor(AbstractMetaClass::findClass(classes(), type));
- return QString();
+ return DefaultValue(DefaultValue::Error);
}
-QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
+static QString constructorCall(const QString &qualifiedCppName, const QStringList &args)
+{
+ return QLatin1String("::") + qualifiedCppName + QLatin1Char('(')
+ + args.join(QLatin1String(", ")) + QLatin1Char(')');
+}
+
+DefaultValue Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
{
if (!metaClass)
- return QString();
+ return DefaultValue(DefaultValue::Error);
- const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(metaClass->typeEntry());
+ const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(metaClass->typeEntry());
if (cType->hasDefaultConstructor())
- return cType->defaultConstructor();
+ 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 AbstractMetaFunction *> candidates;
const AbstractMetaFunctionList &constructors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
- int maxArgs = 0;
for (const AbstractMetaFunction *ctor : constructors) {
- if (ctor->isUserAdded() || ctor->isPrivate() || ctor->functionType() != AbstractMetaFunction::ConstructorFunction)
- continue;
-
- int numArgs = ctor->arguments().size();
- if (numArgs == 0) {
- maxArgs = 0;
- break;
- }
- if (numArgs > maxArgs)
- maxArgs = numArgs;
- }
-
- QString qualifiedCppName = metaClass->typeEntry()->qualifiedCppName();
- QStringList templateTypes;
- const QVector<TypeEntry *> &templateArguments = metaClass->templateArguments();
- for (TypeEntry *templateType : templateArguments)
- templateTypes << templateType->qualifiedCppName();
-
- // Empty constructor.
- if (maxArgs == 0)
- return QLatin1String("::") + qualifiedCppName + QLatin1String("()");
-
- QVector<const AbstractMetaFunction *> candidates;
-
- // Constructors with C++ primitive types, enums or pointers only.
- // Start with the ones with fewer arguments.
- for (int i = 1; i <= maxArgs; ++i) {
- for (const AbstractMetaFunction *ctor : constructors) {
- if (ctor->isUserAdded() || ctor->isPrivate() || ctor->functionType() != AbstractMetaFunction::ConstructorFunction)
- continue;
-
- const AbstractMetaArgumentList &arguments = ctor->arguments();
- if (arguments.size() != i)
- continue;
-
- QStringList args;
- for (const AbstractMetaArgument *arg : arguments) {
- const TypeEntry* type = arg->type()->typeEntry();
- if (type == metaClass->typeEntry()) {
- args.clear();
- break;
- }
-
- if (!arg->originalDefaultValueExpression().isEmpty()) {
- if (!arg->defaultValueExpression().isEmpty()
- && arg->defaultValueExpression() != arg->originalDefaultValueExpression()) {
- args << arg->defaultValueExpression();
- }
- break;
- }
-
- if (type->isCppPrimitive() || type->isEnum() || isPointer(arg->type())) {
- QString argValue = minimalConstructor(arg->type());
- if (argValue.isEmpty()) {
- args.clear();
- break;
- }
- args << argValue;
- } else {
- args.clear();
- break;
- }
+ if (!ctor->isUserAdded() && !ctor->isPrivate()
+ && ctor->functionType() == AbstractMetaFunction::ConstructorFunction) {
+ // No arguments: Default constructible
+ const auto &arguments = ctor->arguments();
+ if (arguments.isEmpty()) {
+ return DefaultValue(DefaultValue::DefaultConstructor,
+ QLatin1String("::") + qualifiedCppName);
}
-
- if (!args.isEmpty())
- return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
-
- candidates << ctor;
+ // First argument has unmodified default: Default constructible with values
+ if (arguments.constFirst()->hasUnmodifiedDefaultValueExpression()) {
+ return DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues,
+ QLatin1String("::") + qualifiedCppName);
+ }
+ // Examine arguments, exclude functions taking a self parameter
+ bool simple = true;
+ bool suitable = true;
+ for (int i = 0, size = arguments.size();
+ suitable && i < size && !arguments.at(i)->hasDefaultValueExpression(); ++i) {
+ const AbstractMetaArgument *arg = arguments.at(i);
+ const TypeEntry *aType = arg->type()->typeEntry();
+ suitable &= aType != cType;
+ simple &= aType->isCppPrimitive() || aType->isEnum() || isPointer(arg->type());
+ }
+ if (suitable)
+ candidates.insert(arguments.size() + (simple ? 0 : 100), ctor);
}
}
- // Constructors with C++ primitive types, enums, pointers, value types,
- // and user defined primitive types.
- // Builds the minimal constructor recursively.
- for (const AbstractMetaFunction *ctor : qAsConst(candidates)) {
+ for (auto it = candidates.cbegin(), end = candidates.cend(); it != end; ++it) {
+ const AbstractMetaArgumentList &arguments = it.value()->arguments();
QStringList args;
- const AbstractMetaArgumentList &arguments = ctor->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (arg->type()->typeEntry() == metaClass->typeEntry()) {
- args.clear();
+ bool ok = true;
+ for (int i =0, size = arguments.size(); ok && i < size; ++i) {
+ const AbstractMetaArgument *arg = arguments.at(i);
+ if (arg->hasDefaultValueExpression()) {
+ if (arg->hasModifiedDefaultValueExpression())
+ args << arg->defaultValueExpression(); // Spell out modified values
break;
}
- QString argValue = minimalConstructor(arg->type());
- if (argValue.isEmpty()) {
- args.clear();
- break;
- }
- args << argValue;
- }
- if (!args.isEmpty()) {
- return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
+ auto argValue = minimalConstructor(arg->type());
+ ok &= argValue.isValid();
+ args << argValue.constructorParameter();
}
+ if (ok)
+ return DefaultValue(DefaultValue::Custom, constructorCall(qualifiedCppName, args));
}
- return QString();
+ return DefaultValue(DefaultValue::Error);
+}
+
+// Should int be used for a (protected) enum when generating the public wrapper?
+bool Generator::useEnumAsIntForProtectedHack(const AbstractMetaType *metaType) const
+{
+ if (metaType->isFlags())
+ return true;
+ if (!metaType->isEnum())
+ return false;
+ const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(metaType);
+ if (!metaEnum)
+ return true;
+ if (metaEnum->attributes() & AbstractMetaAttributes::Public) // No reason, type is public
+ return false;
+ // Only ordinary C-enums can be used as int, scoped enums fail when used
+ // as function arguments.
+ if (metaEnum->enumKind() == EnumKind::EnumClass)
+ qWarning(lcShiboken, "%s", qPrintable(msgCannotUseEnumAsInt(metaEnum->name())));
+ return true;
}
QString Generator::translateType(const AbstractMetaType *cType,
@@ -754,7 +818,7 @@ QString Generator::translateType(const AbstractMetaType *cType,
s = QLatin1String("void");
} else if (cType->isArray()) {
s = translateType(cType->arrayElementType(), context, options) + QLatin1String("[]");
- } else if (options & Generator::EnumAsInts && (cType->isEnum() || cType->isFlags())) {
+ } else if ((options & Generator::EnumAsInts) && useEnumAsIntForProtectedHack(cType)) {
s = QLatin1String("int");
} else {
if (options & Generator::OriginalName) {
diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h
index 010ed868c..225e7aec7 100644
--- a/sources/shiboken2/generator/generator.h
+++ b/sources/shiboken2/generator/generator.h
@@ -57,7 +57,7 @@ class ContainerTypeEntry;
class Indentor;
QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor);
-void verifyDirectoryFor(const QFile &file);
+void verifyDirectoryFor(const QString &file);
QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName = true);
QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName = true);
@@ -95,6 +95,42 @@ const int alwaysGenerateDestructor = 1;
const int alwaysGenerateDestructor = 0;
#endif
+class DefaultValue
+{
+public:
+ enum Type
+ {
+ Error,
+ 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 = Error, QString value = QString());
+ explicit DefaultValue(QString customValue);
+
+ bool isValid() const { return m_type != Error; }
+
+ 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;
+};
+
/**
* A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized
* AbstractMetaType, for which code is currently being generated.
@@ -166,13 +202,74 @@ public:
Generator();
virtual ~Generator();
- bool setup(const ApiExtractor& extractor, const QMap<QString, QString> args);
+ bool setup(const ApiExtractor& extractor);
virtual OptionDescriptions options() const;
+ virtual bool handleOption(const QString &key, const QString &value);
/// Returns the classes used to generate the binding code.
AbstractMetaClassList classes() 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;
+
+ /**
+ * 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
+ */
+ QString moduleName() 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
+ */
+ AbstractMetaFunctionList implicitConversions(const TypeEntry* type) const;
+
+ /// Convenience function for implicitConversions(const TypeEntry* type).
+ AbstractMetaFunctionList implicitConversions(const AbstractMetaType* metaType) const;
+
+ /// Check if type is a pointer.
+ static bool isPointer(const AbstractMetaType* type);
+
+ /// Tells if the type or class is an Object (or QObject) Type.
+ static bool isObjectType(const TypeEntry* type);
+ static bool isObjectType(const ComplexTypeEntry* type);
+ static bool isObjectType(const AbstractMetaType* metaType);
+ static bool isObjectType(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the type is a C string (const char*).
+ static bool isCString(const AbstractMetaType* type);
+ /// Returns true if the type is a void pointer.
+ static bool isVoidPointer(const AbstractMetaType* type);
+
+protected:
/// Returns the classes, topologically ordered, used to generate the binding code.
///
/// The classes are ordered such that derived classes appear later in the list than
@@ -191,33 +288,12 @@ public:
/// Returns all container types found by APIExtractor
ContainerTypeEntryList containerTypes() const;
- /// Returns an AbstractMetaEnum for a given EnumTypeEntry, or NULL if not found.
- const AbstractMetaEnum* findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const;
-
/// Returns an AbstractMetaEnum for a given TypeEntry that is an EnumTypeEntry, or NULL if not found.
const AbstractMetaEnum* findAbstractMetaEnum(const TypeEntry* typeEntry) const;
- /// Returns an AbstractMetaEnum for the enum related to a given FlagsTypeEntry, or NULL if not found.
- const AbstractMetaEnum* findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const;
-
/// Returns an AbstractMetaEnum for a given AbstractMetaType that holds an EnumTypeEntry, or NULL if not found.
const AbstractMetaEnum* findAbstractMetaEnum(const AbstractMetaType* metaType) 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();
-
-
/// Generates a file for given AbstractMetaClass or AbstractMetaType (smart pointer case).
bool generateFileForContext(GeneratorContext &context);
@@ -225,9 +301,6 @@ public:
QString getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
const AbstractMetaClass *smartPointerClass) const;
- /// Returns the generator's name. Used for cosmetic purposes.
- virtual const char* name() const = 0;
-
/// Returns true if the generator should generate any code for the TypeEntry.
bool shouldGenerateTypeEntry(const TypeEntry*) const;
@@ -266,56 +339,10 @@ public:
void replaceTemplateVariables(QString &code, const AbstractMetaFunction *func);
/**
- * 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 package name.
*/
QString packageName() const;
- /**
- * 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
- */
- virtual QString moduleName() 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
- */
- AbstractMetaFunctionList implicitConversions(const TypeEntry* type) const;
-
- /// Convenience function for implicitConversions(const TypeEntry* type).
- AbstractMetaFunctionList implicitConversions(const AbstractMetaType* metaType) const;
-
- /// Check if type is a pointer.
- static bool isPointer(const AbstractMetaType* type);
-
- /// Tells if the type or class is an Object (or QObject) Type.
- static bool isObjectType(const TypeEntry* type);
- static bool isObjectType(const ComplexTypeEntry* type);
- static bool isObjectType(const AbstractMetaType* metaType);
- static bool isObjectType(const AbstractMetaClass* metaClass);
-
- /// Returns true if the type is a C string (const char*).
- static bool isCString(const AbstractMetaType* type);
- /// Returns true if the type is a void pointer.
- static bool isVoidPointer(const AbstractMetaType* type);
-
// Returns the full name of the type.
QString getFullTypeName(const TypeEntry* type) const;
QString getFullTypeName(const AbstractMetaType* type) const;
@@ -333,11 +360,10 @@ public:
* It will check first for a user defined default constructor.
* Returns a null string if it fails.
*/
- QString minimalConstructor(const TypeEntry* type) const;
- QString minimalConstructor(const AbstractMetaType* type) const;
- QString minimalConstructor(const AbstractMetaClass* metaClass) const;
+ DefaultValue minimalConstructor(const TypeEntry* type) const;
+ DefaultValue minimalConstructor(const AbstractMetaType* type) const;
+ DefaultValue minimalConstructor(const AbstractMetaClass* metaClass) const;
-protected:
/**
* Returns the file name used to write the binding code of an AbstractMetaClass/Type.
* \param context the GeneratorContext which contains an AbstractMetaClass or AbstractMetaType
@@ -348,7 +374,7 @@ protected:
virtual QString fileNameForContext(GeneratorContext &context) const = 0;
- virtual bool doSetup(const QMap<QString, QString>& args) = 0;
+ virtual bool doSetup() = 0;
/**
* Write the bindding code for an AbstractMetaClass.
@@ -378,6 +404,8 @@ protected:
const QString &context);
private:
+ bool useEnumAsIntForProtectedHack(const AbstractMetaType *cType) const;
+
struct GeneratorPrivate;
GeneratorPrivate* m_d;
void collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction* func);
diff --git a/sources/shiboken2/generator/main.cpp b/sources/shiboken2/generator/main.cpp
index 0b7c15244..362191fd0 100644
--- a/sources/shiboken2/generator/main.cpp
+++ b/sources/shiboken2/generator/main.cpp
@@ -34,6 +34,9 @@
#include <QtCore/QDir>
#include <iostream>
#include <apiextractor.h>
+#include <fileout.h>
+#include <typedatabase.h>
+#include <messages.h>
#include "generator.h"
#include "shibokenconfig.h"
#include "cppgenerator.h"
@@ -41,9 +44,9 @@
#include "qtdocgenerator.h"
#ifdef _WINDOWS
- #define PATH_SPLITTER ";"
+static const QChar pathSplitter = QLatin1Char(';');
#else
- #define PATH_SPLITTER ":"
+static const QChar pathSplitter = QLatin1Char(':');
#endif
static inline QString languageLevelOption() { return QStringLiteral("language-level"); }
@@ -52,95 +55,12 @@ static inline QString frameworkIncludePathOption() { return QStringLiteral("fram
static inline QString systemIncludePathOption() { return QStringLiteral("system-include-paths"); }
static inline QString typesystemPathOption() { return QStringLiteral("typesystem-paths"); }
static inline QString helpOption() { return QStringLiteral("help"); }
-static const char helpHint[] = "Note: use --help or -h for more information.\n";
-
-namespace {
-
-class ArgsHandler
-{
-public:
- explicit ArgsHandler(const QMap<QString, QString>& other);
- virtual ~ArgsHandler();
-
- inline QMap<QString, QString>& args() const
- {
- return *m_args;
- }
-
- inline bool argExists(const QString& s) const
- {
- return m_args->contains(s);
- }
-
- QString removeArg(const QString& s);
- bool argExistsRemove(const QString& s);
+static inline QString diffOption() { return QStringLiteral("diff"); }
+static inline QString dryrunOption() { return QStringLiteral("dry-run"); }
- inline QString argValue(const QString& s) const
- {
- return m_args->value(s);
- }
-
- inline bool noArgs() const
- {
- return m_args->isEmpty();
- }
-
- QString errorMessage() const;
-
-private:
- QMap<QString, QString>* m_args;
-};
-
-ArgsHandler::ArgsHandler(const QMap<QString, QString>& other)
- : m_args(new QMap<QString, QString>(other))
-{
-}
-
-ArgsHandler::~ArgsHandler()
-{
- delete m_args;
-}
-
-QString ArgsHandler::removeArg(const QString& s)
-{
- QString retval;
-
- if (argExists(s)) {
- retval = argValue(s);
- m_args->remove(s);
- }
-
- return retval;
-}
-
-bool ArgsHandler::argExistsRemove(const QString& s)
-{
- bool retval = false;
-
- if (argExists(s)) {
- retval = true;
- m_args->remove(s);
- }
+static const char helpHint[] = "Note: use --help or -h for more information.\n";
- return retval;
-}
-
-QString ArgsHandler::errorMessage() const
-{
- typedef QMap<QString, QString>::ConstIterator StringMapConstIt;
-
- QString message;
- QTextStream str(&message);
- str << "shiboken: Called with wrong arguments:";
- for (StringMapConstIt it = m_args->cbegin(), end = m_args->cend(); it != end; ++it) {
- str << ' ' << it.key();
- if (!it.value().isEmpty())
- str << ' ' << it.value();
- }
- str << "\nCommand line: " << QCoreApplication::arguments().join(QLatin1Char(' '));
- return message;
-}
-}
+typedef QMap<QString, QString> CommandArgumentMap;
typedef Generator::OptionDescriptions OptionDescriptions;
@@ -214,18 +134,18 @@ static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args)
}
if (!includePaths.isEmpty())
- args.insert(includePathOption(), includePaths.join(QLatin1String(PATH_SPLITTER)));
+ args.insert(includePathOption(), includePaths.join(pathSplitter));
if (!frameworkIncludePaths.isEmpty())
args.insert(frameworkIncludePathOption(),
- frameworkIncludePaths.join(QLatin1String(PATH_SPLITTER)));
+ frameworkIncludePaths.join(pathSplitter));
if (!systemIncludePaths.isEmpty()) {
args.insert(systemIncludePathOption(),
- systemIncludePaths.join(QLatin1String(PATH_SPLITTER)));
+ systemIncludePaths.join(pathSplitter));
}
if (!typesystemPaths.isEmpty())
- args.insert(typesystemPathOption(), typesystemPaths.join(QLatin1String(PATH_SPLITTER)));
+ args.insert(typesystemPathOption(), typesystemPaths.join(pathSplitter));
if (!apiVersions.isEmpty())
args.insert(QLatin1String("api-version"), apiVersions.join(QLatin1Char('|')));
if (!languageLevel.isEmpty())
@@ -233,9 +153,9 @@ static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args)
return true;
}
-static QMap<QString, QString> getInitializedArguments()
+static CommandArgumentMap getInitializedArguments()
{
- QMap<QString, QString> args;
+ CommandArgumentMap args;
QStringList arguments = QCoreApplication::arguments();
QString appName = arguments.constFirst();
arguments.removeFirst();
@@ -277,11 +197,11 @@ static QMap<QString, QString> getInitializedArguments()
// Concatenate values of path arguments that can occur multiple times on the
// command line.
static void addPathOptionValue(const QString &option, const QString &value,
- QMap<QString, QString> &args)
+ CommandArgumentMap &args)
{
- const QMap<QString, QString>::iterator it = args.find(option);
+ const CommandArgumentMap::iterator it = args.find(option);
if (it != args.end())
- it.value().append(QLatin1String(PATH_SPLITTER) + value);
+ it.value().append(pathSplitter + value);
else
args.insert(option, value);
}
@@ -369,7 +289,9 @@ void printUsage()
s << "Usage:\n "
<< "shiboken [options] header-file typesystem-file\n\n"
<< "General options:\n";
- const QString pathSyntax = QLatin1String("<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]");
+ QString pathSyntax;
+ QTextStream(&pathSyntax) << "<path>[" << pathSplitter << "<path>"
+ << pathSplitter << "...]";
OptionDescriptions generalOptions = OptionDescriptions()
<< qMakePair(QLatin1String("api-version=<\"package mask\">,<\"version\">"),
QLatin1String("Specify the supported api version used to generate the bindings"))
@@ -380,18 +302,22 @@ void printUsage()
<< qMakePair(QLatin1String("drop-type-entries=\"<TypeEntry0>[;TypeEntry1;...]\""),
QLatin1String("Semicolon separated list of type system entries (classes, namespaces,\n"
"global functions and enums) to be dropped from generation."))
- << qMakePair(QLatin1String("-F") + pathSyntax, QString())
+ << qMakePair(QLatin1String("-F<path>"), QString())
<< qMakePair(QLatin1String("framework-include-paths=") + pathSyntax,
QLatin1String("Framework include paths used by the C++ parser"))
- << qMakePair(QLatin1String("-isystem") + pathSyntax, QString())
+ << qMakePair(QLatin1String("-isystem<path>"), QString())
<< qMakePair(QLatin1String("system-include-paths=") + pathSyntax,
QLatin1String("System include paths used by the C++ parser"))
<< qMakePair(QLatin1String("generator-set=<\"generator module\">"),
QLatin1String("generator-set to be used. e.g. qtdoc"))
+ << qMakePair(diffOption(),
+ QLatin1String("Print a diff of wrapper files"))
+ << qMakePair(dryrunOption(),
+ QLatin1String("Dry run, do not generate wrapper files"))
<< qMakePair(QLatin1String("-h"), QString())
<< qMakePair(helpOption(),
QLatin1String("Display this help and exit"))
- << qMakePair(QLatin1String("-I") + pathSyntax, QString())
+ << qMakePair(QLatin1String("-I<path>"), QString())
<< qMakePair(QLatin1String("include-paths=") + pathSyntax,
QLatin1String("Include paths used by the C++ parser"))
<< qMakePair(languageLevelOption() + QLatin1String("=, -std=<level>"),
@@ -407,7 +333,7 @@ void printUsage()
"Replaces and overrides command line arguments"))
<< qMakePair(QLatin1String("silent"),
QLatin1String("Avoid printing any message"))
- << qMakePair(QLatin1String("-T") + pathSyntax, QString())
+ << qMakePair(QLatin1String("-T<path>"), QString())
<< qMakePair(QLatin1String("typesystem-paths=") + pathSyntax,
QLatin1String("Paths used when searching for typesystems"))
<< qMakePair(QLatin1String("version"),
@@ -438,19 +364,15 @@ static inline void errorPrint(const QString& s)
<< "\nCommand line: " << qPrintable(arguments.join(QLatin1Char(' '))) << '\n';
}
-static QString msgInvalidVersion(const QString &package, const QString &version)
-{
- return QLatin1String("Invalid version \"") + version
- + QLatin1String("\" specified for package ") + package + QLatin1Char('.');
-}
-
static void parseIncludePathOption(const QString &option, HeaderType headerType,
- ArgsHandler &args,
+ CommandArgumentMap &args,
ApiExtractor &extractor)
{
- const QString path = args.removeArg(option);
- if (!path.isEmpty()) {
- const QStringList includePathListList = path.split(QLatin1String(PATH_SPLITTER));
+ const CommandArgumentMap::iterator it = args.find(option);
+ if (it != args.end()) {
+ const QStringList includePathListList =
+ it.value().split(pathSplitter, QString::SkipEmptyParts);
+ args.erase(it);
for (const QString &s : includePathListList)
extractor.addIncludePath(HeaderPath{QFile::encodeName(s), headerType});
}
@@ -469,19 +391,24 @@ int main(int argc, char *argv[])
qCDebug(lcShiboken()).noquote().nospace() << QCoreApplication::arguments().join(QLatin1Char(' '));
// Store command arguments in a map
- QMap<QString, QString> args = getCommandLineArgs();
- ArgsHandler argsHandler(args);
+ CommandArgumentMap args = getCommandLineArgs();
Generators generators;
- if (argsHandler.argExistsRemove(QLatin1String("version"))) {
+ CommandArgumentMap::iterator ait = args.find(QLatin1String("version"));
+ if (ait != args.end()) {
+ args.erase(ait);
printVerAndBanner();
return EXIT_SUCCESS;
}
- QString generatorSet = argsHandler.removeArg(QLatin1String("generator-set"));
- // Also check QLatin1String("generatorSet") command line argument for backward compatibility.
- if (generatorSet.isEmpty())
- generatorSet = argsHandler.removeArg(QLatin1String("generatorSet"));
+ QString generatorSet;
+ ait = args.find(QLatin1String("generator-set"));
+ if (ait == args.end()) // Also check QLatin1String("generatorSet") command line argument for backward compatibility.
+ ait = args.find(QLatin1String("generatorSet"));
+ if (ait != args.end()) {
+ generatorSet = ait.value();
+ args.erase(ait);
+ }
// Pre-defined generator sets.
if (generatorSet == QLatin1String("qtdoc")) {
@@ -497,28 +424,45 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
- if (argsHandler.argExistsRemove(QLatin1String("help"))) {
+ ait = args.find(QLatin1String("help"));
+ if (ait != args.end()) {
+ args.erase(ait);
printUsage();
return EXIT_SUCCESS;
}
+ ait = args.find(diffOption());
+ if (ait != args.end()) {
+ args.erase(ait);
+ FileOut::diff = true;
+ }
+
+ ait = args.find(dryrunOption());
+ if (ait != args.end()) {
+ args.erase(ait);
+ FileOut::dummy = true;
+ }
+
QString licenseComment;
- QString licenseFileName = argsHandler.removeArg(QLatin1String("license-file"));
- if (!licenseFileName.isEmpty()) {
- if (QFile::exists(licenseFileName)) {
- QFile licenseFile(licenseFileName);
- if (licenseFile.open(QIODevice::ReadOnly))
- licenseComment = QString::fromUtf8(licenseFile.readAll());
+ ait = args.find(QLatin1String("license-file"));
+ if (ait != args.end()) {
+ QFile licenseFile(ait.value());
+ args.erase(ait);
+ if (licenseFile.open(QIODevice::ReadOnly)) {
+ licenseComment = QString::fromUtf8(licenseFile.readAll());
} else {
- errorPrint(QStringLiteral("Couldn't find the file containing the license heading: %1").
- arg(licenseFileName));
+ errorPrint(QStringLiteral("Could not open the file \"%1\" containing the license heading: %2").
+ arg(QDir::toNativeSeparators(licenseFile.fileName()), licenseFile.errorString()));
return EXIT_FAILURE;
}
}
- QString outputDirectory = argsHandler.removeArg(QLatin1String("output-directory"));
- if (outputDirectory.isEmpty())
- outputDirectory = QLatin1String("out");
+ QString outputDirectory = QLatin1String("out");
+ ait = args.find(QLatin1String("output-directory"));
+ if (ait != args.end()) {
+ outputDirectory = ait.value();
+ args.erase(ait);
+ }
if (!QDir(outputDirectory).exists()) {
if (!QDir().mkpath(outputDirectory)) {
@@ -532,11 +476,15 @@ int main(int argc, char *argv[])
ApiExtractor extractor;
extractor.setLogDirectory(outputDirectory);
- if (argsHandler.argExistsRemove(QLatin1String("silent"))) {
+ ait = args.find(QLatin1String("silent"));
+ if (ait != args.end()) {
extractor.setSilent(true);
+ args.erase(ait);
} else {
- QString level = argsHandler.removeArg(QLatin1String("debug-level"));
- if (!level.isEmpty()) {
+ ait = args.find(QLatin1String("debug-level"));
+ if (ait != args.end()) {
+ const QString level = ait.value();
+ args.erase(ait);
if (level == QLatin1String("sparse"))
extractor.setDebugLevel(ReportHandler::SparseDebug);
else if (level == QLatin1String("medium"))
@@ -545,11 +493,15 @@ int main(int argc, char *argv[])
extractor.setDebugLevel(ReportHandler::FullDebug);
}
}
- if (argsHandler.argExistsRemove(QLatin1String("no-suppress-warnings")))
+ ait = args.find(QLatin1String("no-suppress-warnings"));
+ if (ait != args.end()) {
+ args.erase(ait);
extractor.setSuppressWarnings(false);
-
- if (argsHandler.argExists(QLatin1String("api-version"))) {
- const QStringList &versions = argsHandler.removeArg(QLatin1String("api-version")).split(QLatin1Char('|'));
+ }
+ ait = args.find(QLatin1String("api-version"));
+ if (ait != args.end()) {
+ const QStringList &versions = ait.value().split(QLatin1Char('|'));
+ args.erase(ait);
for (const QString &fullVersion : versions) {
QStringList parts = fullVersion.split(QLatin1Char(','));
QString package;
@@ -563,54 +515,65 @@ int main(int argc, char *argv[])
}
}
- if (argsHandler.argExists(QLatin1String("drop-type-entries")))
- extractor.setDropTypeEntries(argsHandler.removeArg(QLatin1String("drop-type-entries")));
+ ait = args.find(QLatin1String("drop-type-entries"));
+ if (ait != args.end()) {
+ extractor.setDropTypeEntries(ait.value());
+ args.erase(ait);
+ }
- QString path = argsHandler.removeArg(QLatin1String("typesystem-paths"));
- if (!path.isEmpty())
- extractor.addTypesystemSearchPath(path.split(QLatin1String(PATH_SPLITTER)));
+ ait = args.find(QLatin1String("typesystem-paths"));
+ if (ait != args.end()) {
+ extractor.addTypesystemSearchPath(ait.value().split(pathSplitter));
+ args.erase(ait);
+ }
parseIncludePathOption(includePathOption(), HeaderType::Standard,
- argsHandler, extractor);
+ args, extractor);
parseIncludePathOption(frameworkIncludePathOption(), HeaderType::Framework,
- argsHandler, extractor);
+ args, extractor);
parseIncludePathOption(systemIncludePathOption(), HeaderType::System,
- argsHandler, extractor);
+ args, extractor);
- QString cppFileName = argsHandler.removeArg(QLatin1String("arg-1"));
+ ait = args.find(QLatin1String("arg-1"));
+ if (ait == args.end()) {
+ errorPrint(QLatin1String("Required argument header-file is missing."));
+ return EXIT_FAILURE;
+ }
+ const QString cppFileName = ait.value();
+ args.erase(ait);
const QFileInfo cppFileNameFi(cppFileName);
if (!cppFileNameFi.isFile() && !cppFileNameFi.isSymLink()) {
errorPrint(QLatin1Char('"') + cppFileName + QLatin1String("\" does not exist."));
return EXIT_FAILURE;
}
- QString typeSystemFileName = argsHandler.removeArg(QLatin1String("arg-2"));
+ ait = args.find(QLatin1String("arg-2"));
+ if (ait == args.end()) {
+ errorPrint(QLatin1String("Required argument typesystem-file is missing."));
+ return EXIT_FAILURE;
+ }
+ const QString typeSystemFileName = ait.value();
+ args.erase(ait);
QString messagePrefix = QFileInfo(typeSystemFileName).baseName();
if (messagePrefix.startsWith(QLatin1String("typesystem_")))
messagePrefix.remove(0, 11);
ReportHandler::setPrefix(QLatin1Char('(') + messagePrefix + QLatin1Char(')'));
- /* Make sure to remove the project file's arguments (if any) and
- * --project-file, also the arguments of each generator before
- * checking if there isn't any existing arguments in argsHandler.
- */
- argsHandler.removeArg(QLatin1String("project-file"));
- QMap<QString, QString> projectFileArgs = getInitializedArguments();
- if (!projectFileArgs.isEmpty()) {
- QMap<QString, QString>::const_iterator it =
- projectFileArgs.constBegin();
- for ( ; it != projectFileArgs.constEnd(); ++it)
- argsHandler.removeArg(it.key());
- }
- for (const GeneratorPtr &generator : qAsConst(generators)) {
- const OptionDescriptions &options = generator->options();
- for (const auto &od : options)
- argsHandler.removeArg(od.first);
- }
-
- const QString languageLevel = argsHandler.removeArg(languageLevelOption());
- if (!languageLevel.isEmpty()) {
- const QByteArray languageLevelBA = languageLevel.toLatin1();
+ // Pass option to all generators (Cpp/Header generator have the same options)
+ for (ait = args.begin(); ait != args.end(); ) {
+ bool found = false;
+ for (const GeneratorPtr &generator : qAsConst(generators))
+ found |= generator->handleOption(ait.key(), ait.value());
+ if (found)
+ ait = args.erase(ait);
+ else
+ ++ait;
+ }
+
+ ait = args.find(languageLevelOption());
+ if (ait != args.end()) {
+ const QByteArray languageLevelBA = ait.value().toLatin1();
+ args.erase(ait);
const LanguageLevel level = clang::languageLevelFromOption(languageLevelBA.constData());
if (level == LanguageLevel::Default) {
std::cout << "Invalid argument for language level: \""
@@ -620,8 +583,17 @@ int main(int argc, char *argv[])
extractor.setLanguageLevel(level);
}
- if (!argsHandler.noArgs()) {
- errorPrint(argsHandler.errorMessage());
+ /* Make sure to remove the project file's arguments (if any) and
+ * --project-file, also the arguments of each generator before
+ * checking if there isn't any existing arguments in argsHandler.
+ */
+ args.remove(QLatin1String("project-file"));
+ CommandArgumentMap projectFileArgs = getInitializedArguments();
+ for (auto it = projectFileArgs.cbegin(), end = projectFileArgs.cend(); it != end; ++it)
+ args.remove(it.key());
+
+ if (!args.isEmpty()) {
+ errorPrint(msgLeftOverArguments(args));
std::cout << helpHint;
return EXIT_FAILURE;
}
@@ -642,17 +614,16 @@ int main(int argc, char *argv[])
if (!extractor.classCount())
qCWarning(lcShiboken) << "No C++ classes found!";
- qCDebug(lcShiboken) << extractor;
+ qCDebug(lcShiboken) << extractor << '\n'
+ << *TypeDatabase::instance();
for (const GeneratorPtr &g : qAsConst(generators)) {
g->setOutputDirectory(outputDirectory);
g->setLicenseComment(licenseComment);
- if (g->setup(extractor, args)) {
- if (!g->generate()) {
- errorPrint(QLatin1String("Error running generator: ")
- + QLatin1String(g->name()) + QLatin1Char('.'));
- return EXIT_FAILURE;
- }
+ if (!g->setup(extractor) || !g->generate()) {
+ errorPrint(QLatin1String("Error running generator: ")
+ + QLatin1String(g->name()) + QLatin1Char('.'));
+ return EXIT_FAILURE;
}
}
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
index d47ba8bd7..19ddd5f37 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
@@ -28,6 +28,7 @@
#include "qtdocgenerator.h"
#include <abstractmetalang.h>
+#include <messages.h>
#include <reporthandler.h>
#include <typesystem.h>
#include <qtdocparser.h>
@@ -202,34 +203,6 @@ private:
const QString &m_label;
};
-static QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
- const QString &tag, const QString &message)
-{
- QString result;
- QTextStream str(&result);
- str << "While handling <";
- const QStringRef currentTag = reader.name();
- if (currentTag.isEmpty())
- str << tag;
- else
- str << currentTag;
- str << "> in " << context << ", line "<< reader.lineNumber()
- << ": " << message;
- return result;
-}
-
-static QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context,
- const QString &tag, const QString &location, const QString &identifier,
- const QString &fallback)
-{
- QString message = QLatin1String("Falling back to \"")
- + QDir::toNativeSeparators(fallback) + QLatin1String("\" for \"") + location
- + QLatin1Char('"');
- if (!identifier.isEmpty())
- message += QLatin1String(" [") + identifier + QLatin1Char(']');
- return msgTagWarning(reader, context, tag, message);
-}
-
struct QtXmlToSphinx::LinkContext
{
enum Type
@@ -305,7 +278,7 @@ QTextStream &operator<<(QTextStream &str, const QtXmlToSphinx::LinkContext &link
}
QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context)
- : m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false)
+ : m_tableHasHeader(false), m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false)
{
m_handlerMap.insert(QLatin1String("heading"), &QtXmlToSphinx::handleHeadingTag);
m_handlerMap.insert(QLatin1String("brief"), &QtXmlToSphinx::handleParaTag);
@@ -1302,7 +1275,7 @@ bool QtXmlToSphinx::convertToRst(QtDocGenerator *generator,
QFile sourceFile(sourceFileName);
if (!sourceFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
if (errorMessage)
- *errorMessage = FileOut::msgCannotOpenForReading(sourceFile);
+ *errorMessage = msgCannotOpenForReading(sourceFile);
return false;
}
const QString doc = QString::fromUtf8(sourceFile.readAll());
@@ -1325,7 +1298,13 @@ void QtXmlToSphinx::Table::normalize()
//QDoc3 generates tables with wrong number of columns. We have to
//check and if necessary, merge the last columns.
- int maxCols = self.at(0).count();
+ int maxCols = -1;
+ for (const auto &row : qAsConst(self)) {
+ if (row.count() > maxCols)
+ maxCols = row.count();
+ }
+ if (maxCols <= 0)
+ return;
// add col spans
for (row = 0; row < count(); ++row) {
for (col = 0; col < at(row).count(); ++col) {
@@ -1513,11 +1492,10 @@ QString QtDocGenerator::fileNameForContext(GeneratorContext &context) const
const AbstractMetaClass *metaClass = context.metaClass();
if (!context.forSmartPointer()) {
return getClassTargetFullName(metaClass, false) + fileNameSuffix();
- } else {
- const AbstractMetaType *smartPointerType = context.preciseType();
- QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
- return fileNameBase + fileNameSuffix();
}
+ const AbstractMetaType *smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
+ return fileNameBase + fileNameSuffix();
}
void QtDocGenerator::writeFormattedText(QTextStream &s, const Documentation &doc,
@@ -1534,7 +1512,7 @@ void QtDocGenerator::writeFormattedText(QTextStream &s, const Documentation &doc
} else {
const QString &value = doc.value();
const QVector<QStringRef> lines = value.splitRef(QLatin1Char('\n'));
- int typesystemIndentation = std::numeric_limits<int>().max();
+ int typesystemIndentation = std::numeric_limits<int>::max();
// check how many spaces must be removed from the beginning of each line
for (const QStringRef &line : lines) {
const auto it = std::find_if(line.cbegin(), line.cend(),
@@ -1542,7 +1520,7 @@ void QtDocGenerator::writeFormattedText(QTextStream &s, const Documentation &doc
if (it != line.cend())
typesystemIndentation = qMin(typesystemIndentation, int(it - line.cbegin()));
}
- if (typesystemIndentation == std::numeric_limits<int>().max())
+ if (typesystemIndentation == std::numeric_limits<int>::max())
typesystemIndentation = 0;
for (const QStringRef &line : lines) {
s << INDENT
@@ -1677,7 +1655,7 @@ void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass*
functionList << str;
}
- if ((functionList.size() > 0) || (staticFunctionList.size() > 0)) {
+ if (!functionList.isEmpty() || !staticFunctionList.isEmpty()) {
QtXmlToSphinx::Table functionTable;
s << endl
@@ -1694,7 +1672,7 @@ void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass*
void QtDocGenerator::writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions)
{
- if (functions.size() > 0) {
+ if (!functions.isEmpty()) {
s << title << endl
<< QString(title.size(), QLatin1Char('^')) << endl;
@@ -1777,7 +1755,8 @@ void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass*
writeFormattedText(s, func->documentation(), cppClass);
}
-QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* /* cppClass */,
+ const AbstractMetaFunction* func)
{
QString ret;
int optArgs = 0;
@@ -1859,8 +1838,7 @@ void QtDocGenerator::writeDocSnips(QTextStream &s,
if (row.trimmed().size() == 0) {
if (currenRow == 0)
continue;
- else
- s << endl;
+ s << endl;
}
if (currenRow == 0) {
@@ -2124,7 +2102,7 @@ void QtDocGenerator::writeModuleDocumentation()
s << ".. module:: " << it.key() << endl << endl;
- QString title = it.key();
+ const QString &title = it.key();
s << title << endl;
s << Pad('*', title.length()) << endl << endl;
@@ -2201,7 +2179,7 @@ void QtDocGenerator::writeAdditionalDocumentation()
QFile additionalDocumentationFile(m_additionalDocumentationList);
if (!additionalDocumentationFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(lcShiboken, "%s",
- qPrintable(FileOut::msgCannotOpenForReading(additionalDocumentationFile)));
+ qPrintable(msgCannotOpenForReading(additionalDocumentationFile)));
return;
}
@@ -2261,32 +2239,28 @@ void QtDocGenerator::writeAdditionalDocumentation()
successCount, count);
}
-bool QtDocGenerator::doSetup(const QMap<QString, QString>& args)
-{
- m_libSourceDir = args.value(QLatin1String("library-source-dir"));
- m_docDataDir = args.value(QLatin1String("documentation-data-dir"));
#ifdef __WIN32__
# define PATH_SEP ';'
#else
# define PATH_SEP ':'
#endif
- m_codeSnippetDirs = args.value(QLatin1String("documentation-code-snippets-dir"), m_libSourceDir).split(QLatin1Char(PATH_SEP));
- m_extraSectionDir = args.value(QLatin1String("documentation-extra-sections-dir"));
- m_docParser = args.value(QLatin1String("doc-parser")) == QLatin1String("doxygen")
- ? static_cast<DocParser*>(new DoxygenParser)
- : static_cast<DocParser*>(new QtDocParser);
- qCDebug(lcShiboken).noquote().nospace() << "doc-parser: " << args.value(QLatin1String("doc-parser"));
+bool QtDocGenerator::doSetup()
+{
+ if (m_codeSnippetDirs.isEmpty())
+ m_codeSnippetDirs = m_libSourceDir.split(QLatin1Char(PATH_SEP));
+
+ if (!m_docParser)
+ m_docParser = new QtDocParser;
if (m_libSourceDir.isEmpty() || m_docDataDir.isEmpty()) {
qCWarning(lcShiboken) << "Documentation data dir and/or Qt source dir not informed, "
"documentation will not be extracted from Qt sources.";
return false;
- } else {
- m_docParser->setDocumentationDataDirectory(m_docDataDir);
- m_docParser->setLibrarySourceDirectory(m_libSourceDir);
}
- m_additionalDocumentationList = args.value(additionalDocumentationOption());
+
+ m_docParser->setDocumentationDataDirectory(m_docDataDir);
+ m_docParser->setLibrarySourceDirectory(m_libSourceDir);
return true;
}
@@ -2294,19 +2268,49 @@ bool QtDocGenerator::doSetup(const QMap<QString, QString>& args)
Generator::OptionDescriptions QtDocGenerator::options() const
{
return OptionDescriptions()
- << qMakePair(QLatin1String("doc-parser"),
+ << qMakePair(QLatin1String("doc-parser=<parser>"),
QLatin1String("The documentation parser used to interpret the documentation\n"
"input files (qdoc|doxygen)"))
- << qMakePair(QLatin1String("documentation-code-snippets-dir"),
+ << qMakePair(QLatin1String("documentation-code-snippets-dir=<dir>"),
QLatin1String("Directory used to search code snippets used by the documentation"))
- << qMakePair(QLatin1String("documentation-data-dir"),
+ << qMakePair(QLatin1String("documentation-data-dir=<dir>"),
QLatin1String("Directory with XML files generated by documentation tool"))
- << qMakePair(QLatin1String("documentation-extra-sections-dir"),
+ << qMakePair(QLatin1String("documentation-extra-sections-dir=<dir>"),
QLatin1String("Directory used to search for extra documentation sections"))
- << qMakePair(QLatin1String("library-source-dir"),
+ << qMakePair(QLatin1String("library-source-dir=<dir>"),
QLatin1String("Directory where library source code is located"))
- << qMakePair(additionalDocumentationOption(),
+ << qMakePair(additionalDocumentationOption() + QLatin1String("=<file>"),
QLatin1String("List of additional XML files to be converted to .rst files\n"
"(for example, tutorials)."));
}
+bool QtDocGenerator::handleOption(const QString &key, const QString &value)
+{
+ if (key == QLatin1String("library-source-dir")) {
+ m_libSourceDir = value;
+ return true;
+ }
+ if (key == QLatin1String("documentation-data-dir")) {
+ m_docDataDir = value;
+ return true;
+ }
+ if (key == QLatin1String("documentation-code-snippets-dir")) {
+ m_codeSnippetDirs = value.split(QLatin1Char(PATH_SEP));
+ return true;
+ }
+ if (key == QLatin1String("documentation-extra-sections-dir")) {
+ m_extraSectionDir = value;
+ return true;
+ }
+ if (key == QLatin1String("doc-parser")) {
+ qCDebug(lcShiboken).noquote().nospace() << "doc-parser: " << value;
+ if (value == QLatin1String("doxygen"))
+ m_docParser = new DoxygenParser;
+ return true;
+ }
+ if (key == additionalDocumentationOption()) {
+ m_additionalDocumentationList = value;
+ return true;
+ }
+ return false;
+}
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
index e467abe90..5545de9a9 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
@@ -209,7 +209,7 @@ public:
QString docDataDir() const { return m_docDataDir; }
- bool doSetup(const QMap<QString, QString>& args) override;
+ bool doSetup() override;
const char* name() const override
{
@@ -217,15 +217,15 @@ public:
}
OptionDescriptions options() const override;
+ bool handleOption(const QString &key, const QString &value) override;
QStringList codeSnippetDirs() const
{
return m_codeSnippetDirs;
}
- bool shouldGenerate(const AbstractMetaClass *) const override;
-
protected:
+ bool shouldGenerate(const AbstractMetaClass *) const override;
QString fileNameSuffix() const override;
QString fileNameForContext(GeneratorContext &context) const override;
void generateClass(QTextStream &s, GeneratorContext &classContext) override;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 9e1d6926e..99947d347 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -29,8 +29,10 @@
#include <memory>
#include "cppgenerator.h"
+#include "fileout.h"
#include "overloaddata.h"
#include <abstractmetalang.h>
+#include <messages.h>
#include <reporthandler.h>
#include <typedatabase.h>
@@ -41,6 +43,8 @@
#include <QtCore/QDebug>
#include <QMetaType>
+static const char CPP_ARG0[] = "cppArg0";
+
QHash<QString, QString> CppGenerator::m_nbFuncs = QHash<QString, QString>();
QHash<QString, QString> CppGenerator::m_sqFuncs = QHash<QString, QString>();
QHash<QString, QString> CppGenerator::m_mpFuncs = QHash<QString, QString>();
@@ -58,6 +62,28 @@ inline AbstractMetaType* getTypeWithoutContainer(AbstractMetaType* arg)
return arg;
}
+// A helper for writing C++ return statements for either void ("return;")
+// or some return value ("return value;")
+class returnStatement
+{
+public:
+ explicit returnStatement(QString s) : m_returnValue(std::move(s)) {}
+
+ friend QTextStream &operator<<(QTextStream &s, const returnStatement &r);
+
+private:
+ const QString m_returnValue;
+};
+
+QTextStream &operator<<(QTextStream &s, const returnStatement &r)
+{
+ s << "return";
+ if (!r.m_returnValue.isEmpty())
+ s << ' ' << r.m_returnValue;
+ s << ';';
+ return s;
+}
+
CppGenerator::CppGenerator()
{
// Number protocol structure members names
@@ -87,27 +113,27 @@ CppGenerator::CppGenerator()
m_nbFuncs.insert(QLatin1String("bool"), QLatin1String("nb_nonzero"));
// sequence protocol functions
- typedef QPair<QString, QString> StrPair;
m_sequenceProtocol.insert(QLatin1String("__len__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR), QLatin1String("Py_ssize_t")));
+ {QLatin1String("PyObject* self"),
+ QLatin1String("Py_ssize_t")});
m_sequenceProtocol.insert(QLatin1String("__getitem__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i"),
- QLatin1String("PyObject*")));
+ {QLatin1String("PyObject* self, Py_ssize_t _i"),
+ QLatin1String("PyObject*")});
m_sequenceProtocol.insert(QLatin1String("__setitem__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* _value"),
- QLatin1String("int")));
+ {QLatin1String("PyObject* self, Py_ssize_t _i, PyObject* _value"),
+ QLatin1String("int")});
m_sequenceProtocol.insert(QLatin1String("__getslice__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2"),
- QLatin1String("PyObject*")));
+ {QLatin1String("PyObject* self, Py_ssize_t _i1, Py_ssize_t _i2"),
+ QLatin1String("PyObject*")});
m_sequenceProtocol.insert(QLatin1String("__setslice__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2, PyObject* _value"),
- QLatin1String("int")));
+ {QLatin1String("PyObject* self, Py_ssize_t _i1, Py_ssize_t _i2, PyObject* _value"),
+ QLatin1String("int")});
m_sequenceProtocol.insert(QLatin1String("__contains__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _value"),
- QLatin1String("int")));
+ {QLatin1String("PyObject* self, PyObject* _value"),
+ QLatin1String("int")});
m_sequenceProtocol.insert(QLatin1String("__concat__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _other"),
- QLatin1String("PyObject*")));
+ {QLatin1String("PyObject* self, PyObject* _other"),
+ QLatin1String("PyObject*")});
// Sequence protocol structure members names
m_sqFuncs.insert(QLatin1String("__concat__"), QLatin1String("sq_concat"));
@@ -120,14 +146,14 @@ CppGenerator::CppGenerator()
// mapping protocol function
m_mappingProtocol.insert(QLatin1String("__mlen__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR),
- QLatin1String("Py_ssize_t")));
+ {QLatin1String("PyObject* self"),
+ QLatin1String("Py_ssize_t")});
m_mappingProtocol.insert(QLatin1String("__mgetitem__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key"),
- QLatin1String("PyObject*")));
+ {QLatin1String("PyObject* self, PyObject* _key"),
+ QLatin1String("PyObject*")});
m_mappingProtocol.insert(QLatin1String("__msetitem__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key, PyObject* _value"),
- QLatin1String("int")));
+ {QLatin1String("PyObject* self, PyObject* _key, PyObject* _value"),
+ QLatin1String("int")});
// Sequence protocol structure members names
m_mpFuncs.insert(QLatin1String("__mlen__"), QLatin1String("mp_length"));
@@ -186,18 +212,19 @@ QVector<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(c
return result;
}
-bool CppGenerator::hasBoolCast(const AbstractMetaClass* metaClass) const
+const AbstractMetaFunction *CppGenerator::boolCast(const AbstractMetaClass* metaClass) const
{
if (!useIsNullAsNbNonZero())
- return false;
+ return nullptr;
// TODO: This could be configurable someday
const AbstractMetaFunction* func = metaClass->findFunction(QLatin1String("isNull"));
if (!func || !func->type() || !func->type()->typeEntry()->isPrimitive() || !func->isPublic())
- return false;
+ return nullptr;
const PrimitiveTypeEntry* pte = static_cast<const PrimitiveTypeEntry*>(func->type()->typeEntry());
while (pte->referencedTypeEntry())
pte = pte->referencedTypeEntry();
- return func && func->isConstant() && pte->name() == QLatin1String("bool") && func->arguments().isEmpty();
+ return func && func->isConstant() && pte->name() == QLatin1String("bool")
+ && func->arguments().isEmpty() ? func : nullptr;
}
typedef QMap<QString, AbstractMetaFunctionList> FunctionGroupMap;
@@ -219,6 +246,21 @@ static QString chopType(QString s)
return s;
}
+// Helper for field setters: Check for "const QWidget *" (settable field),
+// but not "int *const" (read-only field).
+static bool isPointerToConst(const AbstractMetaType *t)
+{
+ const AbstractMetaType::Indirections &indirections = t->indirectionsV();
+ return t->isConstant() && !indirections.isEmpty()
+ && indirections.constLast() != Indirection::ConstPointer;
+}
+
+static inline bool canGenerateFieldSetter(const AbstractMetaField *field)
+{
+ const AbstractMetaType *type = field->type();
+ return !type->isConstant() || isPointerToConst(type);
+}
+
/*!
Function used to write the class generated binding code on the buffer
\param s the output buffer
@@ -260,6 +302,8 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
// needs the 'set' class from C++ STL.
if (hasMultipleInheritanceInAncestry(metaClass))
s << "#include <set>" << endl;
+ if (metaClass->generateExceptionHandling())
+ s << "#include <exception>" << endl;
s << endl << "// module include" << endl << "#include \"" << getModuleHeaderFileName() << '"' << endl;
@@ -315,7 +359,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
static_cast<const SmartPointerTypeEntry *>(classContext.preciseType()
->typeEntry());
QString rawGetter = typeEntry->getter();
- s << "static const char * " SMART_POINTER_GETTER " = \"" << rawGetter << "\";";
+ s << "static const char * " << SMART_POINTER_GETTER << " = \"" << rawGetter << "\";";
}
// class inject-code native/beginning
@@ -459,7 +503,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
writeCopyFunction(s, classContext);
- signatureStream << metaClass->fullName() << ".__copy__()" << endl;
+ signatureStream << fullPythonClassName(metaClass) << ".__copy__()" << endl;
}
// Write single method definitions
@@ -490,16 +534,20 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
}
}
- if (hasBoolCast(metaClass)) {
+ if (const AbstractMetaFunction *f = boolCast(metaClass)) {
ErrorCode errorCode(-1);
- s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* self)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, classContext);
- s << INDENT << "int result;" << endl;
- s << INDENT << BEGIN_ALLOW_THREADS << endl;
- s << INDENT << "result = !" CPP_SELF_VAR "->isNull();" << endl;
- s << INDENT << END_ALLOW_THREADS << endl;
- s << INDENT << "return result;" << endl;
+ if (f->allowThread()) {
+ s << INDENT << "int result;" << endl;
+ s << INDENT << BEGIN_ALLOW_THREADS << endl;
+ s << INDENT << "result = !" << CPP_SELF_VAR << "->isNull();" << endl;
+ s << INDENT << END_ALLOW_THREADS << endl;
+ s << INDENT << "return result;" << endl;
+ } else {
+ s << INDENT << "return !" << CPP_SELF_VAR << "->isNull();" << endl;
+ }
s << '}' << endl << endl;
}
@@ -546,7 +594,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
if (metaField->isStatic())
continue;
writeGetterFunction(s, metaField, classContext);
- if (!metaField->type()->isConstant())
+ if (canGenerateFieldSetter(metaField))
writeSetterFunction(s, metaField, classContext);
s << endl;
}
@@ -557,10 +605,12 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
if (metaField->isStatic())
continue;
- bool hasSetter = !metaField->type()->isConstant();
s << INDENT << "{const_cast<char*>(\"" << metaField->name() << "\"), ";
- s << cpythonGetterFunctionName(metaField);
- s << ", " << (hasSetter ? cpythonSetterFunctionName(metaField) : QLatin1String("0"));
+ s << cpythonGetterFunctionName(metaField) << ", ";
+ if (canGenerateFieldSetter(metaField))
+ s << cpythonSetterFunctionName(metaField);
+ else
+ s << '0';
s << "}," << endl;
}
s << INDENT << "{0} // Sentinel" << endl;
@@ -686,7 +736,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
Indentation indentation(INDENT);
- QString defaultReturnExpr;
+ DefaultValue defaultReturnExpr;
if (retType) {
const FunctionModificationList &mods = func->modifications();
for (const FunctionModification &mod : mods) {
@@ -694,9 +744,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) {
static const QRegularExpression regex(QStringLiteral("%(\\d+)"));
Q_ASSERT(regex.isValid());
- defaultReturnExpr = argMod.replacedDefaultExpression;
+ QString expr = argMod.replacedDefaultExpression;
for (int offset = 0; ; ) {
- const QRegularExpressionMatch match = regex.match(defaultReturnExpr, offset);
+ const QRegularExpressionMatch match = regex.match(expr, offset);
if (!match.hasMatch())
break;
const int argId = match.capturedRef(1).toInt() - 1;
@@ -704,23 +754,27 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
qCWarning(lcShiboken) << "The expression used in return value contains an invalid index.";
break;
}
- defaultReturnExpr.replace(match.captured(0), func->arguments().at(argId)->name());
+ expr.replace(match.captured(0), func->arguments().at(argId)->name());
offset = match.capturedStart(1);
}
+ defaultReturnExpr.setType(DefaultValue::Custom);
+ defaultReturnExpr.setValue(expr);
}
}
}
- if (defaultReturnExpr.isEmpty())
+ if (!defaultReturnExpr.isValid())
defaultReturnExpr = minimalConstructor(func->type());
- if (defaultReturnExpr.isEmpty()) {
+ if (!defaultReturnExpr.isValid()) {
QString errorMsg = QLatin1String(__FUNCTION__) + QLatin1String(": ");
if (const AbstractMetaClass *c = func->implementingClass())
errorMsg += c->qualifiedCppName() + QLatin1String("::");
errorMsg += func->signature();
- errorMsg = ShibokenGenerator::msgCouldNotFindMinimalConstructor(errorMsg, func->type()->cppSignature());
+ errorMsg = msgCouldNotFindMinimalConstructor(errorMsg, func->type()->cppSignature());
qCWarning(lcShiboken).noquote().nospace() << errorMsg;
s << endl << INDENT << "#error " << errorMsg << endl;
}
+ } else {
+ defaultReturnExpr.setType(DefaultValue::Void);
}
if (func->isAbstract() && func->isModifiedRemoved()) {
@@ -728,7 +782,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
<< QString::fromLatin1("Pure virtual method '%1::%2' must be implement but was "\
"completely removed on type system.")
.arg(func->ownerClass()->name(), func->minimalSignature());
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
s << '}' << endl << endl;
return;
}
@@ -747,13 +801,13 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << INDENT << "if (PyErr_Occurred())" << endl;
{
Indentation indentation(INDENT);
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
- s << INDENT << "Shiboken::AutoDecRef " PYTHON_OVERRIDE_VAR "(Shiboken::BindingManager::instance().getOverride(this, \"";
+ s << INDENT << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR << "(Shiboken::BindingManager::instance().getOverride(this, \"";
s << funcName << "\"));" << endl;
- s << INDENT << "if (" PYTHON_OVERRIDE_VAR ".isNull()) {" << endl;
+ s << INDENT << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {" << endl;
{
Indentation indentation(INDENT);
CodeSnipList snips;
@@ -768,7 +822,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
s << func->ownerClass()->name() << '.' << funcName;
s << "()' not implemented.\");" << endl;
- s << INDENT << "return " << (retType ? defaultReturnExpr : QString());
+ s << INDENT << "return";
+ if (retType)
+ s << ' ' << defaultReturnExpr.returnValue();
} else {
s << INDENT << "gil.release();" << endl;
s << INDENT;
@@ -785,7 +841,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
writeConversionRule(s, func, TypeSystem::TargetLangCode);
- s << INDENT << "Shiboken::AutoDecRef " PYTHON_ARGS "(";
+ s << INDENT << "Shiboken::AutoDecRef " << PYTHON_ARGS << "(";
if (func->arguments().isEmpty() || allArgumentsRemoved(func)) {
s << "PyTuple_New(0));" << endl;
@@ -844,7 +900,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (argMod.resetAfterUse && !invalidateArgs.contains(argMod.index)) {
invalidateArgs.insert(argMod.index);
s << INDENT << "bool invalidateArg" << argMod.index;
- s << " = PyTuple_GET_ITEM(" PYTHON_ARGS ", " << argMod.index - 1 << ")->ob_refcnt == 1;" << endl;
+ s << " = PyTuple_GET_ITEM(" << PYTHON_ARGS << ", " << argMod.index - 1 << ")->ob_refcnt == 1;" << endl;
} else if (argMod.index == 0 && argMod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::CppOwnership) {
invalidateReturn = true;
}
@@ -866,36 +922,36 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (!injectedCodeCallsPythonOverride(func)) {
s << INDENT;
- s << "Shiboken::AutoDecRef " PYTHON_RETURN_VAR "(PyObject_Call(" PYTHON_OVERRIDE_VAR ", " PYTHON_ARGS ", NULL));" << endl;
+ s << "Shiboken::AutoDecRef " << PYTHON_RETURN_VAR << "(PyObject_Call(" << PYTHON_OVERRIDE_VAR << ", " << PYTHON_ARGS << ", NULL));" << endl;
s << INDENT << "// An error happened in python code!" << endl;
- s << INDENT << "if (" PYTHON_RETURN_VAR ".isNull()) {" << endl;
+ s << INDENT << "if (" << PYTHON_RETURN_VAR << ".isNull()) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "PyErr_Print();" << endl;
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << '}' << endl;
if (retType) {
if (invalidateReturn)
- s << INDENT << "bool invalidateArg0 = " PYTHON_RETURN_VAR "->ob_refcnt == 1;" << endl;
+ s << INDENT << "bool invalidateArg0 = " << PYTHON_RETURN_VAR << "->ob_refcnt == 1;" << endl;
if (func->typeReplaced(0) != QLatin1String("PyObject")) {
s << INDENT << "// Check return type" << endl;
s << INDENT;
if (func->typeReplaced(0).isEmpty()) {
- s << "PythonToCppFunc " PYTHON_TO_CPP_VAR " = " << cpythonIsConvertibleFunction(func->type());
- s << PYTHON_RETURN_VAR ");" << endl;
- s << INDENT << "if (!" PYTHON_TO_CPP_VAR ") {" << endl;
+ s << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << " = " << cpythonIsConvertibleFunction(func->type());
+ s << PYTHON_RETURN_VAR << ");" << endl;
+ s << INDENT << "if (!" << PYTHON_TO_CPP_VAR << ") {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
"\"Invalid return value in function %s, expected %s, got %s.\", \"";
s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
- s << ", Py_TYPE(" PYTHON_RETURN_VAR ")->tp_name);" << endl;
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);" << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << '}' << endl;
@@ -907,15 +963,16 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
isNumber(func->type()->typeEntry()), func->typeReplaced(0));
s << ';' << endl;
s << INDENT << "if (!typeIsValid";
- s << (isPointerToWrapperType(func->type()) ? " && " PYTHON_RETURN_VAR " != Py_None" : "");
+ if (isPointerToWrapperType(func->type()))
+ s << " && " << PYTHON_RETURN_VAR << " != Py_None";
s << ") {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
"\"Invalid return value in function %s, expected %s, got %s.\", \"";
s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
- s << ", Py_TYPE(" PYTHON_RETURN_VAR ")->tp_name);" << endl;
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);" << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << '}' << endl;
@@ -935,12 +992,12 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (invalidateReturn) {
s << INDENT << "if (invalidateArg0)" << endl;
Indentation indentation(INDENT);
- s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR ".object());" << endl;
+ s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ".object());" << endl;
}
for (int argIndex : qAsConst(invalidateArgs)) {
s << INDENT << "if (invalidateArg" << argIndex << ')' << endl;
Indentation indentation(INDENT);
- s << INDENT << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" PYTHON_ARGS ", ";
+ s << INDENT << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" << PYTHON_ARGS << ", ";
s << (argIndex - 1) << "));" << endl;
}
@@ -950,9 +1007,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
for (const ArgumentModification &argMod : funcMod.argument_mods) {
if (argMod.ownerships.contains(TypeSystem::NativeCode)
&& argMod.index == 0 && argMod.ownerships[TypeSystem::NativeCode] == TypeSystem::CppOwnership) {
- s << INDENT << "if (Shiboken::Object::checkType(" PYTHON_RETURN_VAR "))" << endl;
+ s << INDENT << "if (Shiboken::Object::checkType(" << PYTHON_RETURN_VAR << "))" << endl;
Indentation indent(INDENT);
- s << INDENT << "Shiboken::Object::releaseOwnership(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ");" << endl;
}
}
}
@@ -978,7 +1035,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
}
if (func->type()->referenceType() == LValueReference && !isPointer(func->type()))
s << '*';
- s << CPP_RETURN_VAR ";" << endl;
+ s << CPP_RETURN_VAR << ';' << endl;
}
s << '}' << endl << endl;
@@ -995,7 +1052,7 @@ void CppGenerator::writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass
s << INDENT << "SbkObject* pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl;
s << INDENT << "if (pySelf == NULL)" << endl;
s << INDENT << INDENT << "return " << metaClass->qualifiedCppName() << "::metaObject();" << endl;
- s << INDENT << "return PySide::SignalManager::retriveMetaObject(reinterpret_cast<PyObject*>(pySelf));" << endl;
+ s << INDENT << "return PySide::SignalManager::retrieveMetaObject(reinterpret_cast<PyObject*>(pySelf));" << endl;
s << '}' << endl << endl;
// qt_metacall function
@@ -1259,7 +1316,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla
toCppConv = QLatin1Char('*') + cpythonWrapperCPtr(sourceClass->typeEntry(), QLatin1String("pyIn"));
} else {
// Constructor that does implicit conversion.
- if (!conv->typeReplaced(1).isEmpty())
+ if (!conv->typeReplaced(1).isEmpty() || conv->isModifiedToArray(1))
continue;
const AbstractMetaType* sourceType = conv->arguments().constFirst()->type();
typeCheck = cpythonCheckFunction(sourceType);
@@ -1419,7 +1476,7 @@ void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClas
sourceType = buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass());
} else {
// Constructor that does implicit conversion.
- if (!conv->typeReplaced(1).isEmpty())
+ if (!conv->typeReplaced(1).isEmpty() || conv->isModifiedToArray(1))
continue;
sourceType = conv->arguments().constFirst()->type();
}
@@ -1467,7 +1524,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
// Check if the right constructor was called.
if (!ownerClass->hasPrivateDestructor()) {
s << INDENT;
- s << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ") && !Shiboken::ObjectType::canCallConstructor(" PYTHON_SELF_VAR "->ob_type, Shiboken::SbkType< ::";
+ s << "if (Shiboken::Object::isUserType(self) && !Shiboken::ObjectType::canCallConstructor(self->ob_type, Shiboken::SbkType< ::";
QString qualifiedCppName;
if (!context.forSmartPointer())
qualifiedCppName = ownerClass->qualifiedCppName();
@@ -1476,7 +1533,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
s << qualifiedCppName << " >()))" << endl;
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl << endl;
}
// Declare pointer for the underlying C++ object.
s << INDENT << "::";
@@ -1497,7 +1554,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
writeCppSelfDefinition(s, rfunc, context, overloadData.hasStaticFunction());
}
if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType())
- s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+ s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = 0;" << endl;
initPythonArguments = minArgs != maxArgs || maxArgs > 1;
usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue();
@@ -1505,7 +1562,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
if (maxArgs > 0) {
s << INDENT << "int overloadId = -1;" << endl;
- s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR;
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR;
if (pythonFunctionWrapperUsesListOfArguments(overloadData))
s << "[] = { 0" << QString::fromLatin1(", 0").repeated(maxArgs-1) << " }";
s << ';' << endl;
@@ -1518,7 +1575,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
if (initPythonArguments) {
s << INDENT << "int numArgs = ";
if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData))
- s << "(" PYTHON_ARG " == 0 ? 0 : 1);" << endl;
+ s << "(" << PYTHON_ARG << " == 0 ? 0 : 1);" << endl;
else
writeArgumentsInitializer(s, overloadData);
}
@@ -1534,7 +1591,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
const AbstractMetaClass* metaClass = rfunc->ownerClass();
s << "static int" << endl;
- s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* args, PyObject* kwds)" << endl;
+ s << cpythonFunctionName(rfunc) << "(PyObject* self, PyObject* args, PyObject* kwds)" << endl;
s << '{' << endl;
QSet<QString> argNamesSet;
@@ -1560,10 +1617,10 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
s << INDENT << "const QMetaObject* metaObject;" << endl;
}
- s << INDENT << "SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(self);" << endl;
if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) {
- s << INDENT << "SbkObjectType* type = reinterpret_cast<SbkObjectType*>(" PYTHON_SELF_VAR "->ob_type);" << endl;
+ s << INDENT << "SbkObjectType* type = reinterpret_cast<SbkObjectType*>(self->ob_type);" << endl;
s << INDENT << "SbkObjectType* myType = reinterpret_cast<SbkObjectType*>(" << cpythonTypeNameExt(metaClass->typeEntry()) << ");" << endl;
}
@@ -1577,7 +1634,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
s << INDENT << "\"'" << metaClass->qualifiedCppName();
}
s << "' represents a C++ abstract class and cannot be instantiated\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}' << endl << endl;
}
@@ -1608,7 +1665,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
{
Indentation indent(INDENT);
s << INDENT << "delete cptr;" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}' << endl;
if (overloadData.maxArgs() > 0) {
@@ -1636,12 +1693,12 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
// Create metaObject and register signal/slot
if (metaClass->isQObject() && usePySideExtensions()) {
s << endl << INDENT << "// QObject setup" << endl;
- s << INDENT << "PySide::Signal::updateSourceObject(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "PySide::Signal::updateSourceObject(self);" << endl;
s << INDENT << "metaObject = cptr->metaObject(); // <- init python qt properties" << endl;
- s << INDENT << "if (kwds && !PySide::fillQtProperties(" PYTHON_SELF_VAR ", metaObject, kwds, argNames, " << argNamesSet.count() << "))" << endl;
+ s << INDENT << "if (kwds && !PySide::fillQtProperties(self, metaObject, kwds, argNames, " << argNamesSet.count() << "))" << endl;
{
Indentation indentation(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
}
@@ -1694,7 +1751,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
int maxArgs = overloadData.maxArgs();
s << "static PyObject* ";
- s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR;
+ s << cpythonFunctionName(rfunc) << "(PyObject* self";
if (maxArgs > 0) {
s << ", PyObject* " << (pythonFunctionWrapperUsesListOfArguments(overloadData) ? "args" : PYTHON_ARG);
if (overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator())
@@ -1725,26 +1782,26 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
s << INDENT << "if (!isReverse" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "&& Shiboken::Object::checkType(" PYTHON_ARG ")" << endl;
- s << INDENT << "&& !PyObject_TypeCheck(" PYTHON_ARG ", " PYTHON_SELF_VAR "->ob_type)" << endl;
- s << INDENT << "&& PyObject_HasAttrString(" PYTHON_ARG ", const_cast<char*>(\"" << revOpName << "\"))) {" << endl;
+ s << INDENT << "&& Shiboken::Object::checkType(" << PYTHON_ARG << ")" << endl;
+ s << INDENT << "&& !PyObject_TypeCheck(" << PYTHON_ARG << ", self->ob_type)" << endl;
+ s << INDENT << "&& PyObject_HasAttrString(" << PYTHON_ARG << ", const_cast<char*>(\"" << revOpName << "\"))) {" << endl;
// This PyObject_CallMethod call will emit lots of warnings like
// "deprecated conversion from string constant to char *" during compilation
// due to the method name argument being declared as "char*" instead of "const char*"
// issue 6952 http://bugs.python.org/issue6952
- s << INDENT << "PyObject* revOpMethod = PyObject_GetAttrString(" PYTHON_ARG ", const_cast<char*>(\"" << revOpName << "\"));" << endl;
+ s << INDENT << "PyObject* revOpMethod = PyObject_GetAttrString(" << PYTHON_ARG << ", const_cast<char*>(\"" << revOpName << "\"));" << endl;
s << INDENT << "if (revOpMethod && PyCallable_Check(revOpMethod)) {" << endl;
{
Indentation indent(INDENT);
- s << INDENT << PYTHON_RETURN_VAR " = PyObject_CallFunction(revOpMethod, const_cast<char*>(\"O\"), " PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << PYTHON_RETURN_VAR << " = PyObject_CallFunction(revOpMethod, const_cast<char*>(\"O\"), self);" << endl;
s << INDENT << "if (PyErr_Occurred() && (PyErr_ExceptionMatches(PyExc_NotImplementedError)";
s << " || PyErr_ExceptionMatches(PyExc_AttributeError))) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "PyErr_Clear();" << endl;
- s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
- s << INDENT << PYTHON_RETURN_VAR " = 0;" << endl;
+ s << INDENT << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");" << endl;
+ s << INDENT << PYTHON_RETURN_VAR << " = 0;" << endl;
}
s << INDENT << '}' << endl;
}
@@ -1754,7 +1811,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
s << INDENT << "}" << endl;
}
s << INDENT << "// Do not enter here if other object has implemented a reverse operator." << endl;
- s << INDENT << "if (!" PYTHON_RETURN_VAR ") {" << endl << endl;
+ s << INDENT << "if (!" << PYTHON_RETURN_VAR << ") {" << endl << endl;
}
if (maxArgs > 0)
@@ -1763,7 +1820,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
writeFunctionCalls(s, overloadData, classContext);
if (callExtendedReverseOperator)
- s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl;
+ s << endl << INDENT << "} // End of \"if (!" << PYTHON_RETURN_VAR << ")\"" << endl;
s << endl;
@@ -1771,10 +1828,10 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
if (hasReturnValue) {
if (rfunc->isInplaceOperator()) {
- s << INDENT << "Py_INCREF(" PYTHON_SELF_VAR ");\n";
- s << INDENT << "return " PYTHON_SELF_VAR ";\n";
+ s << INDENT << "Py_INCREF(self);\n";
+ s << INDENT << "return self;\n";
} else {
- s << INDENT << "return " PYTHON_RETURN_VAR ";\n";
+ s << INDENT << "return " << PYTHON_RETURN_VAR << ";\n";
}
} else {
s << INDENT << "Py_RETURN_NONE;" << endl;
@@ -1795,7 +1852,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
int maxArgs = overloadData.maxArgs();
s << INDENT << "PyObject* ";
- s << PYTHON_ARGS "[] = {"
+ s << PYTHON_ARGS << "[] = {"
<< QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), QString::SkipEmptyParts).join(QLatin1String(", "))
<< "};" << endl;
s << endl;
@@ -1807,8 +1864,8 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
s << INDENT << "PyObject* nonvarargs = PyTuple_GetSlice(args, 0, " << maxArgs << ");" << endl;
s << INDENT << "Shiboken::AutoDecRef auto_nonvarargs(nonvarargs);" << endl;
- s << INDENT << PYTHON_ARGS "[" << maxArgs << "] = PyTuple_GetSlice(args, " << maxArgs << ", numArgs);" << endl;
- s << INDENT << "Shiboken::AutoDecRef auto_varargs(" PYTHON_ARGS "[" << maxArgs << "]);" << endl;
+ s << INDENT << PYTHON_ARGS << '[' << maxArgs << "] = PyTuple_GetSlice(args, " << maxArgs << ", numArgs);" << endl;
+ s << INDENT << "Shiboken::AutoDecRef auto_varargs(" << PYTHON_ARGS << "[" << maxArgs << "]);" << endl;
s << endl;
}
@@ -1822,7 +1879,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}';
}
@@ -1835,7 +1892,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}';
}
@@ -1867,13 +1924,12 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
s << "PyArg_ParseTuple(" << argsVar << ", \"|" << QByteArray(maxArgs, 'O') << ':' << funcName << '"';
else
s << "PyArg_UnpackTuple(" << argsVar << ", \"" << funcName << "\", " << minArgs << ", " << maxArgs;
- QStringList palist;
for (int i = 0; i < maxArgs; i++)
- palist << QString::fromLatin1("&(" PYTHON_ARGS "[%1])").arg(i);
- s << ", " << palist.join(QLatin1String(", ")) << "))" << endl;
+ s << ", &(" << PYTHON_ARGS << '[' << i << "])";
+ s << "))" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << endl;
}
@@ -1895,7 +1951,7 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s,
}
QString cppSelfAttribution;
- QString pythonSelfVar = QLatin1String(PYTHON_SELF_VAR);
+ QString pythonSelfVar = QLatin1String("self");
QString cpythonWrapperCPtrResult;
if (!context.forSmartPointer())
cpythonWrapperCPtrResult = cpythonWrapperCPtr(metaClass, pythonSelfVar);
@@ -1908,7 +1964,7 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s,
.arg(className, QLatin1String(CPP_SELF_VAR), cast,
cpythonWrapperCPtrResult);
} else {
- s << INDENT << className << "* " CPP_SELF_VAR " = 0;" << endl;
+ s << INDENT << className << "* " << CPP_SELF_VAR << " = 0;" << endl;
writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
cppSelfAttribution = QString::fromLatin1("%1 = %2%3")
.arg(QLatin1String(CPP_SELF_VAR),
@@ -1918,17 +1974,17 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s,
// Checks if the underlying C++ object is valid.
if (hasStaticOverload && !cppSelfAsReference) {
- s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl;
+ s << INDENT << "if (self) {" << endl;
{
Indentation indent(INDENT);
- writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ writeInvalidPyObjectCheck(s, QLatin1String("self"));
s << INDENT << cppSelfAttribution << ';' << endl;
}
s << INDENT << '}' << endl;
return;
}
- writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ writeInvalidPyObjectCheck(s, QLatin1String("self"));
s << INDENT << cppSelfAttribution << ';' << endl;
}
@@ -1942,17 +1998,17 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s,
if (func->isOperatorOverload() && func->isBinaryOperator()) {
QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry());
- s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG ")" << endl;
+ s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG << ')' << endl;
{
Indentation indent1(INDENT);
Indentation indent2(INDENT);
Indentation indent3(INDENT);
Indentation indent4(INDENT);
- s << INDENT << "&& !" << checkFunc << PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "&& !" << checkFunc << "self);" << endl;
}
s << INDENT << "if (isReverse)" << endl;
Indentation indent(INDENT);
- s << INDENT << "std::swap(" PYTHON_SELF_VAR ", " PYTHON_ARG ");" << endl;
+ s << INDENT << "std::swap(self, " << PYTHON_ARG << ");" << endl;
}
writeCppSelfDefinition(s, context, hasStaticOverload);
@@ -2053,17 +2109,20 @@ void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData)
<< ", 0};" << endl;
s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", overloads);" << endl;
}
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
void CppGenerator::writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue)
{
- s << INDENT << "if (PyErr_Occurred()" << (hasReturnValue ? " || !" PYTHON_RETURN_VAR : "") << ") {" << endl;
+ s << INDENT << "if (PyErr_Occurred()";
+ if (hasReturnValue)
+ s << " || !" << PYTHON_RETURN_VAR;
+ s << ") {" << endl;
{
Indentation indent(INDENT);
if (hasReturnValue)
- s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");" << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}' << endl;
}
@@ -2072,12 +2131,13 @@ void CppGenerator::writeInvalidPyObjectCheck(QTextStream& s, const QString& pyOb
{
s << INDENT << "if (!Shiboken::Object::isValid(" << pyObj << "))" << endl;
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
static QString pythonToCppConverterForArgumentName(const QString& argumentName)
{
- static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS"(\\[\\d+[-]?\\d*\\])"));
+ static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS)
+ + QLatin1String(R"((\[\d+[-]?\d*\]))"));
Q_ASSERT(pyArgsRegex.isValid());
const QRegularExpressionMatch match = pyArgsRegex.match(argumentName);
QString result = QLatin1String(PYTHON_TO_CPP_VAR);
@@ -2379,7 +2439,7 @@ void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunctio
void CppGenerator::writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue)
{
if (thereIsReturnValue && (!func->type() || func->argumentRemoved(0)) && !injectedCodeHasReturnValueAttribution(func)) {
- s << INDENT << PYTHON_RETURN_VAR " = Py_None;" << endl;
+ s << INDENT << PYTHON_RETURN_VAR << " = Py_None;" << endl;
s << INDENT << "Py_INCREF(Py_None);" << endl;
}
}
@@ -2493,8 +2553,9 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const Ov
const AbstractMetaFunction* refFunc = overloadData->referenceFunction();
QStringList typeChecks;
+
QString pyArgName = (usePyArgs && maxArgs > 1)
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(overloadData->argPos())
+ ? pythonArgsAt(overloadData->argPos())
: QLatin1String(PYTHON_ARG);
OverloadData* od = overloadData;
int startArg = od->argPos();
@@ -2503,7 +2564,7 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const Ov
bool typeReplacedByPyObject = od->argumentTypeReplaced() == QLatin1String("PyObject");
if (!typeReplacedByPyObject) {
if (usePyArgs)
- pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(od->argPos());
+ pyArgName = pythonArgsAt(od->argPos());
QString typeCheck;
QTextStream tck(&typeCheck);
const AbstractMetaFunction* func = od->referenceFunction();
@@ -2613,7 +2674,7 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s,
s << INDENT << "PyErr_Format(PyExc_TypeError, \"%s is a private method.\", \""
<< func->signature().replace(QLatin1String("::"), QLatin1String("."))
<< "\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
return;
}
@@ -2630,7 +2691,8 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s,
const AbstractMetaArgument* arg = func->arguments().at(argIdx);
if (func->argumentRemoved(argIdx + 1)) {
if (!arg->defaultValueExpression().isEmpty()) {
- QString cppArgRemoved = QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(argIdx);
+ const QString cppArgRemoved = QLatin1String(CPP_ARG_REMOVED)
+ + QString::number(argIdx);
s << INDENT << getFullTypeName(arg->type()) << ' ' << cppArgRemoved;
s << " = " << guessScopeForDefaultValue(func, arg) << ';' << endl;
writeUnusedVariableCast(s, cppArgRemoved);
@@ -2649,8 +2711,8 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s,
if (!argType || (mayHaveUnunsedArguments && !injectedCodeUsesArgument(func, argIdx)))
continue;
int argPos = argIdx - removedArgs;
- QString argName = QString::fromLatin1(CPP_ARG"%1").arg(argPos);
- QString pyArgName = usePyArgs ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos) : QLatin1String(PYTHON_ARG);
+ QString argName = QLatin1String(CPP_ARG) + QString::number(argPos);
+ QString pyArgName = usePyArgs ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG);
QString defaultValue = guessScopeForDefaultValue(func, arg);
writeArgumentConversion(s, argType, argName, pyArgName, func->implementingClass(), defaultValue, func->isUserAdded());
}
@@ -2896,10 +2958,8 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, const Abs
const AbstractMetaType* type = containerType->instantiations().at(i);
QString typeName = getFullTypeName(type);
if (type->isValue() && isValueTypeWithCopyConstructorOnly(type)) {
- static const QRegularExpression regex(QLatin1String(CONVERTTOCPP_REGEX));
- Q_ASSERT(regex.isValid());
for (int pos = 0; ; ) {
- const QRegularExpressionMatch match = regex.match(code, pos);
+ const QRegularExpressionMatch match = convertToCppRegEx().match(code, pos);
if (!match.hasMatch())
break;
pos = match.capturedEnd();
@@ -2954,15 +3014,13 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream& s, const AbstractMe
s << INDENT << "PyObject* ";
for (const AbstractMetaArgument *arg : args) {
int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
- QString pyArgName = usePyArgs
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(pyArgIndex)
- : QLatin1String(PYTHON_ARG);
+ QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG);
s << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
s << INDENT << "if (value && " << pyArgName << ") {" << endl;
{
Indentation indent(INDENT);
s << INDENT << pyErrString.arg(arg->name()) << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << "} else if (value) {" << endl;
{
@@ -2989,7 +3047,7 @@ QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, in
*wrappedClass = 0;
QString pyArgName;
if (argIndex == -1) {
- pyArgName = QLatin1String(PYTHON_SELF_VAR);
+ pyArgName = QLatin1String("self");
*wrappedClass = func->implementingClass();
} else if (argIndex == 0) {
AbstractMetaType *funcType = func->type();
@@ -3016,12 +3074,23 @@ QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, in
&& OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass())[func->name()]))
pyArgName = QLatin1String(PYTHON_ARG);
else
- pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argIndex - 1);
+ pyArgName = pythonArgsAt(argIndex - 1);
}
}
return pyArgName;
}
+static QStringList defaultExceptionHandling()
+{
+ static const QStringList result{
+ QLatin1String("} catch (const std::exception &e) {"),
+ QLatin1String(" PyErr_SetString(PyExc_RuntimeError, e.what());"),
+ QLatin1String("} catch (...) {"),
+ QLatin1String(" PyErr_SetString(PyExc_RuntimeError, \"An unknown exception was caught\");"),
+ QLatin1String("}")};
+ return result;
+}
+
void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *func,
GeneratorContext &context, int maxArgs)
{
@@ -3037,12 +3106,12 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
}
if (func->isAbstract()) {
- s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "))) {\n";
+ s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(self))) {\n";
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
s << func->ownerClass()->name() << '.' << func->name() << "()' not implemented.\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << "}\n";
}
@@ -3091,16 +3160,21 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
if (hasConversionRule)
userArgs << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
else if (!arg->defaultValueExpression().isEmpty())
- userArgs << QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(i);
+ userArgs.append(QLatin1String(CPP_ARG_REMOVED) + QString::number(i));
} else {
int idx = arg->argumentIndex() - removedArgs;
bool deRef = isValueTypeWithCopyConstructorOnly(arg->type())
|| isObjectTypeUsedAsValueType(arg->type())
|| (arg->type()->referenceType() == LValueReference && isWrapperType(arg->type()) && !isPointer(arg->type()));
- QString argName = hasConversionRule
- ? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
- : QString::fromLatin1("%1" CPP_ARG "%2").arg(deRef ? QLatin1String("*") : QString()).arg(idx);
- userArgs << argName;
+ if (hasConversionRule) {
+ userArgs.append(arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
+ } else {
+ QString argName;
+ if (deRef)
+ argName += QLatin1Char('*');
+ argName += QLatin1String(CPP_ARG) + QString::number(idx);
+ userArgs.append(argName);
+ }
}
}
@@ -3113,17 +3187,16 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
bool argsClear = true;
for (int i = func->arguments().size() - 1; i >= maxArgs + removedArgs; i--) {
const AbstractMetaArgument* arg = func->arguments().at(i);
- bool defValModified = arg->defaultValueExpression() != arg->originalDefaultValueExpression();
+ const bool defValModified = arg->hasModifiedDefaultValueExpression();
bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
if (argsClear && !defValModified && !hasConversionRule)
continue;
- else
- argsClear = false;
+ argsClear = false;
otherArgsModified |= defValModified || hasConversionRule || func->argumentRemoved(i + 1);
if (hasConversionRule)
otherArgs.prepend(arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
else
- otherArgs.prepend(QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(i));
+ otherArgs.prepend(QLatin1String(CPP_ARG_REMOVED) + QString::number(i));
}
if (otherArgsModified)
userArgs << otherArgs;
@@ -3135,10 +3208,11 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
QString useVAddr;
QTextStream uva(&useVAddr);
if (func->isOperatorOverload() && !func->isCallOperator()) {
- QString firstArg = QLatin1String("(*" CPP_SELF_VAR ")");
- if (func->isPointerOperator())
- firstArg.remove(1, 1); // remove the de-reference operator
-
+ QString firstArg(QLatin1Char('('));
+ if (!func->isPointerOperator()) // no de-reference operator
+ firstArg += QLatin1Char('*');
+ firstArg += QLatin1String(CPP_SELF_VAR);
+ firstArg += QLatin1Char(')');
QString secondArg = QLatin1String(CPP_ARG0);
if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().constFirst())) {
secondArg.prepend(QLatin1String("(*"));
@@ -3211,7 +3285,8 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
} else {
const QString selfVarCast = func->ownerClass() == func->implementingClass()
? QLatin1String(CPP_SELF_VAR)
- : QLatin1String("reinterpret_cast<") + methodCallClassName + QLatin1String(" *>(" CPP_SELF_VAR ")");
+ : QLatin1String("reinterpret_cast<") + methodCallClassName
+ + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')');
if (func->isConstant()) {
if (avoidProtectedHack()) {
mc << "const_cast<const ::";
@@ -3219,7 +3294,8 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
// PYSIDE-500: Need a special wrapper cast when inherited
const QString selfWrapCast = func->ownerClass() == func->implementingClass()
? QLatin1String(CPP_SELF_VAR)
- : QLatin1String("reinterpret_cast<") + wrapperName(func->ownerClass()) + QLatin1String(" *>(" CPP_SELF_VAR ")");
+ : QLatin1String("reinterpret_cast<") + wrapperName(func->ownerClass())
+ + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')');
mc << wrapperName(func->ownerClass());
mc << "*>(" << selfWrapCast << ")->";
}
@@ -3263,7 +3339,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
methodCallClassName);
normalCall.remove(QLatin1String("::%CLASS_NAME::"));
methodCall.clear();
- mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")) ? ";
+ mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(self)) ? ";
mc << virtualCall << " : " << normalCall;
}
}
@@ -3271,7 +3347,19 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
}
if (!injectedCodeCallsCppFunction(func)) {
- s << INDENT << BEGIN_ALLOW_THREADS << endl << INDENT;
+ const bool allowThread = func->allowThread();
+ const bool generateExceptionHandling = func->generateExceptionHandling();
+ if (generateExceptionHandling) {
+ s << INDENT << "try {\n";
+ ++INDENT.indent;
+ if (allowThread) {
+ s << INDENT << "Shiboken::ThreadStateSaver threadSaver;\n"
+ << INDENT << "threadSaver.save();\n";
+ }
+ } else if (allowThread) {
+ s << INDENT << BEGIN_ALLOW_THREADS << endl;
+ }
+ s << INDENT;
if (isCtor) {
s << (useVAddr.isEmpty() ?
QString::fromLatin1("cptr = %1;").arg(methodCall) : useVAddr) << endl;
@@ -3299,18 +3387,23 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
methodCall.append(QLatin1Char(')'));
}
}
- s << " " CPP_RETURN_VAR " = ";
+ s << " " << CPP_RETURN_VAR << " = ";
s << methodCall << ';' << endl;
} else {
s << methodCall << ';' << endl;
}
- s << INDENT << END_ALLOW_THREADS << endl;
+ if (allowThread) {
+ s << INDENT << (generateExceptionHandling
+ ? "threadSaver.restore();" : END_ALLOW_THREADS) << '\n';
+ }
+
+ // Convert result
if (!func->conversionRule(TypeSystem::TargetLangCode, 0).isEmpty()) {
writeConversionRule(s, func, TypeSystem::TargetLangCode, QLatin1String(PYTHON_RETURN_VAR));
} else if (!isCtor && !func->isInplaceOperator() && func->type()
&& !injectedCodeHasReturnValueAttribution(func, TypeSystem::TargetLangCode)) {
- s << INDENT << PYTHON_RETURN_VAR " = ";
+ s << INDENT << PYTHON_RETURN_VAR << " = ";
if (isObjectTypeUsedAsValueType(func->type())) {
s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(func->type()->typeEntry())
<< "), " << CPP_RETURN_VAR << ", true, true)";
@@ -3319,6 +3412,13 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
}
s << ';' << endl;
}
+
+ if (generateExceptionHandling) { // "catch" code
+ --INDENT.indent;
+ const QStringList handlingCode = defaultExceptionHandling();
+ for (const auto &line : handlingCode)
+ s << INDENT << line << '\n';
+ }
}
}
@@ -3370,7 +3470,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
s << "getOwnership(" << pyArgName << ");";
} else if (wrappedClass->hasVirtualDestructor()) {
if (arg_mod.index == 0)
- s << "releaseOwnership(" PYTHON_RETURN_VAR ");";
+ s << "releaseOwnership(" << PYTHON_RETURN_VAR << ");";
else
s << "releaseOwnership(" << pyArgName << ");";
} else {
@@ -3406,10 +3506,10 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
else
s << INDENT << "Shiboken::Object::removeReference(";
- s << "reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
+ s << "reinterpret_cast<SbkObject*>(self), \"";
QString varName = arg_mod.referenceCounts.constFirst().varName;
if (varName.isEmpty())
- varName = func->minimalSignature() + QString().number(arg_mod.index);
+ varName = func->minimalSignature() + QString::number(arg_mod.index);
s << varName << "\", " << pyArgName
<< (refCount.action == ReferenceCount::Add ? ", true" : "")
@@ -3531,7 +3631,7 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn
const FlagsTypeEntry* flags = 0;
if (enumType->isFlags())
- flags = reinterpret_cast<const FlagsTypeEntry*>(enumType);
+ flags = static_cast<const FlagsTypeEntry*>(enumType);
s << INDENT << "// Register converter for " << enumFlagName << " '" << enumType->qualifiedCppName() << "'." << endl;
s << INDENT << '{' << endl;
@@ -3575,7 +3675,7 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn
s << INDENT << '}' << endl;
if (!flags)
- writeEnumConverterInitialization(s, reinterpret_cast<const EnumTypeEntry*>(enumType)->flags());
+ writeEnumConverterInitialization(s, static_cast<const EnumTypeEntry*>(enumType)->flags());
}
void CppGenerator::writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type)
@@ -3656,10 +3756,7 @@ bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClass* metaClass)
}
const ComplexTypeEntry* baseType = metaClass->typeEntry()->baseContainerType();
- if (baseType && baseType->isContainer())
- return true;
-
- return false;
+ return baseType && baseType->isContainer();
}
bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass* metaClass)
@@ -3872,7 +3969,7 @@ void CppGenerator::writeMappingMethods(QTextStream &s,
CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl;
- writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ writeInvalidPyObjectCheck(s, QLatin1String("self"));
writeCppSelfDefinition(s, func, context);
@@ -3899,7 +3996,7 @@ void CppGenerator::writeSequenceMethods(QTextStream &s,
CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl;
- writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ writeInvalidPyObjectCheck(s, QLatin1String("self"));
writeCppSelfDefinition(s, func, context);
@@ -3964,7 +4061,6 @@ void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMe
funcs.insert(QLatin1String("__msetitem__"), QString());
}
- QString baseName = cpythonBaseName(metaClass);
for (auto it = m_mpFuncs.cbegin(), end = m_mpFuncs.cend(); it != end; ++it) {
const QString &mpName = it.key();
if (funcs[mpName].isEmpty())
@@ -4015,7 +4111,8 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet
QString baseName = cpythonBaseName(metaClass);
- nb[QLatin1String("bool")] = hasBoolCast(metaClass) ? baseName + QLatin1String("___nb_bool") : QString();
+ if (hasBoolCast(metaClass))
+ nb.insert(QLatin1String("bool"), baseName + QLatin1String("___nb_bool"));
for (QHash<QString, QString>::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) {
const QString &nbName = it.key();
@@ -4054,9 +4151,9 @@ void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaCla
{
QString baseName = cpythonBaseName(metaClass);
s << "static int ";
- s << baseName << "_traverse(PyObject* " PYTHON_SELF_VAR ", visitproc visit, void* arg)" << endl;
+ s << baseName << "_traverse(PyObject* self, visitproc visit, void* arg)" << endl;
s << '{' << endl;
- s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_traverse(self, visit, arg);" << endl;
s << '}' << endl;
}
@@ -4064,9 +4161,9 @@ void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass*
{
QString baseName = cpythonBaseName(metaClass);
s << "static int ";
- s << baseName << "_clear(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << baseName << "_clear(PyObject* self)" << endl;
s << '{' << endl;
- s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_clear(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_clear(self);" << endl;
s << '}' << endl;
}
@@ -4074,7 +4171,7 @@ void CppGenerator::writeCopyFunction(QTextStream &s, GeneratorContext &context)
{
const AbstractMetaClass *metaClass = context.metaClass();
const QString className = chopType(cpythonTypeName(metaClass));
- s << "static PyObject* " << className << "___copy__(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "static PyObject* " << className << "___copy__(PyObject* self)" << endl;
s << "{" << endl;
writeCppSelfDefinition(s, context, false, true);
QString conversionCode;
@@ -4084,9 +4181,9 @@ void CppGenerator::writeCopyFunction(QTextStream &s, GeneratorContext &context)
conversionCode = cpythonToPythonConversionFunction(context.preciseType());
s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << conversionCode;
- s << CPP_SELF_VAR ");" << endl;
+ s << CPP_SELF_VAR << ");" << endl;
writeFunctionReturnErrorCheckSection(s);
- s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl;
+ s << INDENT << "return " << PYTHON_RETURN_VAR << ";" << endl;
s << "}" << endl;
s << endl;
}
@@ -4096,7 +4193,7 @@ void CppGenerator::writeGetterFunction(QTextStream &s,
GeneratorContext &context)
{
ErrorCode errorCode(0);
- s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", void*)" << endl;
+ s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* self, void*)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
@@ -4161,7 +4258,7 @@ void CppGenerator::writeGetterFunction(QTextStream &s,
s << INDENT << "pyOut = ";
s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(fieldType)
<< "), " << cppField << ", false, true);" << endl;
- s << INDENT << "Shiboken::Object::setParent(" PYTHON_SELF_VAR ", pyOut)";
+ s << INDENT << "Shiboken::Object::setParent(self, pyOut)";
} else {
s << INDENT << "pyOut = ";
writeToPythonConversion(s, fieldType, metaField->enclosingClass(), cppField);
@@ -4177,7 +4274,7 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
GeneratorContext &context)
{
ErrorCode errorCode(0);
- s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* pyIn, void*)" << endl;
+ s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* self, PyObject* pyIn, void*)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
@@ -4193,7 +4290,7 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
AbstractMetaType* fieldType = metaField->type();
- s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << "{nullptr};" << endl;
s << INDENT << "if (!";
writeTypeCheck(s, fieldType, QLatin1String("pyIn"), isNumber(fieldType->typeEntry()));
s << ") {" << endl;
@@ -4219,6 +4316,8 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);" << endl;
s << INDENT << cppField << " = cppOut_local";
} else {
+ if (isPointerToConst(fieldType))
+ s << "const ";
s << getFullTypeNameWithoutModifiers(fieldType);
s << QString::fromLatin1("*").repeated(fieldType->indirections()) << "& cppOut_ptr = ";
s << cppField << ';' << endl;
@@ -4227,7 +4326,7 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
s << ';' << endl << endl;
if (isPointerToWrapperType(fieldType)) {
- s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
+ s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(self), \"";
s << metaField->name() << "\", pyIn);" << endl;
}
@@ -4240,12 +4339,12 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co
const AbstractMetaClass *metaClass = context.metaClass();
QString baseName = cpythonBaseName(metaClass);
s << "static PyObject* ";
- s << baseName << "_richcompare(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ", int op)" << endl;
+ s << baseName << "_richcompare(PyObject* self, PyObject* " << PYTHON_ARG << ", int op)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context, false, true);
writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
- s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
- s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR << ';' << endl;
+ s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = 0;" << endl;
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
s << endl;
@@ -4302,15 +4401,17 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co
CodeSnipList snips = func->injectedCodeSnips();
writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, func->arguments().constLast());
} else {
- QString expression = QString::fromLatin1("%1%2 %3 (%4" CPP_ARG0 ")")
- .arg(func->isPointerOperator() ? QLatin1String("&") : QString(),
- QLatin1String(CPP_SELF_VAR), op,
- shouldDereferenceAbstractMetaTypePointer(argType) ? QLatin1String("*") : QString());
s << INDENT;
if (func->type())
- s << func->type()->cppSignature() << " " CPP_RETURN_VAR " = ";
- s << expression << ';' << endl;
- s << INDENT << PYTHON_RETURN_VAR " = ";
+ s << func->type()->cppSignature() << " " << CPP_RETURN_VAR << " = ";
+ // expression
+ if (func->isPointerOperator())
+ s << '&';
+ s << CPP_SELF_VAR << ' ' << op << '(';
+ if (shouldDereferenceAbstractMetaTypePointer(argType))
+ s << '*';
+ s << CPP_ARG0 << ");" << endl;
+ s << INDENT << PYTHON_RETURN_VAR << " = ";
if (func->type())
writeToPythonConversion(s, func->type(), metaClass, QLatin1String(CPP_RETURN_VAR));
else
@@ -4324,9 +4425,9 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co
s << " else {" << endl;
if (operatorId == QLatin1String("Py_EQ") || operatorId == QLatin1String("Py_NE")) {
Indentation indent(INDENT);
- s << INDENT << PYTHON_RETURN_VAR " = "
+ s << INDENT << PYTHON_RETURN_VAR << " = "
<< (operatorId == QLatin1String("Py_EQ") ? "Py_False" : "Py_True") << ';' << endl;
- s << INDENT << "Py_INCREF(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "Py_INCREF(" << PYTHON_RETURN_VAR << ");" << endl;
} else {
Indentation indent(INDENT);
s << INDENT << "goto " << baseName << "_RichComparison_TypeError;" << endl;
@@ -4343,18 +4444,18 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co
}
s << INDENT << '}' << endl << endl;
- s << INDENT << "if (" PYTHON_RETURN_VAR " && !PyErr_Occurred())" << endl;
+ s << INDENT << "if (" << PYTHON_RETURN_VAR << " && !PyErr_Occurred())" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl;
+ s << INDENT << "return " << PYTHON_RETURN_VAR << ";" << endl;
}
s << INDENT << baseName << "_RichComparison_TypeError:" << endl;
s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"operator not implemented.\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl << endl;
s << '}' << endl << endl;
}
-void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads)
+void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList &overloads)
{
Q_ASSERT(!overloads.isEmpty());
OverloadData overloadData(overloads, this);
@@ -4378,7 +4479,7 @@ void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMeta
s << "|METH_STATIC";
}
-void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads)
+void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList &overloads)
{
Q_ASSERT(!overloads.isEmpty());
const AbstractMetaFunction* func = overloads.constFirst();
@@ -4510,7 +4611,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
s << INDENT << "if (!" << cpythonTypeNameExt(cppEnum->typeEntry()) << ')' << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl << endl;
}
}
@@ -4543,7 +4644,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
<< "))->tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << "Py_DECREF(anonEnumItem);" << endl;
}
@@ -4553,7 +4654,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
s << enumValueText << ") < 0)" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
}
break;
@@ -4564,7 +4665,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
Indentation indent(INDENT);
s << INDENT << enclosingObjectVariable << ", \"" << enumValue->name() << "\", ";
s << enumValueText << "))" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
break;
case EnumClass: {
@@ -4573,7 +4674,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
Indentation indent(INDENT);
s << INDENT << enumVarTypeObj<< ", \"" << enumValue->name() << "\", "
<< enumValueText << "))" << endl
- << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ << INDENT << returnStatement(m_currentErrorCode) << endl;
}
break;
}
@@ -4618,11 +4719,11 @@ void CppGenerator::writeFlagsToLong(QTextStream& s, const AbstractMetaEnum* cppE
FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
if (!flagsEntry)
return;
- s << "static PyObject* " << cpythonEnumName(cppEnum) << "_long(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "static PyObject* " << cpythonEnumName(cppEnum) << "_long(PyObject* self)" << endl;
s << "{" << endl;
s << INDENT << "int val;" << endl;
AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl;
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &val);" << endl;
s << INDENT << "return Shiboken::Conversions::copyToPython(Shiboken::Conversions::PrimitiveTypeConverter<int>(), &val);" << endl;
s << "}" << endl;
}
@@ -4632,12 +4733,12 @@ void CppGenerator::writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cpp
FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
if (!flagsEntry)
return;
- s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject* self)" << endl;
s << "{" << endl;
s << INDENT << "int val;" << endl;
AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl;
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &val);" << endl;
s << INDENT << "return val != 0;" << endl;
s << "}" << endl;
}
@@ -4679,24 +4780,24 @@ void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const Abstr
}
void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
- QString pyOpName, QString cppOpName)
+ const QString &pyOpName, const QString &cppOpName)
{
FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
Q_ASSERT(flagsEntry);
- s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl;
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* self, PyObject* " << PYTHON_ARG << ")" << endl;
s << '{' << endl;
AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << "::" << flagsEntry->originalName() << " cppResult, " CPP_SELF_VAR ", cppArg;" << endl;
+ s << INDENT << "::" << flagsEntry->originalName() << " cppResult, " << CPP_SELF_VAR << ", cppArg;" << endl;
s << "#ifdef IS_PY3K" << endl;
- s << INDENT << CPP_SELF_VAR " = (::" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" PYTHON_SELF_VAR ");" << endl;
- s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" PYTHON_ARG ");" << endl;
+ s << INDENT << CPP_SELF_VAR << " = (::" << flagsEntry->originalName() << ")(int)PyLong_AsLong(self);" << endl;
+ s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" << PYTHON_ARG << ");" << endl;
s << "#else" << endl;
- s << INDENT << CPP_SELF_VAR " = (::" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" PYTHON_SELF_VAR ");" << endl;
- s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" PYTHON_ARG ");" << endl;
+ s << INDENT << CPP_SELF_VAR << " = (::" << flagsEntry->originalName() << ")(int)PyInt_AsLong(self);" << endl;
+ s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" << PYTHON_ARG << ");" << endl;
s << "#endif" << endl << endl;
- s << INDENT << "cppResult = " CPP_SELF_VAR " " << cppOpName << " cppArg;" << endl;
+ s << INDENT << "cppResult = " << CPP_SELF_VAR << " " << cppOpName << " cppArg;" << endl;
s << INDENT << "return ";
writeToPythonConversion(s, flagsType, 0, QLatin1String("cppResult"));
s << ';' << endl;
@@ -4704,23 +4805,24 @@ void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEn
}
void CppGenerator::writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
- QString pyOpName, QString cppOpName, bool boolResult)
+ const QString &pyOpName,
+ const QString &cppOpName, bool boolResult)
{
FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
Q_ASSERT(flagsEntry);
- s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl;
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* self, PyObject* " << PYTHON_ARG << ")" << endl;
s << '{' << endl;
AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << "::" << flagsEntry->originalName() << " " CPP_SELF_VAR ";" << endl;
- s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &" CPP_SELF_VAR ");" << endl;
+ s << INDENT << "::" << flagsEntry->originalName() << " " << CPP_SELF_VAR << ";" << endl;
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &" << CPP_SELF_VAR << ");" << endl;
s << INDENT;
if (boolResult)
s << "bool";
else
s << "::" << flagsEntry->originalName();
- s << " cppResult = " << cppOpName << CPP_SELF_VAR ";" << endl;
+ s << " cppResult = " << cppOpName << CPP_SELF_VAR << ';' << endl;
s << INDENT << "return ";
if (boolResult)
s << "PyBool_FromLong(cppResult)";
@@ -4846,8 +4948,16 @@ void CppGenerator::writeClassRegister(QTextStream &s,
else
s << INDENT << "0," << endl;
- // 9:isInnerClass
- s << INDENT << (hasEnclosingClass ? "true" : "false") << endl;
+ // 9:wrapperflags
+ QByteArrayList wrapperFlags;
+ if (hasEnclosingClass)
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::InnerClass"));
+ if (metaClass->deleteInMainThread())
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::DeleteInMainThread"));
+ if (wrapperFlags.isEmpty())
+ s << INDENT << '0';
+ else
+ s << INDENT << wrapperFlags.join(" | ");
}
s << INDENT << ");" << endl;
s << INDENT << endl;
@@ -5042,25 +5152,27 @@ void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMeta
s << "}\n\n";
}
-QString CppGenerator::writeSmartPointerGetterCast() {
- return QLatin1String("const_cast<char *>(" SMART_POINTER_GETTER ")");
+QString CppGenerator::writeSmartPointerGetterCast()
+{
+ return QLatin1String("const_cast<char *>(")
+ + QLatin1String(SMART_POINTER_GETTER) + QLatin1Char(')');
}
void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &context)
{
const AbstractMetaClass* metaClass = context.metaClass();
- s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name, PyObject* value)" << endl;
+ s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* self, PyObject* name, PyObject* value)" << endl;
s << '{' << endl;
if (usePySideExtensions()) {
- s << INDENT << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject*>(PySide::Property::getObject(" PYTHON_SELF_VAR ", name)));" << endl;
+ s << INDENT << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject*>(PySide::Property::getObject(self, name)));" << endl;
s << INDENT << "if (!pp.isNull())" << endl;
Indentation indent(INDENT);
- s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty*>(pp.object()), " PYTHON_SELF_VAR ", value);" << endl;
+ s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty*>(pp.object()), self, value);" << endl;
}
if (context.forSmartPointer()) {
s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for the corresponding C++ object held by the smart pointer." << endl;
- s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", "
+ s << INDENT << "PyObject *rawObj = PyObject_CallMethod(self, "
<< writeSmartPointerGetterCast() << ", 0);" << endl;
s << INDENT << "if (rawObj) {" << endl;
{
@@ -5078,7 +5190,7 @@ void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &conte
}
- s << INDENT << "return PyObject_GenericSetAttr(" PYTHON_SELF_VAR ", name, value);" << endl;
+ s << INDENT << "return PyObject_GenericSetAttr(self, name, value);" << endl;
s << '}' << endl;
}
@@ -5088,27 +5200,29 @@ static inline QString qMetaObjectClassName() { return QStringLiteral("QMetaObjec
void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &context)
{
const AbstractMetaClass* metaClass = context.metaClass();
- s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name)" << endl;
+ s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* self, PyObject* name)" << endl;
s << '{' << endl;
QString getattrFunc;
if (usePySideExtensions() && metaClass->isQObject()) {
AbstractMetaClass *qobjectClass = AbstractMetaClass::findClass(classes(), qObjectClassName());
- getattrFunc = QString::fromLatin1("PySide::getMetaDataFromQObject(%1, " PYTHON_SELF_VAR ", name)")
- .arg(cpythonWrapperCPtr(qobjectClass, QLatin1String(PYTHON_SELF_VAR)));
+ QTextStream(&getattrFunc) << "PySide::getMetaDataFromQObject("
+ << cpythonWrapperCPtr(qobjectClass, QLatin1String("self"))
+ << ", self, name)";
} else {
- getattrFunc = QLatin1String("PyObject_GenericGetAttr(" PYTHON_SELF_VAR ", name)");
+ getattrFunc = QLatin1String("PyObject_GenericGetAttr(") + QLatin1String("self")
+ + QLatin1String(", name)");
}
if (classNeedsGetattroFunction(metaClass)) {
- s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl;
+ s << INDENT << "if (self) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "// Search the method in the instance dict" << endl;
- s << INDENT << "if (reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")->ob_dict) {" << endl;
+ s << INDENT << "if (reinterpret_cast<SbkObject*>(self)->ob_dict) {" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "PyObject* meth = PyDict_GetItem(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")->ob_dict, name);" << endl;
+ s << INDENT << "PyObject* meth = PyDict_GetItem(reinterpret_cast<SbkObject*>(self)->ob_dict, name);" << endl;
s << INDENT << "if (meth) {" << endl;
{
Indentation indent(INDENT);
@@ -5119,16 +5233,16 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte
}
s << INDENT << '}' << endl;
s << INDENT << "// Search the method in the type dict" << endl;
- s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ")) {" << endl;
+ s << INDENT << "if (Shiboken::Object::isUserType(self)) {" << endl;
{
Indentation indent(INDENT);
// PYSIDE-772: Perform optimized name mangling.
- s << INDENT << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(" PYTHON_SELF_VAR ", name));" << endl;
- s << INDENT << "PyObject *meth = PyDict_GetItem(Py_TYPE(" PYTHON_SELF_VAR ")->tp_dict, tmp);" << endl;
+ s << INDENT << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(self, name));" << endl;
+ s << INDENT << "PyObject *meth = PyDict_GetItem(Py_TYPE(self)->tp_dict, tmp);" << endl;
s << INDENT << "if (meth)" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return PyFunction_Check(meth) ? SBK_PyMethod_New(meth, " PYTHON_SELF_VAR ") : " << getattrFunc << ';' << endl;
+ s << INDENT << "return PyFunction_Check(meth) ? SBK_PyMethod_New(meth, self) : " << getattrFunc << ';' << endl;
}
}
s << INDENT << '}' << endl;
@@ -5147,7 +5261,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte
s << INDENT << "};" << endl;
s << INDENT << "if (Shiboken::String::compare(name, \"" << func->name() << "\") == 0)" << endl;
Indentation indent(INDENT);
- s << INDENT << "return PyCFunction_NewEx(&non_static_" << defName << ", " PYTHON_SELF_VAR ", 0);" << endl;
+ s << INDENT << "return PyCFunction_NewEx(&non_static_" << defName << ", self, 0);" << endl;
}
}
s << INDENT << '}' << endl;
@@ -5168,7 +5282,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte
s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for "
"the corresponding C++ object held by the smart pointer." << endl;
- s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", "
+ s << INDENT << "PyObject *rawObj = PyObject_CallMethod(self, "
<< writeSmartPointerGetterCast() << ", 0);" << endl;
s << INDENT << "if (rawObj) {" << endl;
{
@@ -5289,15 +5403,11 @@ bool CppGenerator::finishGeneration()
QString moduleFileName(outputDirectory() + QLatin1Char('/') + subDirectoryForPackage(packageName()));
moduleFileName += QLatin1Char('/') + moduleName().toLower() + QLatin1String("_module_wrapper.cpp");
- QFile file(moduleFileName);
- verifyDirectoryFor(file);
- if (!file.open(QFile::WriteOnly)) {
- qCWarning(lcShiboken).noquote().nospace()
- << "Error writing file: " << QDir::toNativeSeparators(moduleFileName);
- return false;
- }
- QTextStream s(&file);
+ verifyDirectoryFor(moduleFileName);
+ FileOut file(moduleFileName);
+
+ QTextStream &s = file.stream;
// write license comment
s << licenseComment() << endl;
@@ -5328,13 +5438,12 @@ bool CppGenerator::finishGeneration()
}
TypeDatabase* typeDb = TypeDatabase::instance();
- TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(typeDb->findType(packageName()));
+ const TypeSystemTypeEntry *moduleEntry = typeDb->findTypeSystemType(packageName());
+ Q_ASSERT(moduleEntry);
//Extra includes
s << endl << "// Extra includes" << endl;
- QVector<Include> extraIncludes;
- if (moduleEntry)
- extraIncludes = moduleEntry->extraIncludes();
+ QVector<Include> extraIncludes = moduleEntry->extraIncludes();
for (AbstractMetaEnum *cppEnum : qAsConst(globalEnums))
extraIncludes.append(cppEnum->typeEntry()->extraIncludes());
qSort(extraIncludes.begin(), extraIncludes.end());
@@ -5343,14 +5452,15 @@ bool CppGenerator::finishGeneration()
s << endl;
s << "// Current module's type array." << endl;
- s << "PyTypeObject** " << cppApiVariableName() << ';' << endl;
+ s << "PyTypeObject** " << cppApiVariableName() << " = nullptr;" << endl;
+
+ s << "// Current module's PyObject pointer." << endl;
+ s << "PyObject* " << pythonModuleObjectName() << " = nullptr;" << endl;
s << "// Current module's converter array." << endl;
- s << "SbkConverter** " << convertersVariableName() << ';' << endl;
+ s << "SbkConverter** " << convertersVariableName() << " = nullptr;" << endl;
- CodeSnipList snips;
- if (moduleEntry)
- snips = moduleEntry->codeSnips();
+ const CodeSnipList snips = moduleEntry->codeSnips();
// module inject-code native/beginning
if (!snips.isEmpty()) {
@@ -5519,6 +5629,9 @@ bool CppGenerator::finishGeneration()
s << moduleName() << "_methods);" << endl;
s << "#endif" << endl << endl;
+ s << INDENT << "// Make module available from global scope" << endl;
+ s << INDENT << pythonModuleObjectName() << " = module;" << endl << endl;
+
//s << INDENT << "// Initialize converters for primitive types." << endl;
//s << INDENT << "initConverters();" << endl << endl;
@@ -5619,7 +5732,7 @@ bool CppGenerator::finishGeneration()
s << "SBK_MODULE_INIT_FUNCTION_END" << endl;
- return true;
+ return file.done() != FileOut::Failure;
}
static ArgumentOwner getArgumentOwner(const AbstractMetaFunction* func, int argIndex)
@@ -5663,22 +5776,20 @@ bool CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMeta
if (parentIndex == 0) {
parentVariable = QLatin1String(PYTHON_RETURN_VAR);
} else if (parentIndex == -1) {
- parentVariable = QLatin1String(PYTHON_SELF_VAR);
+ parentVariable = QLatin1String("self");
} else {
parentVariable = usePyArgs
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(parentIndex - 1)
- : QLatin1String(PYTHON_ARG);
+ ? pythonArgsAt(parentIndex - 1) : QLatin1String(PYTHON_ARG);
}
}
if (childIndex == 0) {
childVariable = QLatin1String(PYTHON_RETURN_VAR);
} else if (childIndex == -1) {
- childVariable = QLatin1String(PYTHON_SELF_VAR);
+ childVariable = QLatin1String("self");
} else {
childVariable = usePyArgs
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(childIndex - 1)
- : QLatin1String(PYTHON_ARG);
+ ? pythonArgsAt(childIndex - 1) : QLatin1String(PYTHON_ARG);
}
s << INDENT << "Shiboken::Object::setParent(" << parentVariable << ", " << childVariable << ");\n";
@@ -5717,7 +5828,7 @@ void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMeta
ArgumentOwner argOwner = getArgumentOwner(func, ArgumentOwner::ReturnIndex);
if (argOwner.action == ArgumentOwner::Invalid || argOwner.index != ArgumentOwner::ThisIndex) {
if (isPointerToWrapperType(type))
- s << INDENT << "Shiboken::Object::setParent(" << self << ", " PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "Shiboken::Object::setParent(self, " << PYTHON_RETURN_VAR << ");" << endl;
}
}
@@ -5737,19 +5848,19 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &
ErrorCode errorCode(0);
// __len__
- s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* self)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
- s << INDENT << "return " CPP_SELF_VAR "->size();" << endl;
+ s << INDENT << "return " << CPP_SELF_VAR << "->size();" << endl;
s << '}' << endl;
// __getitem__
- s << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i)" << endl;
+ s << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__(PyObject* self, Py_ssize_t _i)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
writeIndexError(s, QLatin1String("index out of bounds"));
- s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl;
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " << CPP_SELF_VAR << "->begin();" << endl;
s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;" << endl;
const AbstractMetaType* itemType = metaClass->templateBaseClassInstantiations().constFirst();
@@ -5761,7 +5872,7 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &
// __setitem__
ErrorCode errorCode2(-1);
- s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* pyArg)" << endl;
+ s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* self, Py_ssize_t _i, PyObject* pyArg)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
writeIndexError(s, QLatin1String("list assignment index out of range"));
@@ -5779,7 +5890,7 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &
s << INDENT << '}' << endl;
writeArgumentConversion(s, itemType, QLatin1String("cppValue"), QLatin1String("pyArg"), metaClass);
- s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl;
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " << CPP_SELF_VAR << "->begin();" << endl;
s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;" << endl;
s << INDENT << "*_item = cppValue;" << endl;
s << INDENT << "return 0;" << endl;
@@ -5787,11 +5898,11 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &
}
void CppGenerator::writeIndexError(QTextStream& s, const QString& errorMsg)
{
- s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) " CPP_SELF_VAR "->size()) {" << endl;
+ s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) " << CPP_SELF_VAR << "->size()) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_IndexError, \"" << errorMsg << "\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}' << endl;
}
@@ -5808,7 +5919,10 @@ QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &contex
s << INDENT << "QBuffer buffer;" << endl;
s << INDENT << "buffer.open(QBuffer::ReadWrite);" << endl;
s << INDENT << "QDebug dbg(&buffer);" << endl;
- s << INDENT << "dbg << " << (metaClass->typeEntry()->isValue() ? "*" : "") << CPP_SELF_VAR ";" << endl;
+ s << INDENT << "dbg << ";
+ if (metaClass->typeEntry()->isValue())
+ s << '*';
+ s << CPP_SELF_VAR << ';' << endl;
s << INDENT << "buffer.close();" << endl;
s << INDENT << "QByteArray str = buffer.data();" << endl;
s << INDENT << "int idx = str.indexOf('(');" << endl;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
index 1b59bcda7..55a1c265d 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.h
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -234,8 +234,8 @@ private:
void writeClassDefinition(QTextStream &s,
const AbstractMetaClass *metaClass,
GeneratorContext &classContext);
- void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads);
- void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads);
+ void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList &overloads);
+ void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList &overloads);
void writeSignatureInfo(QTextStream &s, const AbstractMetaFunctionList &overloads);
/// Writes the implementation of all methods part of python sequence protocol
void writeSequenceMethods(QTextStream &s,
@@ -275,9 +275,10 @@ private:
void writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cppEnum);
void writeFlagsNumberMethodsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum);
void writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
- QString pyOpName, QString cppOpName);
+ const QString &pyOpName, const QString &cppOpName);
void writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
- QString pyOpName, QString cppOpName, bool boolResult = false);
+ const QString &pyOpName, const QString &cppOpName,
+ bool boolResult = false);
/// Writes the function that registers the multiple inheritance information for the classes that need it.
void writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass);
@@ -292,7 +293,7 @@ private:
void writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool userHeuristicForReturn);
bool writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool userHeuristicPolicy);
- void writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self = QLatin1String(PYTHON_SELF_VAR));
+ void writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self = QLatin1String("self"));
void writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const;
/**
@@ -327,7 +328,9 @@ private:
QString writeReprFunction(QTextStream &s, GeneratorContext &context);
- bool hasBoolCast(const AbstractMetaClass* metaClass) const;
+ const AbstractMetaFunction *boolCast(const AbstractMetaClass* metaClass) const;
+ bool hasBoolCast(const AbstractMetaClass* metaClass) const
+ { return boolCast(metaClass) != nullptr; }
// Number protocol structure members names.
static QHash<QString, QString> m_nbFuncs;
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
index 8fde3cd31..8881d71f4 100644
--- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
@@ -32,6 +32,8 @@
#include <reporthandler.h>
#include <fileout.h>
+#include <algorithm>
+
#include <QtCore/QDir>
#include <QtCore/QTextStream>
#include <QtCore/QVariant>
@@ -49,11 +51,10 @@ QString HeaderGenerator::fileNameForContext(GeneratorContext &context) const
QString fileNameBase = metaClass->qualifiedCppName().toLower();
fileNameBase.replace(QLatin1String("::"), QLatin1String("_"));
return fileNameBase + fileNameSuffix();
- } else {
- const AbstractMetaType *smartPointerType = context.preciseType();
- QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
- return fileNameBase + fileNameSuffix();
}
+ const AbstractMetaType *smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
+ return fileNameBase + fileNameSuffix();
}
void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const
@@ -116,8 +117,6 @@ void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classConte
if (!avoidProtectedHack())
s << "#define protected public" << endl << endl;
- s << "#include <shiboken.h>" << endl << endl;
-
//Includes
s << metaClass->typeEntry()->include() << endl;
@@ -173,7 +172,7 @@ void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classConte
s << INDENT << "void* qt_metacast(const char* _clname) override;" << endl;
}
- if (m_inheritedOverloads.size()) {
+ if (!m_inheritedOverloads.isEmpty()) {
s << INDENT << "// Inherited overloads, because the using keyword sux" << endl;
writeInheritedOverloads(s);
m_inheritedOverloads.clear();
@@ -230,7 +229,7 @@ void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction*
QString argName = arg->name();
const TypeEntry* enumTypeEntry = 0;
if (arg->type()->isFlags())
- enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
+ enumTypeEntry = static_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
else if (arg->type()->isEnum())
enumTypeEntry = arg->type()->typeEntry();
if (enumTypeEntry)
@@ -284,49 +283,86 @@ void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction*
}
}
-static void _writeTypeIndexDefineLine(QTextStream& s, const QString& variableName, int typeIndex)
+static void _writeTypeIndexValue(QTextStream& s, const QString& variableName,
+ int typeIndex)
{
- s << "#define ";
- s.setFieldWidth(60);
+ s << " ";
+ s.setFieldWidth(56);
s << variableName;
s.setFieldWidth(0);
- s << ' ' << typeIndex << endl;
+ s << " = " << typeIndex;
+}
+
+static inline void _writeTypeIndexValueLine(QTextStream& s,
+ const QString& variableName,
+ int typeIndex)
+{
+ _writeTypeIndexValue(s, variableName, typeIndex);
+ s << ",\n";
}
-void HeaderGenerator::writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry)
+
+void HeaderGenerator::writeTypeIndexValueLine(QTextStream& s, const TypeEntry* typeEntry)
{
if (!typeEntry || !typeEntry->generateCode())
return;
s.setFieldAlignment(QTextStream::AlignLeft);
- int typeIndex = getTypeIndex(typeEntry);
- _writeTypeIndexDefineLine(s, getTypeIndexVariableName(typeEntry), typeIndex);
+ const int typeIndex = typeEntry->sbkIndex();
+ _writeTypeIndexValueLine(s, getTypeIndexVariableName(typeEntry), typeIndex);
if (typeEntry->isComplex()) {
- const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(typeEntry);
+ const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(typeEntry);
if (cType->baseContainerType()) {
const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), cType);
if (metaClass->templateBaseClass())
- _writeTypeIndexDefineLine(s, getTypeIndexVariableName(metaClass, true), typeIndex);
+ _writeTypeIndexValueLine(s, getTypeIndexVariableName(metaClass, true), typeIndex);
}
}
if (typeEntry->isEnum()) {
- const EnumTypeEntry* ete = reinterpret_cast<const EnumTypeEntry*>(typeEntry);
+ const EnumTypeEntry* ete = static_cast<const EnumTypeEntry*>(typeEntry);
if (ete->flags())
- writeTypeIndexDefineLine(s, ete->flags());
+ writeTypeIndexValueLine(s, ete->flags());
}
}
-void HeaderGenerator::writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass)
+void HeaderGenerator::writeTypeIndexValueLines(QTextStream& s, const AbstractMetaClass* metaClass)
{
if (!metaClass->typeEntry()->generateCode())
return;
- writeTypeIndexDefineLine(s, metaClass->typeEntry());
+ writeTypeIndexValueLine(s, metaClass->typeEntry());
const AbstractMetaEnumList &enums = metaClass->enums();
for (const AbstractMetaEnum *metaEnum : enums) {
if (metaEnum->isPrivate())
continue;
- writeTypeIndexDefineLine(s, metaEnum->typeEntry());
+ writeTypeIndexValueLine(s, metaEnum->typeEntry());
}
}
+// Format the typedefs for the typedef entries to be generated
+static void formatTypeDefEntries(QTextStream &s)
+{
+ QVector<const TypedefEntry *> 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 = name.splitRef(QLatin1String("::"));
+ const int nameSpaceCount = components.size() - 1;
+ for (int n = 0; n < nameSpaceCount; ++n)
+ s << "namespace " << components.at(n) << " {\n";
+ s << "using " << components.constLast() << " = " << e->sourceType() << ";\n";
+ for (int n = 0; n < nameSpaceCount; ++n)
+ s << "}\n";
+ }
+ s << '\n';
+}
+
+
bool HeaderGenerator::finishGeneration()
{
// Generate the main header for this module.
@@ -342,47 +378,49 @@ bool HeaderGenerator::finishGeneration()
Indentation indent(INDENT);
- macrosStream << "// Type indices" << endl;
+ macrosStream << "// Type indices\nenum : int {\n";
AbstractMetaEnumList globalEnums = this->globalEnums();
- const AbstractMetaClassList &classList = classes();
+ AbstractMetaClassList classList = classes();
+
+ std::sort(classList.begin(), classList.end(), [](AbstractMetaClass *a, AbstractMetaClass* b) {
+ return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
+ });
+
for (const AbstractMetaClass *metaClass : classList) {
- writeTypeIndexDefine(macrosStream, metaClass);
+ writeTypeIndexValueLines(macrosStream, metaClass);
lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
}
for (const AbstractMetaEnum *metaEnum : qAsConst(globalEnums))
- writeTypeIndexDefineLine(macrosStream, metaEnum->typeEntry());
+ writeTypeIndexValueLine(macrosStream, metaEnum->typeEntry());
// Write the smart pointer define indexes.
int smartPointerCountIndex = getMaxTypeIndex();
int smartPointerCount = 0;
const QVector<const AbstractMetaType *> &instantiatedSmartPtrs = instantiatedSmartPointers();
for (const AbstractMetaType *metaType : instantiatedSmartPtrs) {
- QString variableName = getTypeIndexVariableName(metaType);
- macrosStream << "#define ";
- macrosStream.setFieldWidth(60);
- macrosStream << variableName;
- macrosStream.setFieldWidth(0);
- macrosStream << ' ' << smartPointerCountIndex << " // " << metaType->cppSignature()
- << endl;
+ _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(metaType),
+ smartPointerCountIndex);
+ macrosStream << ", // " << metaType->cppSignature() << endl;
++smartPointerCountIndex;
++smartPointerCount;
}
+ _writeTypeIndexValue(macrosStream,
+ QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT"),
+ getMaxTypeIndex() + smartPointerCount);
+ macrosStream << "\n};\n";
- macrosStream << "#define ";
- macrosStream.setFieldWidth(60);
- macrosStream << QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT");
- macrosStream.setFieldWidth(0);
- macrosStream << ' ' << getMaxTypeIndex() + smartPointerCount << endl << endl;
macrosStream << "// This variable stores all Python types exported by this module." << endl;
macrosStream << "extern PyTypeObject** " << cppApiVariableName() << ';' << endl << endl;
+ macrosStream << "// This variable stores the Python module object exported by this module." << endl;
+ macrosStream << "extern PyObject* " << pythonModuleObjectName() << ';' << endl << endl;
macrosStream << "// This variable stores all type converters exported by this module." << endl;
macrosStream << "extern SbkConverter** " << convertersVariableName() << ';' << endl << endl;
// TODO-CONVERTER ------------------------------------------------------------------------------
// Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex().
- macrosStream << "// Converter indices" << endl;
+ macrosStream << "// Converter indices\nenum : int {\n";
const PrimitiveTypeEntryList &primitives = primitiveTypes();
int pCount = 0;
for (const PrimitiveTypeEntry *ptype : primitives) {
@@ -393,28 +431,25 @@ bool HeaderGenerator::finishGeneration()
if (!ptype->generateCode() || !ptype->customConversion())
continue;
- _writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(ptype), pCount++);
+ _writeTypeIndexValueLine(macrosStream, getTypeIndexVariableName(ptype), pCount++);
}
const QVector<const AbstractMetaType *> &containers = instantiatedContainers();
for (const AbstractMetaType *container : containers) {
- //_writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(container), pCount);
- // DEBUG
- QString variableName = getTypeIndexVariableName(container);
- macrosStream << "#define ";
- macrosStream.setFieldWidth(60);
- macrosStream << variableName;
- macrosStream.setFieldWidth(0);
- macrosStream << ' ' << pCount << " // " << container->cppSignature() << endl;
- // DEBUG
+ _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(container), pCount);
+ macrosStream << ", // " << container->cppSignature() << endl;
pCount++;
}
// Because on win32 the compiler will not accept a zero length array.
if (pCount == 0)
pCount++;
- _writeTypeIndexDefineLine(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT").arg(moduleName()), pCount);
- macrosStream << endl;
+ _writeTypeIndexValue(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT")
+ .arg(moduleName()), pCount);
+ macrosStream << "\n};\n";
+
+ formatTypeDefEntries(macrosStream);
+
// TODO-CONVERTER ------------------------------------------------------------------------------
macrosStream << "// Macros for type check" << endl;
@@ -474,12 +509,6 @@ bool HeaderGenerator::finishGeneration()
s << "#include <sbkpython.h>" << endl;
s << "#include <sbkconverter.h>" << endl;
- s << "#include <sbkenum.h>" << endl;
- s << "#include <basewrapper.h>" << endl;
- s << "#include <bindingmanager.h>" << endl;
- s << "#include <memory>" << endl << endl;
- if (usePySideExtensions())
- s << "#include <pysidesignal.h>" << endl;
QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports();
if (!requiredTargetImports.isEmpty()) {
@@ -580,7 +609,7 @@ void HeaderGenerator::writeInheritedOverloads(QTextStream& s)
QString argName = arg->name();
const TypeEntry* enumTypeEntry = 0;
if (arg->type()->isFlags())
- enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
+ enumTypeEntry = static_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
else if (arg->type()->isEnum())
enumTypeEntry = arg->type()->typeEntry();
if (enumTypeEntry)
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.h b/sources/shiboken2/generator/shiboken2/headergenerator.h
index acf0448a7..821531aab 100644
--- a/sources/shiboken2/generator/shiboken2/headergenerator.h
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.h
@@ -55,8 +55,8 @@ private:
void writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum);
void writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass);
void writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType);
- void writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry);
- void writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeTypeIndexValueLine(QTextStream& s, const TypeEntry* typeEntry);
+ void writeTypeIndexValueLines(QTextStream& s, const AbstractMetaClass* metaClass);
void writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum);
void writeInheritedOverloads(QTextStream& s);
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
index 73198ba12..a95603754 100644
--- a/sources/shiboken2/generator/shiboken2/overloaddata.cpp
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
@@ -94,8 +94,6 @@ static bool typesAreEqual(const AbstractMetaType* typeA, const AbstractMetaType*
*/
struct OverloadSortData
{
- OverloadSortData() : counter(0) {}
-
/**
* Adds a typeName into the type map without associating it with
* a OverloadData. This is done to express type dependencies that could
@@ -121,7 +119,7 @@ struct OverloadSortData
int lastProcessedItemId() { return counter - 1; }
- int counter;
+ int counter = 0;
QHash<QString, int> map; // typeName -> id
QHash<int, OverloadData*> reverseMap; // id -> OverloadData;
};
@@ -149,11 +147,11 @@ static QString getImplicitConversionTypeName(const AbstractMetaType* containerTy
for (const AbstractMetaType *otherType : instantiations)
types << (otherType == instantiation ? impConv : getTypeName(otherType));
- const ContainerTypeEntry* containerTypeEntry = dynamic_cast<const ContainerTypeEntry*>(containerType->typeEntry());
- return containerTypeEntry->qualifiedCppName() + QLatin1Char('<')
+ return containerType->typeEntry()->qualifiedCppName() + QLatin1Char('<')
+ types.join(QLatin1String(", ")) + QLatin1String(" >");
}
+// overloaddata.cpp
static QString msgCyclicDependency(const QString &funcName, const QString &graphName,
const OverloadData::MetaFunctionList &involvedConversions)
{
@@ -499,7 +497,8 @@ OverloadData::OverloadData(const AbstractMetaFunctionList& overloads, const Shib
OverloadData::OverloadData(OverloadData* headOverloadData, const AbstractMetaFunction* func,
const AbstractMetaType* argType, int argPos)
: m_minArgs(256), m_maxArgs(0), m_argPos(argPos), m_argType(argType),
- m_headOverloadData(headOverloadData), m_previousOverloadData(0)
+ m_headOverloadData(headOverloadData), m_previousOverloadData(nullptr),
+ m_generator(nullptr)
{
if (func)
this->addOverload(func);
@@ -808,8 +807,7 @@ QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList&
{
int minArgs = 10000;
int maxArgs = 0;
- for (int i = 0; i < overloads.size(); i++) {
- const AbstractMetaFunction* func = overloads[i];
+ for (const AbstractMetaFunction *func : overloads) {
int origNumArgs = func->arguments().size();
int removed = numberOfRemovedArguments(func);
int numArgs = origNumArgs - removed;
@@ -825,7 +823,7 @@ QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList&
minArgs = fixedArgIndex;
}
}
- return QPair<int, int>(minArgs, maxArgs);
+ return {minArgs, maxArgs};
}
bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads)
@@ -840,7 +838,7 @@ bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads)
return singleArgument;
}
-void OverloadData::dumpGraph(QString filename) const
+void OverloadData::dumpGraph(const QString &filename) const
{
QFile file(filename);
if (file.open(QFile::WriteOnly)) {
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.h b/sources/shiboken2/generator/shiboken2/overloaddata.h
index 435c19aa2..4759ca9c3 100644
--- a/sources/shiboken2/generator/shiboken2/overloaddata.h
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.h
@@ -114,7 +114,7 @@ public:
/// Returns true if all overloads have no more than one argument.
static bool isSingleArgument(const AbstractMetaFunctionList& overloads);
- void dumpGraph(QString filename) const;
+ void dumpGraph(const QString &filename) const;
QString dumpGraph() const;
bool hasArgumentTypeReplace() const;
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 80096cbf2..b9eea7529 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -28,9 +28,11 @@
#include "shibokengenerator.h"
#include <abstractmetalang.h>
+#include <messages.h>
#include "overloaddata.h"
#include <reporthandler.h>
#include <typedatabase.h>
+#include <abstractmetabuilder.h>
#include <iostream>
#include <QtCore/QDir>
@@ -39,13 +41,29 @@
#include <limits>
#include <memory>
-#define NULL_VALUE "NULL"
-#define AVOID_PROTECTED_HACK "avoid-protected-hack"
-#define PARENT_CTOR_HEURISTIC "enable-parent-ctor-heuristic"
-#define RETURN_VALUE_HEURISTIC "enable-return-value-heuristic"
-#define ENABLE_PYSIDE_EXTENSIONS "enable-pyside-extensions"
-#define DISABLE_VERBOSE_ERROR_MESSAGES "disable-verbose-error-messages"
-#define USE_ISNULL_AS_NB_NONZERO "use-isnull-as-nb_nonzero"
+static const char NULL_VALUE[] = "NULL";
+static const char AVOID_PROTECTED_HACK[] = "avoid-protected-hack";
+static const char PARENT_CTOR_HEURISTIC[] = "enable-parent-ctor-heuristic";
+static const char RETURN_VALUE_HEURISTIC[] = "enable-return-value-heuristic";
+static const char ENABLE_PYSIDE_EXTENSIONS[] = "enable-pyside-extensions";
+static const char DISABLE_VERBOSE_ERROR_MESSAGES[] = "disable-verbose-error-messages";
+static const char USE_ISNULL_AS_NB_NONZERO[] = "use-isnull-as-nb_nonzero";
+
+const char *CPP_ARG = "cppArg";
+const char *CPP_ARG_REMOVED = "removed_cppArg";
+const char *CPP_RETURN_VAR = "cppResult";
+const char *CPP_SELF_VAR = "cppSelf";
+const char *PYTHON_ARG = "pyArg";
+const char *PYTHON_ARGS = "pyArgs";
+const char *PYTHON_OVERRIDE_VAR = "pyOverride";
+const char *PYTHON_RETURN_VAR = "pyResult";
+const char *PYTHON_TO_CPP_VAR = "pythonToCpp";
+const char *SMART_POINTER_GETTER = "kSmartPointerGetter";
+
+const char *CONV_RULE_OUT_VAR_SUFFIX = "_out";
+const char *BEGIN_ALLOW_THREADS =
+ "PyThreadState* _save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS";
+const char *END_ALLOW_THREADS = "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS";
//static void dumpFunction(AbstractMetaFunctionList lst);
@@ -100,7 +118,7 @@ static QString resolveScopePrefix(const AbstractMetaEnum *metaEnum,
return resolveScopePrefix(parts, value);
}
-ShibokenGenerator::ShibokenGenerator() : Generator()
+ShibokenGenerator::ShibokenGenerator()
{
if (m_pythonPrimitiveTypeName.isEmpty())
ShibokenGenerator::initPrimitiveTypesCorrespondences();
@@ -117,17 +135,19 @@ ShibokenGenerator::ShibokenGenerator() : Generator()
m_typeSystemConvName[TypeSystemIsConvertibleFunction] = QLatin1String("isConvertible");
m_typeSystemConvName[TypeSystemToCppFunction] = QLatin1String("toCpp");
m_typeSystemConvName[TypeSystemToPythonFunction] = QLatin1String("toPython");
+
+ const char CHECKTYPE_REGEX[] = R"(%CHECKTYPE\[([^\[]*)\]\()";
+ const char ISCONVERTIBLE_REGEX[] = R"(%ISCONVERTIBLE\[([^\[]*)\]\()";
+ const char CONVERTTOPYTHON_REGEX[] = R"(%CONVERTTOPYTHON\[([^\[]*)\]\()";
+ const char CONVERTTOCPP_REGEX[] =
+ R"((\*?%?[a-zA-Z_][\w\.]*(?:\[[^\[^<^>]+\])*)(?:\s+)=(?:\s+)%CONVERTTOCPP\[([^\[]*)\]\()";
m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegularExpression(QLatin1String(CHECKTYPE_REGEX));
m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegularExpression(QLatin1String(ISCONVERTIBLE_REGEX));
m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegularExpression(QLatin1String(CONVERTTOPYTHON_REGEX));
m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegularExpression(QLatin1String(CONVERTTOCPP_REGEX));
}
-ShibokenGenerator::~ShibokenGenerator()
-{
- // TODO-CONVERTER: it must be caching types that were not created here.
- //qDeleteAll(m_metaTypeFromStringCache.values());
-}
+ShibokenGenerator::~ShibokenGenerator() = default;
void ShibokenGenerator::clearTpFuncs()
{
@@ -277,7 +297,7 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass* metaCl
for (const AbstractMetaFunction *func : funcs) {
if (!func->isProtected() || func->isSignal() || func->isModifiedRemoved())
continue;
- else if (func->isOperatorOverload())
+ if (func->isOperatorOverload())
protectedOperators++;
else
protectedFunctions++;
@@ -332,9 +352,8 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const
result += QLatin1String("Wrapper");
return result;
- } else {
- return metaClass->qualifiedCppName();
}
+ return metaClass->qualifiedCppName();
}
QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const
@@ -342,7 +361,19 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const
return metaType->cppSignature();
}
-QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func)
+QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClass)
+{
+ QString fullClassName = metaClass->name();
+ const AbstractMetaClass *enclosing = metaClass->enclosingClass();
+ while (enclosing) {
+ fullClassName.prepend(enclosing->name() + QLatin1Char('.'));
+ enclosing = enclosing->enclosingClass();
+ }
+ fullClassName.prepend(packageName() + QLatin1Char('.'));
+ return fullClassName;
+}
+
+QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction *func) //WS
{
QString funcName;
if (func->isOperatorOverload())
@@ -350,11 +381,11 @@ QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* fu
else
funcName = func->name();
if (func->ownerClass()) {
- QString fullName = func->ownerClass()->fullName();
+ QString fullClassName = fullPythonClassName(func->ownerClass());
if (func->isConstructor())
- funcName = fullName;
+ funcName = fullClassName;
else
- funcName.prepend(fullName + QLatin1Char('.'));
+ funcName.prepend(fullClassName + QLatin1Char('.'));
}
else {
funcName = packageName() + QLatin1Char('.') + func->name();
@@ -434,7 +465,8 @@ QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField* me
return QStringLiteral("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
}
-static QString cpythonEnumFlagsName(QString moduleName, QString qualifiedCppName)
+static QString cpythonEnumFlagsName(const QString &moduleName,
+ const QString &qualifiedCppName)
{
QString result = QStringLiteral("Sbk%1_%2").arg(moduleName, qualifiedCppName);
result.replace(QLatin1String("::"), QLatin1String("_"));
@@ -570,7 +602,7 @@ QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunction
fieldName.prepend(prefix);
prefix.clear();
} else {
- fieldName.prepend(QLatin1String(CPP_SELF_VAR "->"));
+ fieldName.prepend(QLatin1String(CPP_SELF_VAR) + QLatin1String("->"));
}
value.replace(match.captured(1), fieldName);
break;
@@ -616,12 +648,14 @@ QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClas
return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("SpecialCastFunction");
}
-QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName)
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass,
+ const QString &argName)
{
return cpythonWrapperCPtr(metaClass->typeEntry(), argName);
}
-QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName)
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType,
+ const QString &argName)
{
if (!ShibokenGenerator::isWrapperType(metaType->typeEntry()))
return QString();
@@ -630,7 +664,8 @@ QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType,
+ QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
}
-QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName)
+QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type,
+ const QString &argName)
{
if (!ShibokenGenerator::isWrapperType(type))
return QString();
@@ -706,7 +741,8 @@ QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction* func,
|| arg->type()->referenceType() == LValueReference) {
result += QLatin1Char(objType);
} else if (arg->type()->isPrimitive()) {
- const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) arg->type()->typeEntry();
+ const PrimitiveTypeEntry *ptype =
+ static_cast<const PrimitiveTypeEntry *>(arg->type()->typeEntry());
if (ptype->basicReferencedTypeEntry())
ptype = ptype->basicReferencedTypeEntry();
if (m_formatUnits.contains(ptype->name()))
@@ -745,7 +781,7 @@ QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type)
if (ShibokenGenerator::isWrapperType(type) || type->isNamespace()) { // && type->referenceType() == NoReference) {
baseName = QLatin1String("Sbk_") + type->name();
} else if (type->isPrimitive()) {
- const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *ptype = static_cast<const PrimitiveTypeEntry *>(type);
while (ptype->basicReferencedTypeEntry())
ptype = ptype->basicReferencedTypeEntry();
if (ptype->targetLangApiName() == ptype->name())
@@ -753,11 +789,11 @@ QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type)
else
baseName = ptype->targetLangApiName();
} else if (type->isEnum()) {
- baseName = cpythonEnumName((const EnumTypeEntry*) type);
+ baseName = cpythonEnumName(static_cast<const EnumTypeEntry *>(type));
} else if (type->isFlags()) {
- baseName = cpythonFlagsName((const FlagsTypeEntry*) type);
+ baseName = cpythonFlagsName(static_cast<const FlagsTypeEntry *>(type));
} else if (type->isContainer()) {
- const ContainerTypeEntry* ctype = (const ContainerTypeEntry*) type;
+ const ContainerTypeEntry *ctype = static_cast<const ContainerTypeEntry *>(type);
switch (ctype->type()) {
case ContainerTypeEntry::ListContainer:
case ContainerTypeEntry::StringListContainer:
@@ -858,14 +894,6 @@ QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType* type)
+ getTypeIndexVariableName(type) + QLatin1Char(']');
}
-static QString msgUnknownOperator(const AbstractMetaFunction* func)
-{
- QString result = QLatin1String("Unknown operator: \"") + func->originalName() + QLatin1Char('"');
- if (const AbstractMetaClass *c = func->implementingClass())
- result += QLatin1String(" in class: ") + c->name();
- return result;
-}
-
static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); }
QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative)
@@ -925,7 +953,7 @@ QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry* typ
return pythonPrimitiveTypeName(type->name());
}
-QString ShibokenGenerator::pythonOperatorFunctionName(QString cppOpFuncName)
+QString ShibokenGenerator::pythonOperatorFunctionName(const QString &cppOpFuncName)
{
QString value = m_pythonOperators.value(cppOpFuncName);
if (value.isEmpty())
@@ -953,7 +981,7 @@ QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction
return op;
}
-QString ShibokenGenerator::pythonRichCompareOperatorId(QString cppOpFuncName)
+QString ShibokenGenerator::pythonRichCompareOperatorId(const QString &cppOpFuncName)
{
return QLatin1String("Py_") + m_pythonOperators.value(cppOpFuncName).toUpper();
}
@@ -963,7 +991,7 @@ QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunctio
return pythonRichCompareOperatorId(func->originalName());
}
-bool ShibokenGenerator::isNumber(QString cpythonApiName)
+bool ShibokenGenerator::isNumber(const QString &cpythonApiName)
{
return cpythonApiName == QLatin1String("PyInt")
|| cpythonApiName == QLatin1String("PyFloat")
@@ -975,7 +1003,7 @@ bool ShibokenGenerator::isNumber(const TypeEntry* type)
{
if (!type->isPrimitive())
return false;
- return isNumber(pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type));
+ return isNumber(pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type)));
}
bool ShibokenGenerator::isNumber(const AbstractMetaType* type)
@@ -987,7 +1015,8 @@ bool ShibokenGenerator::isPyInt(const TypeEntry* type)
{
if (!type->isPrimitive())
return false;
- return pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type) == QLatin1String("PyInt");
+ return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type))
+ == QLatin1String("PyInt");
}
bool ShibokenGenerator::isPyInt(const AbstractMetaType* type)
@@ -998,7 +1027,7 @@ bool ShibokenGenerator::isPyInt(const AbstractMetaType* type)
bool ShibokenGenerator::isWrapperType(const TypeEntry* type)
{
if (type->isComplex())
- return ShibokenGenerator::isWrapperType((const ComplexTypeEntry*)type);
+ return ShibokenGenerator::isWrapperType(static_cast<const ComplexTypeEntry *>(type));
return type->isObject() || type->isValue() || type->isSmartPointer();
}
bool ShibokenGenerator::isWrapperType(const ComplexTypeEntry* type)
@@ -1052,7 +1081,7 @@ bool ShibokenGenerator::isUserPrimitive(const TypeEntry* type)
{
if (!type->isPrimitive())
return false;
- const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry *>(type);
if (trueType->basicReferencedTypeEntry())
trueType = trueType->basicReferencedTypeEntry();
return trueType->isPrimitive() && !trueType->isCppPrimitive()
@@ -1072,7 +1101,7 @@ bool ShibokenGenerator::isCppPrimitive(const TypeEntry* type)
return true;
if (!type->isPrimitive())
return false;
- const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry *>(type);
if (trueType->basicReferencedTypeEntry())
trueType = trueType->basicReferencedTypeEntry();
return trueType->qualifiedCppName() == QLatin1String("std::string");
@@ -1125,9 +1154,11 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType
if (isVoidPointer(metaType))
return QLatin1String("PyObject_Check");
return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
- } else if (metaType->typeEntry()->isContainer()) {
+ }
+ if (metaType->typeEntry()->isContainer()) {
QString typeCheck = QLatin1String("Shiboken::Conversions::");
- ContainerTypeEntry::Type type = ((const ContainerTypeEntry*)metaType->typeEntry())->type();
+ ContainerTypeEntry::Type type =
+ static_cast<const ContainerTypeEntry *>(metaType->typeEntry())->type();
if (type == ContainerTypeEntry::ListContainer
|| type == ContainerTypeEntry::StringListContainer
|| type == ContainerTypeEntry::LinkedListContainer
@@ -1154,8 +1185,8 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType
const AbstractMetaType* firstType = metaType->instantiations().constFirst();
const AbstractMetaType* secondType = metaType->instantiations().constLast();
if (isPointerToWrapperType(firstType) && isPointerToWrapperType(secondType)) {
- typeCheck += QString::fromLatin1("check%1Types(%2, %3, ").arg(pyType)
- .arg(cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType));
+ typeCheck += QString::fromLatin1("check%1Types(%2, %3, ")
+ .arg(pyType, cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType));
} else {
typeCheck += QString::fromLatin1("convertible%1Types(%2, %3, %4, %5, ")
.arg(pyType, converterObject(firstType),
@@ -1182,8 +1213,10 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool gene
if (type->isEnum() || type->isFlags() || isWrapperType(type))
return QString::fromLatin1("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type));
- else if (isCppPrimitive(type))
- return pythonPrimitiveTypeName((const PrimitiveTypeEntry*)type) + QLatin1String("_Check");
+ if (isCppPrimitive(type)) {
+ return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type))
+ + QLatin1String("_Check");
+ }
QString typeCheck;
if (type->targetLangApiName() == type->name())
typeCheck = cpythonIsConvertibleFunction(type);
@@ -1392,7 +1425,7 @@ void ShibokenGenerator::writeFunctionArguments(QTextStream &s,
if (options & Generator::WriteSelf) {
s << func->implementingClass()->name() << '&';
if (!(options & SkipName))
- s << " " PYTHON_SELF_VAR;
+ s << " self";
}
int argUsed = 0;
@@ -1412,13 +1445,12 @@ QString ShibokenGenerator::functionReturnType(const AbstractMetaFunction* func,
QString modifiedReturnType = QString(func->typeReplaced(0));
if (!modifiedReturnType.isNull() && !(options & OriginalTypeDescription))
return modifiedReturnType;
- else
- return translateType(func->type(), func->implementingClass(), options);
+ return translateType(func->type(), func->implementingClass(), options);
}
QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func,
- QString prepend,
- QString append,
+ const QString &prepend,
+ const QString &append,
Options options,
int /* argCount */) const
{
@@ -1619,8 +1651,9 @@ ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentRepl
QString argValue;
if (language == TypeSystem::TargetLangCode) {
bool hasConversionRule = !func->conversionRule(convLang, i+1).isEmpty();
- bool argRemoved = func->argumentRemoved(i+1);
- removed = removed + (int) argRemoved;
+ const bool argRemoved = func->argumentRemoved(i+1);
+ if (argRemoved)
+ ++removed;
if (argRemoved && hasConversionRule)
argValue = arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
else if (argRemoved || (lastArg && arg->argumentIndex() > lastArg->argumentIndex()))
@@ -1636,8 +1669,7 @@ ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentRepl
}
if (type->typeEntry()->isCustom()) {
argValue = usePyArgs
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos)
- : QLatin1String(PYTHON_ARG);
+ ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG);
} else {
argValue = hasConversionRule
? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
@@ -1673,17 +1705,6 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
s << INDENT << "// End of code injection" << endl;
}
-static 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 AbstractMetaClass *c = func->implementingClass())
- str << c->name() << "::";
- str << func->signature();
- return result;
-}
-
void ShibokenGenerator::writeCodeSnips(QTextStream& s,
const CodeSnipList& codeSnips,
TypeSystem::CodeSnipPosition position,
@@ -1712,7 +1733,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
Q_ASSERT(pyArgsRegex.isValid());
if (language == TypeSystem::TargetLangCode) {
if (usePyArgs) {
- code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS"[\\1-1]"));
+ code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS) + QLatin1String("[\\1-1]"));
} else {
static const QRegularExpression pyArgsRegexCheck(QStringLiteral("%PYARG_([2-9]+)"));
Q_ASSERT(pyArgsRegexCheck.isValid());
@@ -1729,8 +1750,10 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
// Python argument on the binding virtual method.
static const QRegularExpression pyArgsAttributionRegex(QStringLiteral("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"));
Q_ASSERT(pyArgsAttributionRegex.isValid());
- code.replace(pyArgsAttributionRegex, QLatin1String("PyTuple_SET_ITEM(" PYTHON_ARGS ", \\1-1, \\2)"));
- code.replace(pyArgsRegex, QLatin1String("PyTuple_GET_ITEM(" PYTHON_ARGS ", \\1-1)"));
+ code.replace(pyArgsAttributionRegex, QLatin1String("PyTuple_SET_ITEM(")
+ + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1, \\2)"));
+ code.replace(pyArgsRegex, QLatin1String("PyTuple_GET_ITEM(")
+ + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1)"));
}
// Replace %ARG#_TYPE variables.
@@ -1763,7 +1786,8 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
}
// Replace template variable for self Python object.
- QString pySelf = (language == TypeSystem::NativeCode) ? QLatin1String("pySelf") : QLatin1String(PYTHON_SELF_VAR);
+ QString pySelf = language == TypeSystem::NativeCode
+ ? QLatin1String("pySelf") : QLatin1String("self");
code.replace(QLatin1String("%PYSELF"), pySelf);
// Replace template variable for a pointer to C++ of this object.
@@ -1960,16 +1984,6 @@ static QString getConverterTypeSystemVariableArgument(const QString& code, int p
}
typedef QPair<QString, QString> StringPair;
-static 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;
-}
-
void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code)
{
QVector<StringPair> replacements;
@@ -1978,7 +1992,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
const QRegularExpressionMatch match = rit.next();
const QStringList list = match.capturedTexts();
QString conversionString = list.constFirst();
- QString conversionTypeName = list.constLast();
+ const QString &conversionTypeName = list.constLast();
QString message;
const AbstractMetaType *conversionType = buildAbstractMetaTypeFromString(conversionTypeName, &message);
if (!conversionType) {
@@ -2002,8 +2016,8 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
QString varName = list.at(1).trimmed();
if (!varType.isEmpty()) {
if (varType != conversionType->cppSignature()) {
- qFatal(qPrintable(QString::fromLatin1("Types of receiver variable ('%1') and %CONVERTTOCPP type system variable ('%2') differ.")
- .arg(varType, conversionType->cppSignature())), NULL);
+ qFatal("Types of receiver variable ('%s') and %%CONVERTTOCPP type system variable ('%s') differ.",
+ qPrintable(varType), qPrintable(conversionType->cppSignature()));
}
c << getFullTypeName(conversionType) << ' ' << varName;
writeMinimalConstructorExpression(c, conversionType);
@@ -2032,18 +2046,21 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
c << '(';
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)) {
- qFatal(qPrintable(QString::fromLatin1("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%1'")
- .arg(code)), NULL);
+ qFatal("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%s'",
+ qPrintable(code));
}
if (conversion.contains(QLatin1String("%in"))) {
conversion.prepend(QLatin1Char('('));
@@ -2172,9 +2189,7 @@ bool ShibokenGenerator::classNeedsSetattroFunction(const AbstractMetaClass *meta
{
if (!metaClass)
return false;
- if (metaClass->typeEntry()->isSmartPointer())
- return true;
- return false;
+ return metaClass->typeEntry()->isSmartPointer();
}
AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass)
@@ -2244,9 +2259,7 @@ AbstractMetaClassList ShibokenGenerator::getAllAncestors(const AbstractMetaClass
QString ShibokenGenerator::getModuleHeaderFileName(const QString& moduleName) const
{
- QString result = moduleName.isEmpty() ? packageName() : moduleName;
- result.replace(QLatin1Char('.'), QLatin1Char('_'));
- return result.toLower() + QLatin1String("_python.h");
+ return moduleCppPrefix(moduleName).toLower() + QLatin1String("_python.h");
}
bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass)
@@ -2254,12 +2267,10 @@ bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass)
{
if (metaClass->isNamespace() || isObjectType(metaClass))
return false;
- else if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown)
+ if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown)
return metaClass->hasCloneOperator();
- else
- return (metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet);
- return false;
+ return metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet;
}
AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeSignature,
@@ -2269,110 +2280,18 @@ AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ
if (typeSignature.startsWith(QLatin1String("::")))
typeSignature.remove(0, 2);
- if (m_metaTypeFromStringCache.contains(typeSignature))
- return m_metaTypeFromStringCache.value(typeSignature);
-
- QString typeString = typeSignature;
- bool isConst = typeString.startsWith(QLatin1String("const "));
- if (isConst)
- typeString.remove(0, sizeof("const ") / sizeof(char) - 1);
-
- ReferenceType refType = NoReference;
- if (typeString.endsWith(QLatin1String("&&"))) {
- refType = RValueReference;
- typeString.chop(2);
- typeString = typeString.trimmed();
- } else if (typeString.endsWith(QLatin1Char('&'))) {
- refType = LValueReference;
- typeString.chop(1);
- typeString = typeString.trimmed();
- }
-
- int indirections = 0;
- while (typeString.endsWith(QLatin1Char('*'))) {
- ++indirections;
- typeString.chop(1);
- typeString = typeString.trimmed();
- }
-
- if (typeString.startsWith(QLatin1String("::")))
- typeString.remove(0, 2);
-
- QString adjustedTypeName = typeString;
- AbstractMetaTypeList instantiations;
- int lpos = typeString.indexOf(QLatin1Char('<'));
- if (lpos > -1) {
- QStringList instantiatedTypes;
- int rpos = typeString.lastIndexOf(QLatin1Char('>'));
- if ((lpos != -1) && (rpos != -1)) {
- QString type = typeString.mid(lpos + 1, rpos - lpos - 1);
- int depth = 0;
- int start = 0;
- for (int i = 0; i < type.count(); ++i) {
- if (type.at(i) == QLatin1Char('<')) {
- ++depth;
- } else if (type.at(i) == QLatin1Char('>')) {
- --depth;
- } else if (type.at(i) == QLatin1Char(',') && depth == 0) {
- instantiatedTypes << type.mid(start, i - start).trimmed();
- start = i + 1;
- }
- }
- instantiatedTypes << type.mid(start).trimmed();
- adjustedTypeName.truncate(lpos);
- }
- for (const QString &instantiatedType : qAsConst(instantiatedTypes)) {
- AbstractMetaType *tmplArgType = buildAbstractMetaTypeFromString(instantiatedType);
- if (!tmplArgType) {
- if (errorMessage) {
- QTextStream(errorMessage) << "Cannot find template type \""
- << instantiatedType << "\" for \"" << typeSignature << "\".";
- }
- return nullptr;
- }
- instantiations.append(tmplArgType);
- }
- }
-
- TypeEntry *typeEntry = nullptr;
- AbstractMetaType::TypeUsagePattern pattern = AbstractMetaType::InvalidPattern;
-
- if (instantiations.size() == 1
- && instantiations.at(0)->typeUsagePattern() == AbstractMetaType::EnumPattern
- && adjustedTypeName == QLatin1String("QFlags")) {
- pattern = AbstractMetaType::FlagsPattern;
- typeEntry = TypeDatabase::instance()->findType(typeSignature);
- } else {
- typeEntry = TypeDatabase::instance()->findType(adjustedTypeName);
- }
-
- if (!typeEntry) {
- if (errorMessage) {
- QTextStream(errorMessage) << "Cannot find type \"" << adjustedTypeName
- << "\" for \"" << typeSignature << "\".";
+ auto it = m_metaTypeFromStringCache.find(typeSignature);
+ if (it == m_metaTypeFromStringCache.end()) {
+ AbstractMetaType *metaType =
+ AbstractMetaBuilder::translateType(typeSignature, nullptr, true, errorMessage);
+ if (Q_UNLIKELY(!metaType)) {
+ if (errorMessage)
+ errorMessage->prepend(msgCannotBuildMetaType(typeSignature));
+ return nullptr;
}
- return nullptr;
+ it = m_metaTypeFromStringCache.insert(typeSignature, metaType);
}
-
- AbstractMetaType *metaType = new AbstractMetaType();
- metaType->setTypeEntry(typeEntry);
- metaType->setIndirections(indirections);
- metaType->setReferenceType(refType);
- metaType->setConstant(isConst);
- metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
- switch (pattern) {
- case AbstractMetaType::FlagsPattern:
- metaType->setTypeUsagePattern(pattern);
- break;
- default:
- metaType->setInstantiations(instantiations);
- metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
- metaType->decideUsagePattern();
- break;
- }
-
- m_metaTypeFromStringCache.insert(typeSignature, metaType);
- return metaType;
+ return it.value();
}
AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry)
@@ -2384,7 +2303,7 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const Ty
return m_metaTypeFromStringCache.value(typeName);
AbstractMetaType* metaType = new AbstractMetaType;
metaType->setTypeEntry(typeEntry);
- metaType->setIndirections(0);
+ metaType->clearIndirections();
metaType->setReferenceType(NoReference);
metaType->setConstant(false);
metaType->decideUsagePattern();
@@ -2449,7 +2368,7 @@ AbstractMetaFunctionList ShibokenGenerator::getInheritedOverloads(const Abstract
{
AbstractMetaFunctionList results;
AbstractMetaClass* basis;
- if (func->ownerClass() && (basis = func->ownerClass()->baseClass(), basis)) {
+ if (func->ownerClass() && (basis = func->ownerClass()->baseClass())) {
for (; basis; basis = basis->baseClass()) {
const AbstractMetaFunction* inFunc = basis->findFunction(func->name());
if (inFunc && !seen->contains(inFunc->minimalSignature())) {
@@ -2509,6 +2428,23 @@ Generator::OptionDescriptions ShibokenGenerator::options() const
"the value of boolean casts"));
}
+bool ShibokenGenerator::handleOption(const QString &key, const QString & /* value */)
+{
+ if (key == QLatin1String(PARENT_CTOR_HEURISTIC))
+ return (m_useCtorHeuristic = true);
+ if (key == QLatin1String(ENABLE_PYSIDE_EXTENSIONS))
+ return (m_usePySideExtensions = true);
+ if (key == QLatin1String(RETURN_VALUE_HEURISTIC))
+ return (m_userReturnValueHeuristic = true);
+ if (key == QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES))
+ return (m_verboseErrorMessagesDisabled = true);
+ if (key == QLatin1String(USE_ISNULL_AS_NB_NONZERO))
+ return (m_useIsNullAsNbNonZero = true);
+ if (key == QLatin1String(AVOID_PROTECTED_HACK))
+ return (m_avoidProtectedHack = true);
+ return false;
+}
+
static void getCode(QStringList& code, const CodeSnipList& codeSnips)
{
for (const CodeSnip &snip : qAsConst(codeSnips))
@@ -2534,15 +2470,8 @@ static void getCode(QStringList& code, const TypeEntry* type)
code.append(toNative->conversion());
}
-bool ShibokenGenerator::doSetup(const QMap<QString, QString>& args)
+bool ShibokenGenerator::doSetup()
{
- m_useCtorHeuristic = args.contains(QLatin1String(PARENT_CTOR_HEURISTIC));
- m_usePySideExtensions = args.contains(QLatin1String(ENABLE_PYSIDE_EXTENSIONS));
- m_userReturnValueHeuristic = args.contains(QLatin1String(RETURN_VALUE_HEURISTIC));
- m_verboseErrorMessagesDisabled = args.contains(QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES));
- m_useIsNullAsNbNonZero = args.contains(QLatin1String(USE_ISNULL_AS_NB_NONZERO));
- m_avoidProtectedHack = args.contains(QLatin1String(AVOID_PROTECTED_HACK));
-
TypeDatabase* td = TypeDatabase::instance();
QStringList snips;
const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
@@ -2554,7 +2483,11 @@ bool ShibokenGenerator::doSetup(const QMap<QString, QString>& args)
const AbstractMetaClassList &classList = classes();
for (const AbstractMetaClass *metaClass : classList)
getCode(snips, metaClass->typeEntry());
- getCode(snips, td->findType(packageName()));
+
+ const TypeSystemTypeEntry *moduleEntry = td->findTypeSystemType(packageName());
+ Q_ASSERT(moduleEntry);
+ getCode(snips, moduleEntry);
+
const FunctionGroupMap &functionGroups = getFunctionGroups();
for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
for (AbstractMetaFunction *func : it.value())
@@ -2611,15 +2544,25 @@ bool ShibokenGenerator::avoidProtectedHack() const
return m_avoidProtectedHack;
}
-QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const
-{
- QString result = moduleName.isEmpty() ? ShibokenGenerator::packageName() : moduleName;
+QString ShibokenGenerator::moduleCppPrefix(const QString& moduleName) const
+ {
+ QString result = moduleName.isEmpty() ? packageName() : moduleName;
result.replace(QLatin1Char('.'), QLatin1Char('_'));
- result.prepend(QLatin1String("Sbk"));
- result.append(QLatin1String("Types"));
return result;
}
+QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const
+{
+ return QLatin1String("Sbk") + moduleCppPrefix(moduleName)
+ + QLatin1String("Types");
+}
+
+QString ShibokenGenerator::pythonModuleObjectName(const QString& moduleName) const
+{
+ return QLatin1String("Sbk") + moduleCppPrefix(moduleName)
+ + QLatin1String("ModuleObject");
+}
+
QString ShibokenGenerator::convertersVariableName(const QString& moduleName) const
{
QString result = cppApiVariableName(moduleName);
@@ -2639,35 +2582,50 @@ static QString processInstantiationsVariableName(const AbstractMetaType* type)
}
return res;
}
+
+static void appendIndexSuffix(QString *s)
+{
+ if (!s->endsWith(QLatin1Char('_')))
+ s->append(QLatin1Char('_'));
+ s->append(QStringLiteral("IDX"));
+}
+
QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* metaClass, bool alternativeTemplateName)
{
if (alternativeTemplateName) {
const AbstractMetaClass* templateBaseClass = metaClass->templateBaseClass();
if (!templateBaseClass)
return QString();
- QString base = _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
- QString instantiations;
+ QString result = QLatin1String("SBK_")
+ + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
const AbstractMetaTypeList &templateBaseClassInstantiations = metaClass->templateBaseClassInstantiations();
for (const AbstractMetaType *instantiation : templateBaseClassInstantiations)
- instantiations += processInstantiationsVariableName(instantiation);
- return QString::fromLatin1("SBK_%1%2_IDX").arg(base, instantiations);
+ result += processInstantiationsVariableName(instantiation);
+ appendIndexSuffix(&result);
+ return result;
}
return getTypeIndexVariableName(metaClass->typeEntry());
}
QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type)
{
if (type->isCppPrimitive()) {
- const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry*>(type);
if (trueType->basicReferencedTypeEntry())
type = trueType->basicReferencedTypeEntry();
}
- return QString::fromLatin1("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper());
+ QString result = QLatin1String("SBK_")
+ + _fixedCppTypeName(type->qualifiedCppName()).toUpper();
+ appendIndexSuffix(&result);
+ return result;
}
QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type)
{
- return QString::fromLatin1("SBK%1%2_IDX")
- .arg(type->typeEntry()->isContainer() ? QLatin1Char('_') + moduleName().toUpper() : QString(),
- processInstantiationsVariableName(type));
+ QString result = QLatin1String("SBK");
+ if (type->typeEntry()->isContainer())
+ result += QLatin1Char('_') + moduleName().toUpper();
+ result += processInstantiationsVariableName(type);
+ appendIndexSuffix(&result);
+ return result;
}
bool ShibokenGenerator::verboseErrorMessagesDisabled() const
@@ -2707,30 +2665,37 @@ QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, co
void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor)
{
- if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ if (!defaultCtor.isEmpty()) {
+ s << " = " << defaultCtor;
+ return;
+ }
+ if (isCppPrimitive(type))
return;
- QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
- if (ctor.isEmpty()) {
+ const auto ctor = minimalConstructor(type);
+ if (ctor.isValid()) {
+ s << ctor.initialization();
+ } else {
const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->cppSignature());
qCWarning(lcShiboken()).noquote() << message;
s << ";\n#error " << message << '\n';
- } else {
- s << " = " << ctor;
}
}
void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor)
{
- if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ if (!defaultCtor.isEmpty()) {
+ s << " = " << defaultCtor;
+ return;
+ }
+ if (isCppPrimitive(type))
return;
- QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
-
- if (ctor.isEmpty()) {
+ const auto ctor = minimalConstructor(type);
+ if (ctor.isValid()) {
+ s << ctor.initialization();
+ } else {
const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName());
qCWarning(lcShiboken()).noquote() << message;
s << ";\n#error " << message << endl;
- } else {
- s << " = " << ctor;
}
}
@@ -2738,7 +2703,7 @@ bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry* type)
{
if (!type->isCppPrimitive())
return false;
- const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry *>(type);
if (trueType->basicReferencedTypeEntry())
trueType = trueType->basicReferencedTypeEntry();
QString typeName = trueType->qualifiedCppName();
@@ -2751,8 +2716,8 @@ bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type)
return isCppIntegralPrimitive(type->typeEntry());
}
-QString ShibokenGenerator::msgCouldNotFindMinimalConstructor(const QString &where, const QString &type)
+QString ShibokenGenerator::pythonArgsAt(int i)
{
- return where + QLatin1String(": Could not find a minimal constructor for type '") + type
- + QLatin1String("'. This will result in a compilation error.");
+ return QLatin1String(PYTHON_ARGS) + QLatin1Char('[')
+ + QString::number(i) + QLatin1Char(']');
}
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
index cb1bdd11f..60e31a99b 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -29,28 +29,20 @@
#ifndef SHIBOKENGENERATOR_H
#define SHIBOKENGENERATOR_H
-#define CONV_RULE_OUT_VAR_SUFFIX "_out"
-#define CPP_ARG "cppArg"
-#define CPP_ARG0 CPP_ARG"0"
-#define CPP_ARG_REMOVED "removed_" CPP_ARG
-#define CPP_RETURN_VAR "cppResult"
-#define CPP_SELF_VAR "cppSelf"
-#define PYTHON_ARG "pyArg"
-#define PYTHON_ARGS PYTHON_ARG "s"
-#define PYTHON_OVERRIDE_VAR "pyOverride"
-#define PYTHON_RETURN_VAR "pyResult"
-#define PYTHON_SELF_VAR "self"
-#define THREAD_STATE_SAVER_VAR "threadStateSaver"
-#define BEGIN_ALLOW_THREADS "PyThreadState* _save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS"
-#define END_ALLOW_THREADS "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS"
-#define PYTHON_TO_CPP_VAR "pythonToCpp"
-#define SMART_POINTER_GETTER "kSmartPointerGetter"
-
-#define CHECKTYPE_REGEX "%CHECKTYPE\\[([^\\[]*)\\]\\("
-#define ISCONVERTIBLE_REGEX "%ISCONVERTIBLE\\[([^\\[]*)\\]\\("
-#define CONVERTTOPYTHON_REGEX "%CONVERTTOPYTHON\\[([^\\[]*)\\]\\("
-#define CONVERTTOCPP_REGEX "(\\*?%?[a-zA-Z_][\\w\\.]*(?:\\[[^\\[^<^>]+\\])*)"\
- "(?:\\s+)=(?:\\s+)%CONVERTTOCPP\\[([^\\[]*)\\]\\("
+extern const char *CPP_ARG;
+extern const char *CPP_ARG_REMOVED;
+extern const char *CPP_RETURN_VAR;
+extern const char *CPP_SELF_VAR;
+extern const char *PYTHON_ARG;
+extern const char *PYTHON_ARGS;
+extern const char *PYTHON_OVERRIDE_VAR;
+extern const char *PYTHON_RETURN_VAR;
+extern const char *PYTHON_TO_CPP_VAR;
+extern const char *SMART_POINTER_GETTER;
+
+extern const char *CONV_RULE_OUT_VAR_SUFFIX;
+extern const char *BEGIN_ALLOW_THREADS;
+extern const char *END_ALLOW_THREADS;
#include <generator.h>
@@ -71,61 +63,20 @@ class ShibokenGenerator : public Generator
{
public:
ShibokenGenerator();
- virtual ~ShibokenGenerator();
+ ~ShibokenGenerator() override;
- QString translateTypeForWrapperMethod(const AbstractMetaType* cType,
- const AbstractMetaClass* context, Options opt = NoOption) const;
+ const char *name() const override { return "Shiboken"; }
/**
- * 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.
- */
- QMap<QString, AbstractMetaFunctionList> getFunctionGroups(const AbstractMetaClass* scope = 0);
-
- /**
- * 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.
- */
- AbstractMetaFunctionList getInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
+ * Helper function to find for argument default value
+ */
+ static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
- /**
- * 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.
- */
- AbstractMetaFunctionList getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
+ /// Returns a list of all ancestor classes for the given class.
+ AbstractMetaClassList getAllAncestors(const AbstractMetaClass* metaClass) const;
- /**
- * Returns all overloads for a function named \p functionName.
- * \param scope scope used to search for overloads.
- * \param functionName the function name.
- */
- AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName);
- /**
- * 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(QTextStream &s,
- const AbstractMetaFunction* 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 AbstractMetaFunction* func,
- const AbstractMetaArgument* argument,
- Options options = NoOption) const;
+protected:
+ bool doSetup() override;
void writeArgumentNames(QTextStream &s,
const AbstractMetaFunction* func,
@@ -141,14 +92,21 @@ public:
void writeFunctionArguments(QTextStream &s,
const AbstractMetaFunction* func,
Options options = NoOption) const override;
- QString functionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
- /// Utility function for writeCodeSnips.
- typedef QPair<const AbstractMetaArgument*, QString> ArgumentVarReplacementPair;
- typedef QVector<ArgumentVarReplacementPair> ArgumentVarReplacementList;
- ArgumentVarReplacementList getArgumentReplacement(const AbstractMetaFunction* func,
- bool usePyArgs, TypeSystem::Language language,
- const AbstractMetaArgument* lastArg);
+ /**
+ * 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.
+ */
+ QMap<QString, AbstractMetaFunctionList> getFunctionGroups(const AbstractMetaClass* scope = 0);
+
+ /**
+ * 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.
+ */
+ AbstractMetaFunctionList getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
/// Write user's custom code snippets at class or module level.
void writeCodeSnips(QTextStream& s,
@@ -164,33 +122,9 @@ public:
const AbstractMetaFunction* func,
const AbstractMetaArgument* lastArg = 0);
- /// Returns a string with the user's custom code snippets that comply with \p position and \p language.
- QString getCodeSnippets(const QVector<CodeSnip> & codeSnips, TypeSystem::CodeSnipPosition position, TypeSystem::Language language);
-
/// Replaces variables for the user's custom code at global or class level.
void processCodeSnip(QString& code, const AbstractMetaClass* context = 0);
- /// Replaces the %CONVERTTOPYTHON type system variable.
- inline void replaceConvertToPythonTypeSystemVariable(QString& code)
- {
- replaceConverterTypeSystemVariable(TypeSystemToPythonFunction, code);
- }
- /// Replaces the %CONVERTTOCPP type system variable.
- inline void replaceConvertToCppTypeSystemVariable(QString& code)
- {
- replaceConverterTypeSystemVariable(TypeSystemToCppFunction, code);
- }
- /// Replaces the %ISCONVERTIBLE type system variable.
- inline void replaceIsConvertibleToCppTypeSystemVariable(QString& code)
- {
- replaceConverterTypeSystemVariable(TypeSystemIsConvertibleFunction, code);
- }
- /// Replaces the %CHECKTYPE type system variable.
- inline void replaceTypeCheckTypeSystemVariable(QString& code)
- {
- replaceConverterTypeSystemVariable(TypeSystemCheckFunction, code);
- }
-
/**
* Verifies if any of the function's code injections of the "native"
* type needs the type system variable "%PYSELF".
@@ -239,8 +173,8 @@ public:
* \param arg_count the number of function arguments
*/
QString functionSignature(const AbstractMetaFunction* func,
- QString prepend = QString(),
- QString append = QString(),
+ const QString &prepend = QString(),
+ const QString &append = QString(),
Options options = NoOption,
int arg_count = -1) const;
@@ -259,9 +193,6 @@ public:
/// Returns a list of parent classes for a given class.
AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass) const;
- /// Returns a list of all ancestor classes for the given class.
- AbstractMetaClassList getAllAncestors(const AbstractMetaClass* metaClass) const;
-
const AbstractMetaClass* getMultipleInheritingClass(const AbstractMetaClass* metaClass);
void writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
@@ -283,7 +214,8 @@ public:
QString wrapperName(const AbstractMetaClass* metaClass) const;
QString wrapperName(const AbstractMetaType *metaType) const;
- QString fullPythonFunctionName(const AbstractMetaFunction* func);
+ QString fullPythonClassName(const AbstractMetaClass *metaClass);
+ QString fullPythonFunctionName(const AbstractMetaFunction *func); //WS
static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum);
static QString protectedFieldGetterName(const AbstractMetaField* field);
@@ -292,16 +224,16 @@ public:
static QString pythonPrimitiveTypeName(const QString& cppTypeName);
static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry* type);
- static QString pythonOperatorFunctionName(QString cppOpFuncName);
+ static QString pythonOperatorFunctionName(const QString &cppOpFuncName);
static QString pythonOperatorFunctionName(const AbstractMetaFunction* func);
- static QString pythonRichCompareOperatorId(QString cppOpFuncName);
+ static QString pythonRichCompareOperatorId(const QString &cppOpFuncName);
static QString pythonRichCompareOperatorId(const AbstractMetaFunction* func);
static QString fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative);
static QString fixedCppTypeName(const AbstractMetaType* type);
static QString fixedCppTypeName(const TypeEntry* type, QString typeName = QString());
- static bool isNumber(QString cpythonApiName);
+ static bool isNumber(const QString &cpythonApiName);
static bool isNumber(const TypeEntry* type);
static bool isNumber(const AbstractMetaType* type);
static bool isPyInt(const TypeEntry* type);
@@ -389,9 +321,10 @@ public:
QString cpythonSetattroFunctionName(const AbstractMetaClass* metaClass);
QString cpythonGetterFunctionName(const AbstractMetaField* metaField);
QString cpythonSetterFunctionName(const AbstractMetaField* metaField);
- QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName = QLatin1String(PYTHON_SELF_VAR));
- QString cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName);
- QString cpythonWrapperCPtr(const TypeEntry* type, QString argName);
+ QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass,
+ const QString &argName = QLatin1String("self"));
+ QString cpythonWrapperCPtr(const AbstractMetaType *metaType, const QString &argName);
+ QString cpythonWrapperCPtr(const TypeEntry* type, const QString &argName);
/// Guesses the scope to where belongs an argument's default value.
QString guessScopeForDefaultValue(const AbstractMetaFunction *func,
@@ -414,6 +347,7 @@ public:
QString getModuleHeaderFileName(const QString& moduleName = QString()) const;
OptionDescriptions options() const override;
+ bool handleOption(const QString &key, const QString &value) override;
/// Returns true if the user enabled the so called "parent constructor heuristic".
bool useCtorHeuristic() const;
@@ -426,6 +360,7 @@ public:
/// Returns true if the generated code should use the "#define protected public" hack.
bool avoidProtectedHack() const;
QString cppApiVariableName(const QString& moduleName = QString()) const;
+ QString pythonModuleObjectName(const QString& moduleName = QString()) const;
QString convertersVariableName(const QString& moduleName = QString()) const;
/**
* Returns the type index variable name for a given class. If \p alternativeTemplateName is true
@@ -457,26 +392,12 @@ public:
void writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor = QString());
void writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor = QString());
- /**
- * Helper function to find for argument default value
- */
- static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
-protected:
- bool doSetup(const QMap<QString, QString>& args);
void collectContainerTypesFromConverterMacros(const QString& code, bool toPythonMacro);
// verify whether the class is copyable
bool isCopyable(const AbstractMetaClass* metaClass);
- bool m_native_jump_table;
- static QHash<QString, QString> m_pythonPrimitiveTypeName;
- static QHash<QString, QString> m_pythonOperators;
- static QHash<QString, QString> m_formatUnits;
- static QHash<QString, QString> m_tpFuncs;
- static QStringList m_knownPythonTypes;
-
void clearTpFuncs();
- const char* name() const { return "Shiboken"; }
/// Initializes correspondences between primitive and Python types.
static void initPrimitiveTypesCorrespondences();
@@ -505,6 +426,74 @@ protected:
Indentor INDENT;
+ const QRegularExpression &convertToCppRegEx() const
+ { return m_typeSystemConvRegEx[TypeSystemToCppFunction]; }
+
+ static QString pythonArgsAt(int i);
+
+ static QHash<QString, QString> m_pythonPrimitiveTypeName;
+ static QHash<QString, QString> m_pythonOperators;
+ static QHash<QString, QString> m_formatUnits;
+ static QHash<QString, QString> m_tpFuncs;
+ static QStringList m_knownPythonTypes;
+
+private:
+ QString translateTypeForWrapperMethod(const AbstractMetaType* cType,
+ const AbstractMetaClass* 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.
+ */
+ AbstractMetaFunctionList getInheritedOverloads(const AbstractMetaFunction *func,
+ QSet<QString> *seen);
+
+ /**
+ * Returns all overloads for a function named \p functionName.
+ * \param scope scope used to search for overloads.
+ * \param functionName the function name.
+ */
+ AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope,
+ const QString& functionName);
+ /**
+ * 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(QTextStream &s,
+ const AbstractMetaFunction* 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 AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ Options options = NoOption) const;
+
+ QString functionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
+
+ /// Utility function for writeCodeSnips.
+ typedef QPair<const AbstractMetaArgument*, QString> ArgumentVarReplacementPair;
+ typedef QVector<ArgumentVarReplacementPair> ArgumentVarReplacementList;
+ ArgumentVarReplacementList getArgumentReplacement(const AbstractMetaFunction* 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.
+ QString getCodeSnippets(const QVector<CodeSnip> & codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language);
+
enum TypeSystemConverterVariable {
TypeSystemCheckFunction = 0,
TypeSystemIsConvertibleFunction,
@@ -514,15 +503,36 @@ protected:
};
void replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code);
- static QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type);
+ /// Replaces the %CONVERTTOPYTHON type system variable.
+ inline void replaceConvertToPythonTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToPythonFunction, code);
+ }
+ /// Replaces the %CONVERTTOCPP type system variable.
+ inline void replaceConvertToCppTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToCppFunction, code);
+ }
+ /// Replaces the %ISCONVERTIBLE type system variable.
+ inline void replaceIsConvertibleToCppTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemIsConvertibleFunction, code);
+ }
+ /// Replaces the %CHECKTYPE type system variable.
+ inline void replaceTypeCheckTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemCheckFunction, code);
+ }
-private:
- bool m_useCtorHeuristic;
- bool m_userReturnValueHeuristic;
- bool m_usePySideExtensions;
- bool m_verboseErrorMessagesDisabled;
- bool m_useIsNullAsNbNonZero;
- bool m_avoidProtectedHack;
+ /// Return a prefix with '_' suitable for names in C++
+ QString moduleCppPrefix(const QString& moduleName = QString()) const;
+
+ bool m_useCtorHeuristic = false;
+ bool m_userReturnValueHeuristic = false;
+ bool m_usePySideExtensions = false;
+ bool m_verboseErrorMessagesDisabled = false;
+ bool m_useIsNullAsNbNonZero = false;
+ bool m_avoidProtectedHack = false;
typedef QHash<QString, AbstractMetaType*> AbstractMetaTypeCache;
AbstractMetaTypeCache m_metaTypeFromStringCache;
diff --git a/sources/shiboken2/libshiboken/autodecref.h b/sources/shiboken2/libshiboken/autodecref.h
index 7b6aa47da..72fd236de 100644
--- a/sources/shiboken2/libshiboken/autodecref.h
+++ b/sources/shiboken2/libshiboken/autodecref.h
@@ -43,11 +43,6 @@
#include "sbkpython.h"
#include "basewrapper.h"
-#ifdef _MSC_VER
-__pragma(warning(push))
-__pragma(warning(disable:4522)) // warning: C4522: 'Shiboken::AutoDecRef': multiple assignment operators specified
-#endif
-
struct SbkObject;
namespace Shiboken
{
@@ -58,6 +53,11 @@ namespace Shiboken
struct LIBSHIBOKEN_API AutoDecRef
{
public:
+ AutoDecRef(const AutoDecRef&) = delete;
+ AutoDecRef(AutoDecRef&&) = delete;
+ AutoDecRef& operator=(const AutoDecRef&) = delete;
+ AutoDecRef& operator=(AutoDecRef&&) = delete;
+
/**
* AutoDecRef constructor.
* \param pyobj A borrowed reference to a Python object
@@ -92,35 +92,18 @@ public:
}
/**
- * Decref the current borrowed python reference and take the reference
- * borrowed by \p other, so other.isNull() will return true.
- */
- void operator=(AutoDecRef& other)
- {
- Py_XDECREF(m_pyObj);
- m_pyObj = other.m_pyObj;
- other.m_pyObj = 0;
- }
-
- /**
* Decref the current borrowed python reference and borrow \p other.
*/
- void operator=(PyObject* other)
+ void reset(PyObject* other)
{
Py_XDECREF(m_pyObj);
m_pyObj = other;
}
private:
PyObject* m_pyObj;
- AutoDecRef(const AutoDecRef&);
- AutoDecRef& operator=(const AutoDecRef&);
};
} // namespace Shiboken
-#ifdef _MSC_VER
-__pragma(warning(pop))
-#endif
-
#endif // AUTODECREF_H
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 5ca4172c8..c9e3b9d1b 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -40,6 +40,7 @@
#include "basewrapper.h"
#include "basewrapper_p.h"
#include "bindingmanager.h"
+#include "helper.h"
#include "sbkconverter.h"
#include "sbkenum.h"
#include "sbkstring.h"
@@ -60,6 +61,15 @@ namespace {
void _destroyParentInfo(SbkObject* obj, bool keepReference);
}
+static void callDestructor(const Shiboken::DtorAccumulatorVisitor::DestructorEntries &dts)
+{
+ for (const auto &e : dts) {
+ Shiboken::ThreadStateSaver threadSaver;
+ threadSaver.save();
+ e.destructor(e.cppInstance);
+ }
+}
+
extern "C"
{
@@ -118,20 +128,15 @@ static int SbkObject_traverse(PyObject* self, visitproc visit, void* arg)
//Visit children
Shiboken::ParentInfo* pInfo = sbkSelf->d->parentInfo;
if (pInfo) {
- std::set<SbkObject*>::const_iterator it = pInfo->children.begin();
- for(; it != pInfo->children.end(); ++it)
- Py_VISIT(*it);
+ for (SbkObject *c : pInfo->children)
+ Py_VISIT(c);
}
//Visit refs
Shiboken::RefCountMap* rInfo = sbkSelf->d->referredObjects;
if (rInfo) {
- Shiboken::RefCountMap::const_iterator it = rInfo->begin();
- for (; it != rInfo->end(); ++it) {
- std::list<PyObject*>::const_iterator ref = it->second.begin();
- for(; ref != it->second.end(); ++ref)
- Py_VISIT(*ref);
- }
+ for (auto it = rInfo->begin(), end = rInfo->end(); it != end; ++it)
+ Py_VISIT(it->second);
}
if (sbkSelf->ob_dict)
@@ -186,6 +191,12 @@ SbkObjectType *SbkObject_TypeF(void)
return reinterpret_cast<SbkObjectType *>(type);
}
+static int mainThreadDeletionHandler(void *)
+{
+ if (Py_IsInitialized())
+ Shiboken::BindingManager::instance().runDeletionInMainThread();
+ return 0;
+}
static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete)
{
@@ -214,11 +225,32 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete)
PyObject_ClearWeakRefs(pyObj);
// If I have ownership and is valid delete C++ pointer
- if (canDelete && sbkObj->d->hasOwnership && sbkObj->d->validCppObject) {
- SbkObjectTypePrivate *sotp = PepType_SOTP(pyType);
+ SbkObjectTypePrivate *sotp{nullptr};
+ canDelete &= sbkObj->d->hasOwnership && sbkObj->d->validCppObject;
+ if (canDelete) {
+ sotp = PepType_SOTP(pyType);
+ if (sotp->delete_in_main_thread && Shiboken::currentThreadId() != Shiboken::mainThreadId()) {
+ auto &bindingManager = Shiboken::BindingManager::instance();
+ if (sotp->is_multicpp) {
+ Shiboken::DtorAccumulatorVisitor visitor(sbkObj);
+ Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor);
+ for (const auto &e : visitor.entries())
+ bindingManager.addToDeletionInMainThread(e);
+ } else {
+ Shiboken::DestructorEntry e{sotp->cpp_dtor, sbkObj->d->cptr[0]};
+ bindingManager.addToDeletionInMainThread(e);
+ }
+ Py_AddPendingCall(mainThreadDeletionHandler, nullptr);
+ canDelete = false;
+ }
+ }
+
+ if (canDelete) {
if (sotp->is_multicpp) {
- Shiboken::DeallocVisitor visitor(sbkObj);
+ Shiboken::DtorAccumulatorVisitor visitor(sbkObj);
Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor);
+ Shiboken::Object::deallocData(sbkObj, true);
+ callDestructor(visitor.entries());
} else {
void* cptr = sbkObj->d->cptr[0];
Shiboken::Object::deallocData(sbkObj, true);
@@ -325,7 +357,7 @@ PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* k
Shiboken::ObjectType::initPrivateData(newType);
SbkObjectTypePrivate *sotp = PepType_SOTP(newType);
- std::list<SbkObjectType*> bases = Shiboken::getCppBaseClasses(reinterpret_cast<PyTypeObject*>(newType));
+ const auto bases = Shiboken::getCppBaseClasses(reinterpret_cast<PyTypeObject*>(newType));
if (bases.size() == 1) {
SbkObjectTypePrivate *parentType = PepType_SOTP(bases.front());
sotp->mi_offsets = parentType->mi_offsets;
@@ -352,10 +384,9 @@ PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* k
sotp->d_func = nullptr;
sotp->is_user_type = 1;
- std::list<SbkObjectType*>::const_iterator it = bases.begin();
- for (; it != bases.end(); ++it) {
- if (PepType_SOTP(*it)->subtype_init)
- PepType_SOTP(*it)->subtype_init(newType, args, kwds);
+ for (SbkObjectType *base : bases) {
+ if (PepType_SOTP(base)->subtype_init)
+ PepType_SOTP(base)->subtype_init(newType, args, kwds);
}
return reinterpret_cast<PyObject*>(newType);
@@ -455,37 +486,22 @@ void _destroyParentInfo(SbkObject* obj, bool keepReference)
namespace Shiboken
{
-
-static void decRefPyObjectList(const std::list<PyObject*> &pyObj, PyObject* skip = 0);
-
-static void _walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor)
+bool walkThroughClassHierarchy(PyTypeObject *currentType, HierarchyVisitor *visitor)
{
PyObject* bases = currentType->tp_bases;
Py_ssize_t numBases = PyTuple_GET_SIZE(bases);
- for (int i = 0; i < numBases; ++i) {
+ bool result = false;
+ for (int i = 0; !result && i < numBases; ++i) {
PyTypeObject* type = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i));
-
- if (!PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) {
- continue;
- } else {
+ if (PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) {
SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(type);
- if (PepType_SOTP(sbkType)->is_user_type)
- _walkThroughClassHierarchy(type, visitor);
- else
- visitor->visit(sbkType);
+ result = PepType_SOTP(sbkType)->is_user_type
+ ? walkThroughClassHierarchy(type, visitor) : visitor->visit(sbkType);
}
- if (visitor->wasFinished())
- break;
}
+ return result;
}
-void walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor)
-{
- _walkThroughClassHierarchy(currentType, visitor);
- visitor->done();
-}
-
-
bool importModule(const char* moduleName, PyTypeObject*** cppApiPtr)
{
PyObject* sysModules = PyImport_GetModuleDict();
@@ -517,27 +533,36 @@ bool importModule(const char* moduleName, PyTypeObject*** cppApiPtr)
// Wrapper metatype and base type ----------------------------------------------------------
-void DtorCallerVisitor::visit(SbkObjectType* node)
+HierarchyVisitor::HierarchyVisitor() = default;
+HierarchyVisitor::~HierarchyVisitor() = default;
+
+bool BaseCountVisitor::visit(SbkObjectType *)
{
- m_ptrs.push_back(std::make_pair(m_pyObj->d->cptr[m_ptrs.size()], node));
+ m_count++;
+ return false;
}
-void DtorCallerVisitor::done()
+bool BaseAccumulatorVisitor::visit(SbkObjectType *node)
{
- std::list<std::pair<void*, SbkObjectType*> >::const_iterator it = m_ptrs.begin();
- for (; it != m_ptrs.end(); ++it) {
- Shiboken::ThreadStateSaver threadSaver;
- threadSaver.save();
- PepType_SOTP(it->second)->cpp_dtor(it->first);
- }
+ m_bases.push_back(node);
+ return false;
}
-void DeallocVisitor::done()
+bool GetIndexVisitor::visit(SbkObjectType *node)
{
- Shiboken::Object::deallocData(m_pyObj, true);
- DtorCallerVisitor::done();
+ m_index++;
+ return PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(node), m_desiredType);
}
+bool DtorAccumulatorVisitor::visit(SbkObjectType *node)
+{
+ m_entries.push_back(DestructorEntry{PepType_SOTP(node)->cpp_dtor,
+ m_pyObject->d->cptr[m_entries.size()]});
+ return false;
+}
+
+void _initMainThreadId(); // helper.cpp
+
namespace Conversions { void init(); }
void init()
@@ -546,6 +571,8 @@ void init()
if (shibokenAlreadInitialised)
return;
+ _initMainThreadId();
+
Conversions::init();
PyEval_InitThreads();
@@ -609,25 +636,21 @@ void setErrorAboutWrongArguments(PyObject* args, const char* funcName, const cha
class FindBaseTypeVisitor : public HierarchyVisitor
{
- public:
- FindBaseTypeVisitor(PyTypeObject* typeToFind) : m_found(false), m_typeToFind(typeToFind) {}
- virtual void visit(SbkObjectType* node)
- {
- if (reinterpret_cast<PyTypeObject*>(node) == m_typeToFind) {
- m_found = true;
- finish();
- }
- }
- bool found() const { return m_found; }
+public:
+ explicit FindBaseTypeVisitor(PyTypeObject *typeToFind) : m_typeToFind(typeToFind) {}
+
+ bool visit(SbkObjectType *node) override
+ {
+ return reinterpret_cast<PyTypeObject*>(node) == m_typeToFind;
+ }
- private:
- bool m_found;
- PyTypeObject* m_typeToFind;
+private:
+ PyTypeObject *m_typeToFind;
};
-std::list<SbkObject*> splitPyObject(PyObject* pyObj)
+std::vector<SbkObject *> splitPyObject(PyObject* pyObj)
{
- std::list<SbkObject*> result;
+ std::vector<SbkObject *> result;
if (PySequence_Check(pyObj)) {
AutoDecRef lst(PySequence_Fast(pyObj, "Invalid keep reference object."));
if (!lst.isNull()) {
@@ -643,14 +666,11 @@ std::list<SbkObject*> splitPyObject(PyObject* pyObj)
return result;
}
-static void decRefPyObjectList(const std::list<PyObject*>& lst, PyObject *skip)
+template <class Iterator>
+inline void decRefPyObjectList(Iterator i1, Iterator i2)
{
- std::list<PyObject*>::const_iterator iter = lst.begin();
- while(iter != lst.end()) {
- if (*iter != skip)
- Py_DECREF(*iter);
- ++iter;
- }
+ for (; i1 != i2; ++i1)
+ Py_DECREF(i1->second);
}
namespace ObjectType
@@ -669,8 +689,7 @@ bool isUserType(PyTypeObject* type)
bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType)
{
FindBaseTypeVisitor visitor(ctorType);
- walkThroughClassHierarchy(myType, &visitor);
- if (!visitor.found()) {
+ if (!walkThroughClassHierarchy(myType, &visitor)) {
PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", ctorType->tp_name, myType->tp_name);
return false;
}
@@ -748,7 +767,7 @@ introduceWrapperType(PyObject *enclosingObject,
ObjectDestructor cppObjDtor,
SbkObjectType *baseType,
PyObject *baseTypes,
- bool isInnerClass)
+ unsigned wrapperFlags)
{
if (baseType) {
typeSpec->slots[0].pfunc = reinterpret_cast<void *>(baseType);
@@ -773,10 +792,14 @@ introduceWrapperType(PyObject *enclosingObject,
return nullptr;
initPrivateData(type);
+ auto sotp = PepType_SOTP(type);
+ if (wrapperFlags & DeleteInMainThread)
+ sotp->delete_in_main_thread = 1;
+
setOriginalName(type, originalName);
setDestructorFunction(type, cppObjDtor);
- if (isInnerClass) {
+ if (wrapperFlags & InnerClass) {
if (PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0)
return type;
else
@@ -844,12 +867,13 @@ static void setSequenceOwnership(PyObject* pyObj, bool owner)
if (PySequence_Check(pyObj) && has_length) {
Py_ssize_t size = PySequence_Size(pyObj);
if (size > 0) {
- std::list<SbkObject*> objs = splitPyObject(pyObj);
- for (auto it = objs.begin(), end = objs.end(); it != end; ++it) {
- if (owner)
- getOwnership(*it);
- else
- releaseOwnership(*it);
+ 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)) {
@@ -885,8 +909,9 @@ void callCppDestructors(SbkObject* pyObj)
PyTypeObject *type = Py_TYPE(pyObj);
SbkObjectTypePrivate * sotp = PepType_SOTP(type);
if (sotp->is_multicpp) {
- Shiboken::DtorCallerVisitor visitor(pyObj);
+ Shiboken::DtorAccumulatorVisitor visitor(pyObj);
Shiboken::walkThroughClassHierarchy(type, &visitor);
+ callDestructor(visitor.entries());
} else {
Shiboken::ThreadStateSaver threadSaver;
threadSaver.save();
@@ -977,10 +1002,9 @@ void invalidate(SbkObject* self)
static void recursive_invalidate(PyObject* pyobj, std::set<SbkObject*>& seen)
{
- std::list<SbkObject*> objs = splitPyObject(pyobj);
- std::list<SbkObject*>::const_iterator it = objs.begin();
- for (; it != objs.end(); it++)
- recursive_invalidate(*it, seen);
+ const auto objs = splitPyObject(pyobj);
+ for (SbkObject *o : objs)
+ recursive_invalidate(o, seen);
}
static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen)
@@ -999,30 +1023,22 @@ static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen)
if (self->d->parentInfo) {
// Create a copy because this list can be changed during the process
ChildrenList copy = self->d->parentInfo->children;
- ChildrenList::iterator it = copy.begin();
- for (; it != copy.end(); ++it) {
+ for (SbkObject *child : copy) {
// invalidate the child
- recursive_invalidate(*it, seen);
+ 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(*it, true, true);
+ removeParent(child, true, true);
}
}
// If has ref to other objects invalidate all
if (self->d->referredObjects) {
RefCountMap& refCountMap = *(self->d->referredObjects);
- RefCountMap::iterator iter;
- for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter) {
- const std::list<PyObject*> lst = iter->second;
- std::list<PyObject*>::const_iterator it = lst.begin();
- while(it != lst.end()) {
- recursive_invalidate(*it, seen);
- ++it;
- }
- }
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it)
+ recursive_invalidate(it->second, seen);
}
}
@@ -1037,23 +1053,17 @@ void makeValid(SbkObject* self)
// If it is a parent make all children valid
if (self->d->parentInfo) {
- ChildrenList::iterator it = self->d->parentInfo->children.begin();
- for (; it != self->d->parentInfo->children.end(); ++it)
- makeValid(*it);
+ for (SbkObject *child : self->d->parentInfo->children)
+ makeValid(child);
}
// If has ref to other objects make all valid again
if (self->d->referredObjects) {
RefCountMap& refCountMap = *(self->d->referredObjects);
RefCountMap::iterator iter;
- for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter) {
- const std::list<PyObject*> lst = iter->second;
- std::list<PyObject*>::const_iterator it = lst.begin();
- while(it != lst.end()) {
- if (Shiboken::Object::checkType(*it))
- makeValid(reinterpret_cast<SbkObject*>(*it));
- ++it;
- }
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it) {
+ if (Shiboken::Object::checkType(it->second))
+ makeValid(reinterpret_cast<SbkObject *>(it->second));
}
}
}
@@ -1168,15 +1178,14 @@ SbkObject *findColocatedChild(SbkObject *wrapper,
ChildrenList& children = pInfo->children;
- ChildrenList::iterator childrenEnd = children.end();
- for (ChildrenList::iterator iChild = children.begin(); iChild != childrenEnd; ++iChild) {
- if (!((*iChild)->d && (*iChild)->d->cptr))
+ for (SbkObject *child : children) {
+ if (!(child->d && child->d->cptr))
continue;
- if ((*iChild)->d->cptr[0] == wrapper->d->cptr[0]) {
- if (reinterpret_cast<const void *>(Py_TYPE(*iChild)) == reinterpret_cast<const void *>(instanceType))
- return const_cast<SbkObject *>((*iChild));
+ if (child->d->cptr[0] == wrapper->d->cptr[0]) {
+ if (reinterpret_cast<const void *>(Py_TYPE(child)) == reinterpret_cast<const void *>(instanceType))
+ return child;
else
- return findColocatedChild(const_cast<SbkObject *>(*iChild), instanceType);
+ return findColocatedChild(child, instanceType);
}
}
return 0;
@@ -1435,57 +1444,56 @@ void* getTypeUserData(SbkObject* wrapper)
return PepType_SOTP(Py_TYPE(wrapper))->user_data;
}
-void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append)
+static inline bool isNone(const PyObject *o)
{
- bool isNone = (!referredObject || (referredObject == Py_None));
-
- if (!self->d->referredObjects)
- self->d->referredObjects = new Shiboken::RefCountMap;
-
- RefCountMap& refCountMap = *(self->d->referredObjects);
- RefCountMap::iterator iter = refCountMap.find(key);
- std::list<PyObject*> objects;
- if (iter != refCountMap.end()) {
- objects = (*iter).second;
- std::list<PyObject*>::const_iterator found = std::find(objects.begin(), objects.end(), referredObject);
-
- // skip if objects already exists
- if (found != objects.end())
- return;
- }
+ return o == nullptr || o == Py_None;
+}
- if (append && !isNone) {
- refCountMap[key].push_back(referredObject);
- Py_INCREF(referredObject);
- } else if (!append) {
- if (objects.size() > 0)
- decRefPyObjectList(objects, isNone ? 0 : referredObject);
- if (isNone) {
- if (iter != refCountMap.end())
- refCountMap.erase(iter);
- } else {
- objects.clear();
- objects.push_back(referredObject);
- refCountMap[key] = objects;
- Py_INCREF(referredObject);
+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 removeReference(SbkObject* self, const char* key, PyObject* referredObject)
+void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append)
{
- if (!referredObject || (referredObject == Py_None))
+ if (isNone(referredObject)) {
+ removeRefCountKey(self, key);
return;
+ }
- if (!self->d->referredObjects)
+ if (!self->d->referredObjects) {
+ self->d->referredObjects =
+ new Shiboken::RefCountMap{RefCountMap::value_type{key, referredObject}};
+ Py_INCREF(referredObject);
return;
+ }
RefCountMap& refCountMap = *(self->d->referredObjects);
- RefCountMap::iterator iter = refCountMap.find(key);
- if (iter != refCountMap.end()) {
- decRefPyObjectList(iter->second);
- refCountMap.erase(iter);
+ 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)
@@ -1494,27 +1502,27 @@ void clearReferences(SbkObject* self)
return;
RefCountMap& refCountMap = *(self->d->referredObjects);
- RefCountMap::iterator iter;
- for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter)
- decRefPyObjectList(iter->second);
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it)
+ Py_DECREF(it->second);
self->d->referredObjects->clear();
}
std::string info(SbkObject* self)
{
std::ostringstream s;
- std::list<SbkObjectType*> bases;
if (self->d && self->d->cptr) {
+ std::vector<SbkObjectType *> bases;
if (ObjectType::isUserType(Py_TYPE(self)))
bases = getCppBaseClasses(Py_TYPE(self));
else
bases.push_back(reinterpret_cast<SbkObjectType*>(Py_TYPE(self)));
s << "C++ address....... ";
- std::list<SbkObjectType*>::const_iterator it = bases.begin();
- for (int i = 0; it != bases.end(); ++it, ++i)
- s << reinterpret_cast<PyTypeObject *>(*it)->tp_name << '/' << self->d->cptr[i] << ' ';
+ for (size_t i = 0, size = bases.size(); i < size; ++i) {
+ auto base = reinterpret_cast<PyTypeObject *>(bases[i]);
+ s << base->tp_name << '/' << self->d->cptr[i] << ' ';
+ }
s << "\n";
}
else {
@@ -1535,9 +1543,8 @@ std::string info(SbkObject* self)
if (self->d->parentInfo && !self->d->parentInfo->children.empty()) {
s << "children.......... ";
- ChildrenList& children = self->d->parentInfo->children;
- for (ChildrenList::const_iterator it = children.begin(); it != children.end(); ++it) {
- Shiboken::AutoDecRef child(PyObject_Str(reinterpret_cast<PyObject *>(*it)));
+ for (SbkObject *sbkChild : self->d->parentInfo->children) {
+ Shiboken::AutoDecRef child(PyObject_Str(reinterpret_cast<PyObject *>(sbkChild)));
s << String::toCString(child) << ' ';
}
s << '\n';
@@ -1546,17 +1553,16 @@ std::string info(SbkObject* self)
if (self->d->referredObjects && !self->d->referredObjects->empty()) {
Shiboken::RefCountMap& map = *self->d->referredObjects;
s << "referred objects.. ";
- Shiboken::RefCountMap::const_iterator it = map.begin();
- for (; it != map.end(); ++it) {
- if (it != map.begin())
- s << " ";
- s << '"' << it->first << "\" => ";
- std::list<PyObject*>::const_iterator j = it->second.begin();
- for (; j != it->second.end(); ++j) {
- Shiboken::AutoDecRef obj(PyObject_Str(*j));
- s << String::toCString(obj) << ' ';
+ std::string lastKey;
+ for (auto it = map.begin(), end = map.end(); it != end; ++it) {
+ if (it->first != lastKey) {
+ if (!lastKey.empty())
+ s << " ";
+ s << '"' << it->first << "\" => ";
+ lastKey = it->first;
}
- s << ' ';
+ Shiboken::AutoDecRef obj(PyObject_Str(it->second));
+ s << String::toCString(obj) << ' ';
}
s << '\n';
}
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index 134a3bc51..65849d783 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -190,6 +190,12 @@ LIBSHIBOKEN_API void setDestructorFunction(SbkObjectType* self, ObjectDes
LIBSHIBOKEN_API void initPrivateData(SbkObjectType* self);
+enum WrapperFlags
+{
+ InnerClass = 0x1,
+ DeleteInMainThread = 0x2
+};
+
/**
* Initializes a Shiboken wrapper type and adds it to the module,
* or to the enclosing class if the type is an inner class.
@@ -215,7 +221,7 @@ LIBSHIBOKEN_API SbkObjectType *introduceWrapperType(PyObject *enclosingObject,
ObjectDestructor cppObjDtor,
SbkObjectType *baseType,
PyObject *baseTypes,
- bool isInnerClass);
+ unsigned wrapperFlags = 0);
/**
* Set the subtype init hook for a type.
diff --git a/sources/shiboken2/libshiboken/basewrapper_p.h b/sources/shiboken2/libshiboken/basewrapper_p.h
index ebd2648e7..f8a381078 100644
--- a/sources/shiboken2/libshiboken/basewrapper_p.h
+++ b/sources/shiboken2/libshiboken/basewrapper_p.h
@@ -43,10 +43,10 @@
#include "sbkpython.h"
#include "basewrapper.h"
-#include <list>
-#include <map>
+#include <unordered_map>
#include <set>
#include <string>
+#include <vector>
struct SbkObject;
struct SbkObjectType;
@@ -58,7 +58,7 @@ 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.
*/
-typedef std::map<std::string, std::list<PyObject*> > RefCountMap;
+typedef std::unordered_multimap<std::string, PyObject *> RefCountMap;
/// Linked list of SbkBaseWrapper pointers
typedef std::set<SbkObject*> ChildrenList;
@@ -137,6 +137,7 @@ struct SbkObjectTypePrivate
/// Tells is the type is a value type or an object-type, see BEHAVIOUR_* constants.
// TODO-CONVERTERS: to be deprecated/removed
int type_behaviour : 2;
+ int delete_in_main_thread : 1;
/// C++ name
char* original_name;
/// Type user data
@@ -150,10 +151,21 @@ struct SbkObjectTypePrivate
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::list<SbkObject*> splitPyObject(PyObject* pyObj);
+std::vector<SbkObject *> splitPyObject(PyObject* pyObj);
/**
* Visitor class used by walkOnClassHierarchy function.
@@ -161,81 +173,71 @@ std::list<SbkObject*> splitPyObject(PyObject* pyObj);
class HierarchyVisitor
{
public:
- HierarchyVisitor() : m_wasFinished(false) {}
- virtual ~HierarchyVisitor() {}
- virtual void visit(SbkObjectType* node) = 0;
- virtual void done() {}
- void finish() { m_wasFinished = true; };
- bool wasFinished() const { return m_wasFinished; }
-private:
- bool m_wasFinished;
+ HierarchyVisitor(const HierarchyVisitor &) = delete;
+ HierarchyVisitor(HierarchyVisitor &&) = delete;
+ HierarchyVisitor &operator=(const HierarchyVisitor &) = delete;
+ HierarchyVisitor &operator=(HierarchyVisitor &&) = delete;
+
+ HierarchyVisitor();
+ virtual ~HierarchyVisitor();
+
+ virtual bool visit(SbkObjectType *node) = 0; // return true to terminate
};
class BaseCountVisitor : public HierarchyVisitor
{
public:
- BaseCountVisitor() : m_count(0) {}
-
- void visit(SbkObjectType*)
- {
- m_count++;
- }
+ bool visit(SbkObjectType *) override;
int count() const { return m_count; }
+
private:
- int m_count;
+ int m_count = 0;
};
class BaseAccumulatorVisitor : public HierarchyVisitor
{
public:
- BaseAccumulatorVisitor() {}
+ typedef std::vector<SbkObjectType *> Result;
- void visit(SbkObjectType* node)
- {
- m_bases.push_back(node);
- }
+ bool visit(SbkObjectType *node) override;
+
+ Result bases() const { return m_bases; }
- std::list<SbkObjectType*> bases() const { return m_bases; }
private:
- std::list<SbkObjectType*> m_bases;
+ Result m_bases;
};
class GetIndexVisitor : public HierarchyVisitor
{
public:
- GetIndexVisitor(PyTypeObject* desiredType) : m_index(-1), m_desiredType(desiredType) {}
- virtual void visit(SbkObjectType* node)
- {
- m_index++;
- if (PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(node), m_desiredType))
- finish();
- }
+ explicit GetIndexVisitor(PyTypeObject* desiredType) : m_desiredType(desiredType) {}
+
+ bool visit(SbkObjectType *node) override;
+
int index() const { return m_index; }
private:
- int m_index;
- PyTypeObject* m_desiredType;
+ int m_index = -1;
+ PyTypeObject *m_desiredType;
};
-/// Call the destructor of each C++ object held by a Python object
-class DtorCallerVisitor : public HierarchyVisitor
+/// Collect destructors and C++ instances of each C++ object held by a Python
+/// object
+class DtorAccumulatorVisitor : public HierarchyVisitor
{
public:
- DtorCallerVisitor(SbkObject* pyObj) : m_pyObj(pyObj) {}
- void visit(SbkObjectType* node);
- void done();
-protected:
- std::list<std::pair<void*, SbkObjectType*> > m_ptrs;
- SbkObject* m_pyObj;
-};
+ explicit DtorAccumulatorVisitor(SbkObject *pyObj) : m_pyObject(pyObj) {}
-/// Dealloc of each C++ object held by a Python object, this implies a call to the C++ object destructor
-class DeallocVisitor : public DtorCallerVisitor
-{
-public:
- DeallocVisitor(SbkObject* pyObj) : DtorCallerVisitor(pyObj) {}
- void done();
+ bool visit(SbkObjectType *node) override;
+
+ using DestructorEntries = std::vector<DestructorEntry>;
+
+ const DestructorEntries &entries() const { return m_entries; }
+
+private:
+ DestructorEntries m_entries;
+ SbkObject *m_pyObject;
};
/// \internal Internal function used to walk on classes inheritance trees.
@@ -244,7 +246,7 @@ public:
* For each pure Shiboken type found, HiearchyVisitor::visit is called and the algorithm consider
* all children of this type as visited.
*/
-void walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor);
+bool walkThroughClassHierarchy(PyTypeObject *currentType, HierarchyVisitor *visitor);
inline int getTypeIndexOnHierarchy(PyTypeObject* baseType, PyTypeObject* desiredType)
{
@@ -260,7 +262,7 @@ inline int getNumberOfCppBaseClasses(PyTypeObject* baseType)
return visitor.count();
}
-inline std::list<SbkObjectType*> getCppBaseClasses(PyTypeObject* baseType)
+inline std::vector<SbkObjectType *> getCppBaseClasses(PyTypeObject* baseType)
{
BaseAccumulatorVisitor visitor;
walkThroughClassHierarchy(baseType, &visitor);
diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp
index 0aa520b38..8a9e912fd 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken2/libshiboken/bindingmanager.cpp
@@ -57,14 +57,12 @@ typedef std::unordered_map<const void *, SbkObject *> WrapperMap;
class Graph
{
public:
- typedef std::list<SbkObjectType*> NodeList;
+ typedef std::vector<SbkObjectType *> NodeList;
typedef std::unordered_map<SbkObjectType *, NodeList> Edges;
Edges m_edges;
- Graph()
- {
- }
+ Graph() = default;
void addEdge(SbkObjectType* from, SbkObjectType* to)
{
@@ -78,14 +76,13 @@ public:
file << "digraph D {\n";
- Edges::const_iterator i = m_edges.begin();
- for (; i != m_edges.end(); ++i) {
- SbkObjectType* node1 = i->first;
+ for (auto i = m_edges.begin(), end = m_edges.end(); i != end; ++i) {
+ auto node1 = reinterpret_cast<const PyTypeObject *>(i->first);
const NodeList& nodeList = i->second;
- NodeList::const_iterator j = nodeList.begin();
- for (; j != nodeList.end(); ++j) {
- file << '"' << reinterpret_cast<PyTypeObject *>(*j)->tp_name << "\" -> \""
- << reinterpret_cast<PyTypeObject *>(node1)->tp_name << "\"\n";
+ for (const SbkObjectType *o : nodeList) {
+ auto node2 = reinterpret_cast<const PyTypeObject *>(o);
+ file << '"' << node2->tp_name << "\" -> \""
+ << node1->tp_name << "\"\n";
}
}
file << "}\n";
@@ -97,9 +94,8 @@ public:
Edges::const_iterator edgesIt = m_edges.find(type);
if (edgesIt != m_edges.end()) {
const NodeList& adjNodes = m_edges.find(type)->second;
- NodeList::const_iterator i = adjNodes.begin();
- for (; i != adjNodes.end(); ++i) {
- SbkObjectType* newType = identifyType(cptr, *i, baseType);
+ for (SbkObjectType *node : adjNodes) {
+ SbkObjectType* newType = identifyType(cptr, node, baseType);
if (newType)
return newType;
}
@@ -115,9 +111,8 @@ public:
if (typeFound != type)
*cptr = typeFound;
return type;
- } else {
- return nullptr;
}
+ return nullptr;
}
};
@@ -128,10 +123,9 @@ static void showWrapperMap(const WrapperMap& wrapperMap)
if (Py_VerboseFlag > 0) {
fprintf(stderr, "-------------------------------\n");
fprintf(stderr, "WrapperMap: %p (size: %d)\n", &wrapperMap, (int) wrapperMap.size());
- WrapperMap::const_iterator iter;
- for (iter = wrapperMap.begin(); iter != wrapperMap.end(); ++iter) {
- const SbkObject *sbkObj = iter->second;
- fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", iter->first,
+ for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) {
+ const SbkObject *sbkObj = it->second;
+ fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", it->first,
static_cast<const void *>(sbkObj),
(Py_TYPE(sbkObj))->tp_name,
int(reinterpret_cast<const PyObject *>(sbkObj)->ob_refcnt));
@@ -142,8 +136,11 @@ static void showWrapperMap(const WrapperMap& wrapperMap)
#endif
struct BindingManager::BindingManagerPrivate {
+ using DestructorEntries = std::vector<DestructorEntry>;
+
WrapperMap wrapperMapper;
Graph classHierarchy;
+ DestructorEntries deleteInMainThread;
bool destroying;
BindingManagerPrivate() : destroying(false) {}
@@ -255,6 +252,18 @@ void BindingManager::releaseWrapper(SbkObject* sbkObj)
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)
{
WrapperMap::iterator iter = m_d->wrapperMapper.find(cptr);
diff --git a/sources/shiboken2/libshiboken/bindingmanager.h b/sources/shiboken2/libshiboken/bindingmanager.h
index 13a4d3a2e..d03aa999a 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.h
+++ b/sources/shiboken2/libshiboken/bindingmanager.h
@@ -50,11 +50,18 @@ struct SbkObjectType;
namespace Shiboken
{
+struct DestructorEntry;
+
typedef void (*ObjectVisitor)(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);
@@ -62,6 +69,9 @@ public:
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, const char* methodName);
@@ -94,10 +104,7 @@ public:
private:
~BindingManager();
- // disable copy
BindingManager();
- BindingManager(const BindingManager&);
- BindingManager& operator=(const BindingManager&);
struct BindingManagerPrivate;
BindingManagerPrivate* m_d;
diff --git a/sources/shiboken2/libshiboken/gilstate.h b/sources/shiboken2/libshiboken/gilstate.h
index 00b049802..9da4871d1 100644
--- a/sources/shiboken2/libshiboken/gilstate.h
+++ b/sources/shiboken2/libshiboken/gilstate.h
@@ -49,6 +49,11 @@ 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();
diff --git a/sources/shiboken2/libshiboken/helper.cpp b/sources/shiboken2/libshiboken/helper.cpp
index 472924723..e42daff07 100644
--- a/sources/shiboken2/libshiboken/helper.cpp
+++ b/sources/shiboken2/libshiboken/helper.cpp
@@ -41,6 +41,12 @@
#include "sbkstring.h"
#include <stdarg.h>
+#ifdef _WIN32
+# include <windows.h>
+#else
+# include <pthread.h>
+#endif
+
namespace Shiboken
{
@@ -141,4 +147,24 @@ int warning(PyObject* category, int stacklevel, const char* format, ...)
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;
+}
+
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/helper.h b/sources/shiboken2/libshiboken/helper.h
index b215142c7..9b6d8903f 100644
--- a/sources/shiboken2/libshiboken/helper.h
+++ b/sources/shiboken2/libshiboken/helper.h
@@ -77,7 +77,12 @@ template<class T>
class AutoArrayPointer
{
public:
- AutoArrayPointer(int size) { data = new T[size]; }
+ AutoArrayPointer(const AutoArrayPointer&) = delete;
+ AutoArrayPointer(AutoArrayPointer&&) = delete;
+ AutoArrayPointer& operator=(const AutoArrayPointer&) = delete;
+ AutoArrayPointer& operator=(AutoArrayPointer&&) = delete;
+
+ explicit AutoArrayPointer(int size) { data = new T[size]; }
T& operator[](int pos) { return data[pos]; }
operator T*() const { return data; }
~AutoArrayPointer() { delete[] data; }
@@ -85,6 +90,10 @@ class AutoArrayPointer
T* data;
};
+typedef unsigned long long ThreadId;
+LIBSHIBOKEN_API ThreadId currentThreadId();
+LIBSHIBOKEN_API ThreadId mainThreadId();
+
/**
* An utility function used to call PyErr_WarnEx with a formatted message.
*/
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
index 0baf6ed42..869d09529 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -398,7 +398,10 @@ PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
return ret;
}
+#endif // Py_LIMITED_API
+
// This is only a simple local helper that returns a computed variable.
+// Used also in Python 2.
static PyObject *
PepRun_GetResult(const char *command, const char *resvar)
{
@@ -415,6 +418,8 @@ PepRun_GetResult(const char *command, const char *resvar)
return res;
}
+#ifdef Py_LIMITED_API
+
/*****************************************************************************
*
* Support for classobject.h
@@ -499,13 +504,26 @@ PyTypeObject *PepStaticMethod_TypePtr = NULL;
static PyTypeObject *getStaticMethodType(void)
{
+ // this works for Python 3, only
+ // "StaticMethodType = type(str.__dict__['maketrans'])\n";
static const char prog[] =
- "StaticMethodType = type(str.__dict__['maketrans'])\n";
- return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethodType");
+ "from xxsubtype import spamlist\n"
+ "StaticMethod_Type = type(spamlist.__dict__['staticmeth'])\n";
+ return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethod_Type");
}
-
#endif // Py_LIMITED_API
+#if PY_VERSION_HEX < 0x03000000
+PyTypeObject *PepMethodDescr_TypePtr = NULL;
+
+static PyTypeObject *getMethodDescrType(void)
+{
+ static const char prog[] =
+ "MethodDescr_Type = type(str.split)\n";
+ return (PyTypeObject *) PepRun_GetResult(prog, "MethodDescr_Type");
+}
+#endif
+
/*****************************************************************************
*
* Common newly needed functions
@@ -630,6 +648,9 @@ Pep384_Init()
PepFunction_TypePtr = getFunctionType();
PepStaticMethod_TypePtr = getStaticMethodType();
#endif
+#if PY_VERSION_HEX < 0x03000000
+ PepMethodDescr_TypePtr = getMethodDescrType();
+#endif
}
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h
index b566a6218..6649fa95e 100644
--- a/sources/shiboken2/libshiboken/pep384impl.h
+++ b/sources/shiboken2/libshiboken/pep384impl.h
@@ -286,7 +286,7 @@ LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject *
// But this is no problem as we check it's validity for every version.
#define PYTHON_BUFFER_VERSION_COMPATIBLE (PY_VERSION_HEX >= 0x03030000 && \
- PY_VERSION_HEX < 0X0307FFFF)
+ PY_VERSION_HEX < 0x0307FFFF)
#if !PYTHON_BUFFER_VERSION_COMPATIBLE
# error Please check the buffer compatibility for this python version!
#endif
@@ -470,6 +470,12 @@ extern LIBSHIBOKEN_API PyTypeObject *PepStaticMethod_TypePtr;
#else
#define PepStaticMethod_TypePtr &PyStaticMethod_Type
#endif
+// Although not PEP specific, we resolve this similar issue, here:
+#if PY_VERSION_HEX < 0x03000000
+extern LIBSHIBOKEN_API PyTypeObject *PepMethodDescr_TypePtr;
+#else
+#define PepMethodDescr_TypePtr &PyMethodDescr_Type
+#endif
/*****************************************************************************
*
diff --git a/sources/shiboken2/libshiboken/sbkconverter.cpp b/sources/shiboken2/libshiboken/sbkconverter.cpp
index a13222de6..65844151f 100644
--- a/sources/shiboken2/libshiboken/sbkconverter.cpp
+++ b/sources/shiboken2/libshiboken/sbkconverter.cpp
@@ -246,10 +246,8 @@ PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType *type, PyObject *p
static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn)
{
assert(pyIn);
- const ToCppConversionList& convs = converter->toCppConversions;
- for (ToCppConversionList::const_iterator conv = convs.begin(), end = convs.end(); conv != end; ++conv) {
- PythonToCppFunc toCppFunc = 0;
- if ((toCppFunc = (*conv).first(pyIn)))
+ for (const ToCppConversion &c : converter->toCppConversions) {
+ if (PythonToCppFunc toCppFunc = c.first(pyIn))
return toCppFunc;
}
return 0;
@@ -361,7 +359,7 @@ bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCppFunc)
// 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.
- ToCppConversionList::iterator conv = PepType_SOTP(type)->converter->toCppConversions.begin();
+ const auto conv = PepType_SOTP(type)->converter->toCppConversions.cbegin();
return toCppFunc != (*conv).second;
}
diff --git a/sources/shiboken2/libshiboken/sbkconverter_p.h b/sources/shiboken2/libshiboken/sbkconverter_p.h
index f39608663..a4edfe81e 100644
--- a/sources/shiboken2/libshiboken/sbkconverter_p.h
+++ b/sources/shiboken2/libshiboken/sbkconverter_p.h
@@ -43,11 +43,11 @@
#include "sbkpython.h"
#include "sbkconverter.h"
#include "sbkstring.h"
-#include <list>
#include <limits>
#include <typeinfo>
#include <sstream>
#include <iostream>
+#include <vector>
#include "sbkdbg.h"
@@ -55,7 +55,7 @@ extern "C"
{
typedef std::pair<IsConvertibleToCppFunc, PythonToCppFunc> ToCppConversion;
-typedef std::list<ToCppConversion> ToCppConversionList;
+typedef std::vector<ToCppConversion> ToCppConversionVector;
/**
* \internal
@@ -104,7 +104,7 @@ struct SbkConverter
* For Object Types, that never have implicit conversions, this
* list is always empty.
*/
- ToCppConversionList toCppConversions;
+ ToCppConversionVector toCppConversions;
};
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/sbkdbg.h b/sources/shiboken2/libshiboken/sbkdbg.h
index c26816bbd..fdaf2a27a 100644
--- a/sources/shiboken2/libshiboken/sbkdbg.h
+++ b/sources/shiboken2/libshiboken/sbkdbg.h
@@ -63,6 +63,11 @@
class BaseLogger
{
public:
+ BaseLogger(const BaseLogger&) = delete;
+ BaseLogger(BaseLogger&&) = delete;
+ BaseLogger& operator=(const BaseLogger&) = delete;
+ BaseLogger& operator=(BaseLogger&&) = delete;
+
BaseLogger(std::ostream& output, const char* function, const char* context)
: m_stream(output), m_function(function), m_context(context) {}
~BaseLogger()
diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp
index d129e6380..3c6582adc 100644
--- a/sources/shiboken2/libshiboken/sbkenum.cpp
+++ b/sources/shiboken2/libshiboken/sbkenum.cpp
@@ -47,7 +47,7 @@
#include <string.h>
#include <cstring>
-#include <list>
+#include <vector>
#define SBK_ENUM(ENUM) reinterpret_cast<SbkEnumObject*>(ENUM)
@@ -339,15 +339,18 @@ namespace Shiboken {
class DeclaredEnumTypes
{
public:
+ DeclaredEnumTypes(const DeclaredEnumTypes&) = delete;
+ DeclaredEnumTypes(DeclaredEnumTypes&&) = delete;
+ DeclaredEnumTypes& operator=(const DeclaredEnumTypes&) = delete;
+ DeclaredEnumTypes& operator=(DeclaredEnumTypes&&) = delete;
+
DeclaredEnumTypes();
~DeclaredEnumTypes();
static DeclaredEnumTypes& instance();
void addEnumType(PyTypeObject* type);
private:
- DeclaredEnumTypes(const DeclaredEnumTypes&);
- DeclaredEnumTypes& operator=(const DeclaredEnumTypes&);
- std::list<PyTypeObject*> m_enumTypes;
+ std::vector<PyTypeObject *> m_enumTypes;
};
namespace Enum {
@@ -373,7 +376,9 @@ PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue)
return 0;
}
-static PyTypeObject* createEnum(const char* fullName, const char* cppName, const char* shortName, PyTypeObject* flagsType)
+static PyTypeObject* createEnum(const char* fullName, const char* cppName,
+ const char* /* shortName */,
+ PyTypeObject* flagsType)
{
PyTypeObject* enumType = newTypeWithName(fullName, cppName, flagsType);
if (PyType_Ready(enumType) < 0)
@@ -524,13 +529,8 @@ copyNumberMethods(PyTypeObject *flagsType,
int *pidx)
{
int idx = *pidx;
-#ifdef IS_PY3K
-# define SLOT slot
-#else
-# define SLOT slot_
-#endif
#define PUT_SLOT(name) \
- number_slots[idx].SLOT = (name); \
+ number_slots[idx].slot = (name); \
number_slots[idx].pfunc = PyType_GetSlot(flagsType, (name)); \
++idx;
@@ -593,8 +593,8 @@ newTypeWithName(const char* name,
newspec->flags = SbkNewType_spec.flags;
// we must append all the number methods, so rebuild everything:
int idx = 0;
- while (SbkNewType_slots[idx].SLOT) {
- newslots[idx].SLOT = SbkNewType_slots[idx].SLOT;
+ while (SbkNewType_slots[idx].slot) {
+ newslots[idx].slot = SbkNewType_slots[idx].slot;
newslots[idx].pfunc = SbkNewType_slots[idx].pfunc;
++idx;
}
@@ -644,14 +644,10 @@ DeclaredEnumTypes& DeclaredEnumTypes::instance()
return me;
}
-DeclaredEnumTypes::DeclaredEnumTypes()
-{
-}
+DeclaredEnumTypes::DeclaredEnumTypes() = default;
DeclaredEnumTypes::~DeclaredEnumTypes()
{
- std::list<PyTypeObject*>::const_iterator it = m_enumTypes.begin();
- for (; it != m_enumTypes.end(); ++it) {
/*
* PYSIDE-595: This was "delete *it;" before introducing 'PyType_FromSpec'.
* XXX what should I do now?
@@ -660,8 +656,8 @@ DeclaredEnumTypes::~DeclaredEnumTypes()
* So right now I am doing nothing. Surely wrong but no crash.
* See also the comment in function 'createGlobalEnumItem'.
*/
- //fprintf(stderr, "ttt %d %s\n", Py_REFCNT(*it), *it->tp_name);
- }
+ // for (PyTypeObject *o : m_enumTypes)
+ // fprintf(stderr, "ttt %d %s\n", Py_REFCNT(o), o->tp_name);
m_enumTypes.clear();
}
diff --git a/sources/shiboken2/libshiboken/sbkpython.h b/sources/shiboken2/libshiboken/sbkpython.h
index 29e25605a..f06b0b19e 100644
--- a/sources/shiboken2/libshiboken/sbkpython.h
+++ b/sources/shiboken2/libshiboken/sbkpython.h
@@ -42,19 +42,65 @@
#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" {
-#include <Python.h>
+/*
+ * 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>
+# include <structmember.h>
// Now we have the usual variables from Python.h .
-#include "python25compat.h"
-#include "shibokenmacros.h"
-#include "pep384impl.h"
-#include "typespec.h"
+# include "python25compat.h"
+# include "shibokenmacros.h"
+# include "pep384impl.h"
+# include "typespec.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 "python25compat.h"
+# include "shibokenmacros.h"
+# include "pep384impl.h"
+# include "typespec.h"
+#endif
#if PY_MAJOR_VERSION >= 3
#define IS_PY3K
diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp
index 6ca35f12e..a3ffcdabb 100644
--- a/sources/shiboken2/libshiboken/sbkstring.cpp
+++ b/sources/shiboken2/libshiboken/sbkstring.cpp
@@ -66,10 +66,7 @@ bool check(PyObject* obj)
bool checkChar(PyObject* pyobj)
{
- if (check(pyobj) && (len(pyobj) == 1))
- return true;
-
- return false;
+ return check(pyobj) && (len(pyobj) == 1);
}
bool isConvertible(PyObject* obj)
diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
index dc29b40a7..a691a31ee 100644
--- a/sources/shiboken2/libshiboken/shibokenbuffer.cpp
+++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
@@ -58,6 +58,7 @@ void* Shiboken::Buffer::getPointer(PyObject* pyObj, Py_ssize_t* size)
PyBuffer_Release(&view);
return view.buf;
}
+ return nullptr;
#else
Py_ssize_t bufferSize = 0;
@@ -85,7 +86,8 @@ PyObject* Shiboken::Buffer::newObject(void* memory, Py_ssize_t size, Type type)
view.shape = shape;
// Pep384: This is way too complicated and impossible with the limited api:
//return PyMemoryView_FromBuffer(&view);
- return PyMemoryView_FromMemory((char *)view.buf, size, type == ReadOnly ? PyBUF_READ : PyBUF_WRITE);
+ return PyMemoryView_FromMemory(reinterpret_cast<char *>(view.buf),
+ size, type == ReadOnly ? PyBUF_READ : PyBUF_WRITE);
#else
return type == ReadOnly ? PyBuffer_FromMemory(memory, size) : PyBuffer_FromReadWriteMemory(memory, size);
#endif
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index f0bb8e609..24d60acc4 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -77,18 +77,23 @@ typedef struct safe_globals_struc {
static safe_globals pyside_globals = 0;
-static PyObject *GetSignature_Function(PyCFunctionObject *);
-static PyObject *GetSignature_TypeMod(PyObject *);
+static PyObject *GetSignature_Function(PyCFunctionObject *, const char *);
+static PyObject *GetSignature_TypeMod(PyObject *, const char *);
+static PyObject *GetSignature_Wrapper(PyObject *, const char *);
+static PyObject *get_signature(PyObject *self, PyObject *args);
static PyObject *PySide_BuildSignatureProps(PyObject *class_mod);
+static void init_module_1(void);
+static void init_module_2(void);
+
const char helper_module_name[] = "signature_loader";
const char bootstrap_name[] = "bootstrap";
const char arg_name[] = "pyside_arg_dict";
const char func_name[] = "pyside_type_init";
static PyObject *
-CreateSignature(PyObject *props, const char *sig_kind)
+CreateSignature(PyObject *props, PyObject *key)
{
/*
* Here is the new function to create all signatures. It simply calls
@@ -97,22 +102,22 @@ CreateSignature(PyObject *props, const char *sig_kind)
* to support '_signature_is_functionlike()'.
*/
return PyObject_CallFunction(pyside_globals->createsig_func,
- (char *)"(Os)", props, sig_kind);
+ (char *)"(OO)", props, key);
}
static PyObject *
-pyside_cf_get___signature__(PyObject *func)
+pyside_cf_get___signature__(PyObject *func, const char *modifier)
{
- return GetSignature_Function((PyCFunctionObject *)func);
+ return GetSignature_Function((PyCFunctionObject *)func, modifier);
}
static PyObject *
-pyside_sm_get___signature__(PyObject *sm)
+pyside_sm_get___signature__(PyObject *sm, const char *modifier)
{
PyObject *func, *ret;
func = PyObject_GetAttrString(sm, "__func__");
- ret = GetSignature_Function((PyCFunctionObject *)func);
+ ret = GetSignature_Function((PyCFunctionObject *)func, modifier);
Py_XDECREF(func);
return ret;
}
@@ -192,7 +197,7 @@ qualname_to_func(PyObject *ob)
#endif
static PyObject *
-pyside_md_get___signature__(PyObject *ob)
+pyside_md_get___signature__(PyObject *ob, const char *modifier)
{
PyObject *func;
PyObject *result;
@@ -218,21 +223,31 @@ pyside_md_get___signature__(PyObject *ob)
return Py_None;
if (func == NULL)
Py_FatalError("missing mapping in MethodDescriptor");
- result = pyside_cf_get___signature__(func);
+ result = pyside_cf_get___signature__(func, modifier);
Py_DECREF(func);
return result;
}
static PyObject *
-pyside_tp_get___signature__(PyObject *typemod)
+pyside_wd_get___signature__(PyObject *ob, const char *modifier)
+{
+ return GetSignature_Wrapper(ob, modifier);
+}
+
+static PyObject *
+pyside_tp_get___signature__(PyObject *typemod, const char *modifier)
{
- return GetSignature_TypeMod(typemod);
+ return GetSignature_TypeMod(typemod, modifier);
}
+// forward
+static PyObject *
+GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier);
+
static PyObject *
-GetSignature_Function(PyCFunctionObject *func)
+GetSignature_Function(PyCFunctionObject *func, const char *modifier)
{
- PyObject *typemod, *type_name, *dict, *props, *value, *selftype;
+ PyObject *typemod, *type_name, *dict, *props, *selftype;
PyObject *func_name = PyObject_GetAttrString((PyObject *)func, "__name__");
const char *sig_kind;
int flags;
@@ -241,12 +256,8 @@ GetSignature_Function(PyCFunctionObject *func)
if (selftype == NULL)
selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)func);
if (selftype == NULL) {
- if (!PyErr_Occurred()) {
- PyErr_Format(PyExc_SystemError,
- "the signature for \"%s\" should exist",
- PepCFunction_GET_NAMESTR(func)
- );
- }
+ if (!PyErr_Occurred())
+ Py_RETURN_NONE;
return NULL;
}
if ((PyType_Check(selftype) || PyModule_Check(selftype)))
@@ -279,24 +290,46 @@ GetSignature_Function(PyCFunctionObject *func)
sig_kind = "staticmethod";
else
sig_kind = "method";
- value = PyDict_GetItemString(props, sig_kind);
- if (value == NULL) {
- // we need to compute a signature object
- value = CreateSignature(props, sig_kind);
- if (value != NULL) {
- if (PyDict_SetItemString(props, sig_kind, value) < 0)
- return NULL;
- }
- else
+ return GetSignature_Cached(props, sig_kind, modifier);
+}
+
+static PyObject *
+GetSignature_Wrapper(PyObject *ob, const char *modifier)
+{
+ PyObject *dict, *props;
+ PyObject *func_name = PyObject_GetAttrString(ob, "__name__");
+ PyObject *objclass = PyObject_GetAttrString(ob, "__objclass__");
+ PyObject *class_name = PyObject_GetAttrString(objclass, "__name__");
+ const char *sig_kind;
+
+ if (func_name == nullptr || objclass == nullptr || class_name == nullptr)
+ return nullptr;
+ dict = PyDict_GetItem(pyside_globals->arg_dict, class_name);
+ if (dict == NULL)
+ Py_RETURN_NONE;
+ if (PyTuple_Check(dict)) {
+ /*
+ * We do the initialization lazily.
+ * This has also the advantage that we can freely import PySide.
+ */
+ dict = PySide_BuildSignatureProps(objclass);
+ if (dict == NULL)
Py_RETURN_NONE;
}
- return Py_INCREF(value), value;
+ props = PyDict_GetItem(dict, func_name);
+ Py_DECREF(func_name);
+ Py_DECREF(objclass);
+ Py_DECREF(class_name);
+ if (props == NULL)
+ Py_RETURN_NONE;
+ sig_kind = "method";
+ return GetSignature_Cached(props, sig_kind, modifier);
}
static PyObject *
-GetSignature_TypeMod(PyObject *ob)
+GetSignature_TypeMod(PyObject *ob, const char *modifier)
{
- PyObject *ob_name, *dict, *props, *value;
+ PyObject *ob_name, *dict, *props;
const char *sig_kind;
ob_name = PyObject_GetAttrString(ob, "__name__");
@@ -314,37 +347,62 @@ GetSignature_TypeMod(PyObject *ob)
if (props == NULL)
Py_RETURN_NONE;
sig_kind = "method";
- value = PyDict_GetItemString(props, sig_kind);
- if (value == NULL) {
+ return GetSignature_Cached(props, sig_kind, modifier);
+}
+
+static PyObject *
+GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier)
+{
+ PyObject *key, *value;
+
+ if (modifier == nullptr)
+ key = Py_BuildValue("s", sig_kind);
+ else
+ key = Py_BuildValue("(ss)", sig_kind, modifier);
+ if (key == nullptr)
+ return nullptr;
+ value = PyDict_GetItem(props, key);
+ if (value == nullptr) {
// we need to compute a signature object
- value = CreateSignature(props, sig_kind);
- if (value != NULL) {
- if (PyDict_SetItemString(props, sig_kind, value) < 0)
- return NULL;
+ value = CreateSignature(props, key);
+ if (value != nullptr) {
+ if (PyDict_SetItem(props, key, value) < 0) {
+ // this is an error
+ Py_DECREF(key);
+ return nullptr;
+ }
}
- else
+ else {
+ // key not found
+ Py_DECREF(key);
Py_RETURN_NONE;
+ }
}
return Py_INCREF(value), value;
}
-
static const char PySide_PythonCode[] =
- "from __future__ import print_function, absolute_import\n"
- "import sys, os, traceback\n"
-
- "pyside_package_dir = os.environ.get('PYSIDE_PACKAGE_DIR', '.')\n"
- "__file__ = os.path.join(pyside_package_dir, 'support', 'signature', 'loader.py')\n"
-
- "def bootstrap():\n"
- " try:\n"
- " with open(__file__) as _f:\n"
- " exec(compile(_f.read(), __file__, 'exec'))\n"
- " except Exception as e:\n"
- " print('Exception:', e)\n"
- " traceback.print_exc(file=sys.stdout)\n"
- " globals().update(locals())\n"
- ;
+ "from __future__ import print_function, absolute_import\n" R"~(if True:
+
+ import sys, os, traceback
+
+ pyside_package_dir = os.environ.get('PYSIDE_PACKAGE_DIR')
+ if pyside_package_dir is None:
+ # This happens in shiboken running ctest.
+ from distutils.sysconfig import get_python_lib
+ pyside_package_dir = os.path.join(get_python_lib(), 'PySide2')
+ __file__ = os.path.join(pyside_package_dir, 'support', 'signature', 'loader.py')
+
+ def bootstrap():
+ try:
+ with open(__file__) as _f:
+ exec(compile(_f.read(), __file__, 'exec'))
+ except Exception as e:
+ print('Exception:', e)
+ traceback.print_exc(file=sys.stdout)
+ globals().update(locals())
+
+ )~";
static safe_globals_struc *
init_phase_1(void)
@@ -387,9 +445,10 @@ error:
}
static int
-init_phase_2(safe_globals_struc *p)
+init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
{
- PyObject *bootstrap_func;
+ PyObject *bootstrap_func, *v = nullptr;
+ PyMethodDef *ml;
bootstrap_func = PyObject_GetAttrString(p->helper_module, bootstrap_name);
if (bootstrap_func == NULL)
@@ -403,9 +462,22 @@ init_phase_2(safe_globals_struc *p)
p->createsig_func = PyObject_GetAttrString(p->helper_module, "create_signature");
if (p->createsig_func == NULL)
goto error;
+
+ // The single function to be called, but maybe more to come.
+ for (ml = methods; ml->ml_name != NULL; ml++) {
+ v = PyCFunction_NewEx(ml, nullptr, nullptr);
+ if (v == nullptr) {
+ goto error;
+ }
+ if (PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0) {
+ goto error;
+ }
+ Py_DECREF(v);
+ }
return 0;
error:
+ Py_XDECREF(v);
PyErr_SetString(PyExc_SystemError, "could not initialize part 2");
return -1;
}
@@ -413,8 +485,11 @@ error:
static int
add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp)
{
- PyObject *dict = type->tp_dict;
+ PyObject *dict;
+ assert(PyType_Check(type));
+ PyType_Ready(type);
+ dict = type->tp_dict;
for (; gsp->name != NULL; gsp++) {
PyObject *descr;
if (PyDict_GetItemString(dict, gsp->name))
@@ -463,6 +538,45 @@ static PyGetSetDef new_PyType_getsets[] = {
{0}
};
+static PyGetSetDef new_PyWrapperDescr_getsets[] = {
+ {(char *) "__signature__", (getter)pyside_wd_get___signature__},
+ {0}
+};
+
+////////////////////////////////////////////////////////////////////////////
+//
+// get_signature -- providing a superior interface
+//
+// Additionally 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.
+//
+
+static PyObject *
+get_signature(PyObject *self, PyObject *args)
+{
+ PyObject *ob;
+ const char *modifier = nullptr;
+
+ init_module_1();
+ init_module_2();
+
+ if (!PyArg_ParseTuple(args, "O|s", &ob, &modifier))
+ return NULL;
+ if (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);
+ Py_RETURN_NONE;
+}
+
////////////////////////////////////////////////////////////////////////////
//
// This special Type_Ready does certain initializations earlier with
@@ -497,23 +611,23 @@ void handler(int sig) {
static int
PySideType_Ready(PyTypeObject *type)
{
- PyObject *md;
+ PyObject *md, *wd;
static int init_done = 0;
if (!init_done) {
- // Python2 does not expose certain types. We look them up:
- // PyMethodDescr_Type 'type(str.__dict__["split"])'
- // PyClassMethodDescr_Type. 'type(dict.__dict__["fromkeys"])'
- // The latter is not needed until we use class methods in PySide.
- md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split");
- if (md == NULL
+ md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split"); // method-descriptor
+ wd = PyObject_GetAttrString((PyObject *)Py_TYPE(Py_True), "__add__"); // wrapper-descriptor
+ if (md == nullptr || wd == nullptr
|| PyType_Ready(Py_TYPE(md)) < 0
- || add_more_getsets(Py_TYPE(md), new_PyMethodDescr_getsets) < 0
+ || add_more_getsets(PepMethodDescr_TypePtr, new_PyMethodDescr_getsets) < 0
|| add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets) < 0
|| add_more_getsets(PepStaticMethod_TypePtr, new_PyStaticMethod_getsets) < 0
- || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0)
+ || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0
+ || add_more_getsets(Py_TYPE(wd), new_PyWrapperDescr_getsets) < 0
+ )
return -1;
Py_DECREF(md);
+ Py_DECREF(wd);
#ifndef _WIN32
// We enable the stack trace in CI, only.
const char *testEnv = getenv("QTEST_ENVIRONMENT");
@@ -550,20 +664,26 @@ build_func_to_type(PyObject *obtype)
return 0;
}
+static void
+init_module_1(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ pyside_globals = init_phase_1();
+ if (pyside_globals != nullptr)
+ init_done = 1;
+ }
+}
+
static int
PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
const char *signatures)
{
PyObject *type_name, *arg_tup;
const char *name = NULL;
- static int init_done = 0;
- if (!init_done) {
- pyside_globals = init_phase_1();
- if (pyside_globals == NULL)
- return -1;
- init_done = 1;
- }
+ init_module_1();;
arg_tup = Py_BuildValue("(Os)", type, signatures);
if (arg_tup == NULL)
return -1;
@@ -599,23 +719,34 @@ PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
return 0;
}
-static PyObject *
-PySide_BuildSignatureProps(PyObject *classmod)
+static PyMethodDef signature_methods[] = {
+ {"get_signature", (PyCFunction)get_signature, METH_VARARGS,
+ "get the __signature__, but pass an optional string parameter"},
+ {NULL, NULL}
+};
+
+static void
+init_module_2(void)
{
- PyObject *arg_tup, *dict, *type_name;
static int init_done = 0;
if (!init_done) {
- if (init_phase_2(pyside_globals) < 0)
- return NULL;
+ init_phase_2(pyside_globals, signature_methods);
init_done = 1;
}
+}
+
+static PyObject *
+PySide_BuildSignatureProps(PyObject *classmod)
+{
+ PyObject *arg_tup, *dict, *type_name;
/*
* 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.
*/
+ init_module_2();
type_name = PyObject_GetAttrString(classmod, "__name__");
if (type_name == NULL)
return NULL;
diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h
index 3a229cb5c..b65317662 100644
--- a/sources/shiboken2/libshiboken/signature.h
+++ b/sources/shiboken2/libshiboken/signature.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -45,8 +45,8 @@
extern "C"
{
-LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char*);
-LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char*);
+LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char *); //WS
+LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *);
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/threadstatesaver.h b/sources/shiboken2/libshiboken/threadstatesaver.h
index e9f97f300..ddad9b67f 100644
--- a/sources/shiboken2/libshiboken/threadstatesaver.h
+++ b/sources/shiboken2/libshiboken/threadstatesaver.h
@@ -49,15 +49,17 @@ 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;
-
- ThreadStateSaver(const ThreadStateSaver&);
- ThreadStateSaver& operator=(const ThreadStateSaver&);
};
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/typespec.cpp b/sources/shiboken2/libshiboken/typespec.cpp
index d532c97ed..a67daf12d 100644
--- a/sources/shiboken2/libshiboken/typespec.cpp
+++ b/sources/shiboken2/libshiboken/typespec.cpp
@@ -37,6 +37,7 @@
**
****************************************************************************/
+#include "sbkpython.h"
#include "typespec.h"
#include <structmember.h>
@@ -514,7 +515,7 @@ best_base(PyObject *bases)
}
static const short slotoffsets[] = {
- -1, /* invalid slot_ */
+ -1, /* invalid slot */
/* Generated by typeslots.py */
0,
0,
@@ -603,7 +604,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
PyObject *modname;
char *s;
char *res_start = (char*)res;
- PyType_Slot *slot_;
+ PyType_Slot *slot;
/* Set the type name and qualname */
s = (char *)strrchr(spec->name, '.'); // C++11
@@ -632,11 +633,11 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *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 = (PyTypeObject *)slot_->pfunc; // C++11
- else if (slot_->slot_ == Py_tp_bases) {
- bases = (PyObject *)slot_->pfunc; // C++11
+ for (slot = spec->slots; slot->slot; slot++) {
+ if (slot->slot == Py_tp_base)
+ base = (PyTypeObject *)slot->pfunc; // C++11
+ else if (slot->slot == Py_tp_bases) {
+ bases = (PyObject *)slot->pfunc; // C++11
Py_INCREF(bases);
}
}
@@ -676,23 +677,23 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
type->tp_basicsize = spec->basicsize;
type->tp_itemsize = spec->itemsize;
- for (slot_ = spec->slots; slot_->slot_; slot_++) {
- if (slot_->slot_ < 0
- || (size_t)slot_->slot_ >= Py_ARRAY_LENGTH(slotoffsets)) {
- PyErr_SetString(PyExc_RuntimeError, "invalid slot_ offset");
+ for (slot = spec->slots; slot->slot; slot++) {
+ if (slot->slot < 0
+ || (size_t)slot->slot >= Py_ARRAY_LENGTH(slotoffsets)) {
+ PyErr_SetString(PyExc_RuntimeError, "invalid slot offset");
goto fail;
}
- if (slot_->slot_ == Py_tp_base || slot_->slot_ == Py_tp_bases)
+ if (slot->slot == Py_tp_base || slot->slot == Py_tp_bases)
/* Processed above */
continue;
- *(void**)(res_start + slotoffsets[slot_->slot_]) = slot_->pfunc;
+ *(void**)(res_start + slotoffsets[slot->slot]) = slot->pfunc;
- /* need to make a copy of the docstring slot_, which usually
+ /* need to make a copy of the docstring slot, which usually
points to a static string literal */
- if (slot_->slot_ == Py_tp_doc) {
+ if (slot->slot == Py_tp_doc) {
// No signature in Python 2
- // const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot_->pfunc);
- const char *old_doc = (const char *)slot_->pfunc;
+ // const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot->pfunc);
+ const char *old_doc = (const char *)slot->pfunc;
size_t len = strlen(old_doc)+1;
char *tp_doc = (char *)PyObject_MALLOC(len); // C++11
if (tp_doc == NULL) {
@@ -759,17 +760,17 @@ PyType_FromSpec(PyType_Spec *spec)
}
void *
-PyType_GetSlot(PyTypeObject *type, int slot_)
+PyType_GetSlot(PyTypeObject *type, int slot)
{
- if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot_ < 0) {
+ if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot < 0) {
PyErr_BadInternalCall();
return NULL;
}
- if ((size_t)slot_ >= Py_ARRAY_LENGTH(slotoffsets)) {
- /* Extension module requesting slot_ from a future version */
+ if ((size_t)slot >= Py_ARRAY_LENGTH(slotoffsets)) {
+ /* Extension module requesting slot from a future version */
return NULL;
}
- return *(void**)(((char*)type) + slotoffsets[slot_]);
+ return *(void**)(((char*)type) + slotoffsets[slot]);
}
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/typespec.h b/sources/shiboken2/libshiboken/typespec.h
index 799fcb1b8..81227acac 100644
--- a/sources/shiboken2/libshiboken/typespec.h
+++ b/sources/shiboken2/libshiboken/typespec.h
@@ -40,7 +40,7 @@
#ifndef TYPESPEC_H
#define TYPESPEC_H
-#include <Python.h>
+#include "sbkpython.h"
#include "shibokenmacros.h"
#if PY_MAJOR_VERSION < 3
@@ -48,7 +48,7 @@ extern "C"
{
typedef struct{
- int slot_; // slot is somehow reserved in Qt /* slot id, see below */
+ int slot; // slot is somehow reserved in Qt /* slot id, see below */
void *pfunc; /* function pointer */
} PyType_Slot;
diff --git a/sources/shiboken2/shiboken_tool.py b/sources/shiboken2/shiboken_tool.py
new file mode 100755
index 000000000..8494c5d57
--- /dev/null
+++ b/sources/shiboken2/shiboken_tool.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+import sys
+import os
+import subprocess
+
+def main():
+ # The tools listed as entrypoints in setup.py are copied to 'scripts/..'
+ cmd = os.path.join("..", os.path.basename(sys.argv[0]))
+ command = [os.path.join(os.path.dirname(os.path.realpath(__file__)), cmd)]
+ command.extend(sys.argv[1:])
+ sys.exit(subprocess.call(command))
+
+if __name__ == "__main__":
+ main()
diff --git a/sources/shiboken2/shiboken_version.py b/sources/shiboken2/shiboken_version.py
index 789812464..a883bab96 100644
--- a/sources/shiboken2/shiboken_version.py
+++ b/sources/shiboken2/shiboken_version.py
@@ -38,16 +38,10 @@
#############################################################################
major_version = "5"
-minor_version = "11"
-patch_version = "1"
-
-# For example: "a", "b", "rc"
-# (which means "alpha", "beta", "release candidate").
-# An empty string means the generated package will be an official release.
-pre_release_version_type = "a"
-
-# For example: "1", "2" (which means "beta1", "beta2", if type is "b").
-pre_release_version = "1"
+minor_version = "12"
+patch_version = "0"
+pre_release_version_type = "a" # e.g. "a", "b", "rc".
+pre_release_version = "1" # e.g "1", "2", (which means "beta1", "beta2", if type is "b")
if __name__ == '__main__':
# Used by CMake.
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index f2d7b30f2..20baf9f7e 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -12,7 +12,9 @@ set(shibokenmodule_TYPESYSTEM
${CMAKE_CURRENT_SOURCE_DIR}/typesystem_shiboken.xml
)
-add_custom_command(OUTPUT ${sample_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${sample_SRC}
# Note: shiboken2 is an executable target. By not specifying its explicit
# path, CMAKE figures it out, itself!
# This fixes an issue with Visual Studio, see https://github.com/PySide/shiboken2/pull/11
@@ -39,5 +41,26 @@ target_link_libraries(shibokenmodule
libshiboken)
add_dependencies(shibokenmodule shiboken2)
+create_generator_target(shibokenmodule)
-install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES})
+install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}/shiboken2)
+
+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}/shiboken2")
+
+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}/shiboken2")
+
+# 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}/shiboken2")
diff --git a/sources/shiboken2/shibokenmodule/__init__.py.in b/sources/shiboken2/shibokenmodule/__init__.py.in
new file mode 100644
index 000000000..81ab0063a
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/__init__.py.in
@@ -0,0 +1,4 @@
+__version__ = "@FINAL_PACKAGE_VERSION@"
+__version_info__ = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+
+from .shiboken2 import *
diff --git a/sources/shiboken2/shibokenmodule/_config.py.in b/sources/shiboken2/shibokenmodule/_config.py.in
new file mode 100644
index 000000000..9607e5ca7
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/_config.py.in
@@ -0,0 +1,11 @@
+shiboken_library_soversion = str(@shiboken2_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@
diff --git a/sources/shiboken2/tests/libsample/CMakeLists.txt b/sources/shiboken2/tests/libsample/CMakeLists.txt
index 7bbc0c3dd..ae3d40312 100644
--- a/sources/shiboken2/tests/libsample/CMakeLists.txt
+++ b/sources/shiboken2/tests/libsample/CMakeLists.txt
@@ -10,6 +10,7 @@ complex.cpp
onlycopy.cpp
derived.cpp
echo.cpp
+exceptiontest.cpp
functions.cpp
handle.cpp
implicitconv.cpp
diff --git a/sources/shiboken2/tests/libsample/exceptiontest.cpp b/sources/shiboken2/tests/libsample/exceptiontest.cpp
new file mode 100644
index 000000000..1302a8e43
--- /dev/null
+++ b/sources/shiboken2/tests/libsample/exceptiontest.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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;
+}
diff --git a/sources/shiboken2/tests/libsample/exceptiontest.h b/sources/shiboken2/tests/libsample/exceptiontest.h
new file mode 100644
index 000000000..8ab3e2b67
--- /dev/null
+++ b/sources/shiboken2/tests/libsample/exceptiontest.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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);
+};
+
+#endif // EXCEPTIONTEST_H
diff --git a/sources/shiboken2/tests/libsample/mapuser.cpp b/sources/shiboken2/tests/libsample/mapuser.cpp
index 1dbd02d26..89a835af8 100644
--- a/sources/shiboken2/tests/libsample/mapuser.cpp
+++ b/sources/shiboken2/tests/libsample/mapuser.cpp
@@ -67,3 +67,8 @@ MapUser::showMap(std::map<std::string, int> mapping)
cout << (*it).first << " => " << (*it).second << endl;
}
+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/shiboken2/tests/libsample/mapuser.h b/sources/shiboken2/tests/libsample/mapuser.h
index 9677d2df2..ad434b957 100644
--- a/sources/shiboken2/tests/libsample/mapuser.h
+++ b/sources/shiboken2/tests/libsample/mapuser.h
@@ -58,6 +58,8 @@ public:
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;
};
diff --git a/sources/shiboken2/tests/libsample/nontypetemplate.h b/sources/shiboken2/tests/libsample/nontypetemplate.h
new file mode 100644
index 000000000..4e2100626
--- /dev/null
+++ b/sources/shiboken2/tests/libsample/nontypetemplate.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NONTYPETEMPLATE_H
+#define NONTYPETEMPLATE_H
+
+#include "libsamplemacros.h"
+
+#include <algorithm>
+#include <numeric>
+
+template <int Size> class IntArray
+{
+public:
+ 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];
+};
+
+typedef IntArray<2> IntArray2;
+typedef IntArray<3> IntArray3;
+
+#endif // NONTYPETEMPLATE_H
diff --git a/sources/shiboken2/tests/libsample/objecttype.cpp b/sources/shiboken2/tests/libsample/objecttype.cpp
index e09a92f47..f82b7cf0d 100644
--- a/sources/shiboken2/tests/libsample/objecttype.cpp
+++ b/sources/shiboken2/tests/libsample/objecttype.cpp
@@ -282,6 +282,7 @@ void ObjectType::callVirtualCreateChild()
ObjectType* fake_parent = new ObjectType();
ObjectType* fake_child = createChild(fake_parent);
assert(fake_child->isPython());
+ (void)fake_child;
delete fake_parent;
}
diff --git a/sources/shiboken2/tests/libsample/objecttype.h b/sources/shiboken2/tests/libsample/objecttype.h
index bcb4f3332..ecd67b684 100644
--- a/sources/shiboken2/tests/libsample/objecttype.h
+++ b/sources/shiboken2/tests/libsample/objecttype.h
@@ -63,7 +63,7 @@ private:
class ObjectTypeLayout;
class ObjectType;
-typedef std::list<ObjectType*> ObjectTypeList;
+using ObjectTypeList = std::list<ObjectType*>;
class LIBSAMPLE_API ObjectType
{
diff --git a/sources/shiboken2/tests/libsample/samplenamespace.cpp b/sources/shiboken2/tests/libsample/samplenamespace.cpp
index ec3da3dbf..e066869d2 100644
--- a/sources/shiboken2/tests/libsample/samplenamespace.cpp
+++ b/sources/shiboken2/tests/libsample/samplenamespace.cpp
@@ -36,6 +36,13 @@ using namespace std;
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)
{
diff --git a/sources/shiboken2/tests/libsample/samplenamespace.h b/sources/shiboken2/tests/libsample/samplenamespace.h
index 37a445e51..27fa11290 100644
--- a/sources/shiboken2/tests/libsample/samplenamespace.h
+++ b/sources/shiboken2/tests/libsample/samplenamespace.h
@@ -96,9 +96,11 @@ LIBSAMPLE_API void doSomethingWithArray(const unsigned char* data, unsigned int
LIBSAMPLE_API int enumItemAsDefaultValueToIntArgument(int value = ZeroIn);
-class SomeClass
+class LIBSAMPLE_API SomeClass
{
public:
+ enum class PublicScopedEnum { v1, v2 };
+
class SomeInnerClass
{
public:
@@ -131,6 +133,8 @@ protected:
ProtectedItem0,
ProtectedItem1
};
+
+ PublicScopedEnum protectedMethodReturningPublicScopedEnum() const;
};
class DerivedFromNamespace : public SomeClass::SomeInnerClass::OkThisIsRecursiveEnough
diff --git a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt
index b8b6417d1..ec674b56b 100644
--- a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt
@@ -15,7 +15,9 @@ ${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)
-add_custom_command(OUTPUT ${minimal_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${minimal_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${minimal_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -38,3 +40,4 @@ target_link_libraries(minimal
libminimal
${SBK_PYTHON_LIBRARIES}
libshiboken)
+create_generator_target(minimal)
diff --git a/sources/shiboken2/tests/otherbinding/CMakeLists.txt b/sources/shiboken2/tests/otherbinding/CMakeLists.txt
index 186766b41..0be66f797 100644
--- a/sources/shiboken2/tests/otherbinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/otherbinding/CMakeLists.txt
@@ -17,7 +17,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/other/other_module_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/other-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${other_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${other_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${other_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -48,4 +50,5 @@ target_link_libraries(other
libshiboken)
add_dependencies(other sample)
+create_generator_target(other)
diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt
index 32117e44a..7f4bec5f4 100644
--- a/sources/shiboken2/tests/samplebinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt
@@ -29,11 +29,14 @@ ${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
@@ -125,7 +128,9 @@ ${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)
-add_custom_command(OUTPUT ${sample_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${sample_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${sample_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -149,3 +154,4 @@ target_link_libraries(sample
libsample
${SBK_PYTHON_LIBRARIES}
libshiboken)
+create_generator_target(sample)
diff --git a/sources/shiboken2/tests/samplebinding/exception_test.py b/sources/shiboken2/tests/samplebinding/exception_test.py
new file mode 100644
index 000000000..d6c02433a
--- /dev/null
+++ b/sources/shiboken2/tests/samplebinding/exception_test.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+#
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import unittest
+
+from sample import ExceptionTest
+
+class CppExceptionTest(unittest.TestCase):
+
+ def testVoid(self):
+ exceptionCount = 0
+ et = ExceptionTest()
+
+ et.voidThrowStdException(False)
+
+ try:
+ et.voidThrowStdException(True)
+ except:
+ exceptionCount += 1
+
+ et.voidThrowInt(False)
+
+ try:
+ et.voidThrowInt(True)
+ except:
+ exceptionCount += 1
+
+ self.assertEqual(exceptionCount, 2)
+
+ def testReturnValue(self):
+ exceptionCount = 0
+ et = ExceptionTest()
+
+ result = et.intThrowStdException(False);
+
+ try:
+ result = et.intThrowStdException(True);
+ except:
+ exceptionCount += 1
+
+ result = et.intThrowInt(False);
+
+ try:
+ result = et.intThrowInt(True);
+ except:
+ exceptionCount += 1
+
+ self.assertEqual(exceptionCount, 2)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken2/tests/samplebinding/global.h b/sources/shiboken2/tests/samplebinding/global.h
index f2add93ff..3984102a8 100644
--- a/sources/shiboken2/tests/samplebinding/global.h
+++ b/sources/shiboken2/tests/samplebinding/global.h
@@ -37,8 +37,10 @@
#include "sbkdate.h"
#include "derived.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"
diff --git a/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py b/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py
new file mode 100644
index 000000000..9adfa2441
--- /dev/null
+++ b/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import unittest
+
+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)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
index 00052e881..9b967fc53 100644
--- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
@@ -520,6 +520,10 @@
<suppress-warning text="skipping function 'ClassWithFunctionPointer::callFunctionPointer', unmatched parameter type 'void (*)(void*)'" />
</value-type>
+ <value-type name="IntArray" generate="no"/>
+ <value-type name="IntArray2"/>
+ <value-type name="IntArray3"/>
+
<enum-type name="OverloadedFuncEnum"/>
<!-- BUG:
renaming the ICOverloadedFuncEnum to the same name
@@ -545,6 +549,7 @@
<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" />
@@ -1964,7 +1969,7 @@
<define-ownership owner="c++"/>
</modify-argument>
</modify-function>
- <modify-function signature="acceptSequence(const char*[])">
+ <modify-function signature="acceptSequence(const char*const[])">
<modify-argument index="1">
<replace-type modified-type="PySequence" />
<conversion-rule class="native">
@@ -2388,6 +2393,8 @@
<value-type name="Expression" />
+ <object-type name="ExceptionTest" exception-handling="auto-on"/>
+
<value-type name="ModelIndex" />
<value-type name="ReferentModelIndex">
<modify-function signature="operator const ModelIndex&amp;()const">
diff --git a/sources/shiboken2/tests/smartbinding/CMakeLists.txt b/sources/shiboken2/tests/smartbinding/CMakeLists.txt
index faaa797b6..43888fae2 100644
--- a/sources/shiboken2/tests/smartbinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/smartbinding/CMakeLists.txt
@@ -16,7 +16,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/smart/registry_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/smart-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${smart_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${smart_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${smart_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -40,3 +42,4 @@ target_link_libraries(smart
libsmart
${SBK_PYTHON_LIBRARIES}
libshiboken)
+create_generator_target(smart)
diff --git a/testing/wheel_tester.py b/testing/wheel_tester.py
new file mode 100644
index 000000000..60fd7a38a
--- /dev/null
+++ b/testing/wheel_tester.py
@@ -0,0 +1,295 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+"""
+This script is used by Coin (coin_test_instructions.py specifically) to
+test installation of generated wheels, and test building of the
+"buildable" examples samplebinding and scriptableapplication.
+
+It can also be invoked regularly from the command line via
+python testing/wheel_tester.py --qmake=some-value --cmake=some-value
+
+The qmake and cmake arguments can also be omitted, and they will be
+looked up in your PATH.
+
+Make sure that some generated wheels already exist in the dist/
+directory (e.g. setup.py bdist_wheel was already executed).
+"""
+
+import os, sys
+
+try:
+ this_file = __file__
+except NameError:
+ this_file = sys.argv[0]
+this_file = os.path.abspath(this_file)
+this_dir = os.path.dirname(this_file)
+setup_script_dir = os.path.abspath(os.path.join(this_dir, '..'))
+sys.path.append(setup_script_dir)
+
+from build_scripts.options import OPTION_QMAKE
+from build_scripts.options import OPTION_CMAKE
+
+from build_scripts.utils import find_files_using_glob
+from build_scripts.utils import find_glob_in_path
+from build_scripts.utils import run_process
+from build_scripts.utils import rmtree
+import distutils.log as log
+
+log.set_verbosity(1)
+
+
+def find_executable_qmake():
+ return find_executable('qmake', OPTION_QMAKE)
+
+
+def find_executable_cmake():
+ return find_executable('cmake', OPTION_CMAKE)
+
+
+def find_executable(executable, command_line_value):
+ value = command_line_value
+ option_str = '--{}'.format(executable)
+
+ if value:
+ log.info("{} option given: {}".format(option_str, value))
+ if not os.path.exists(value):
+ raise RuntimeError("No executable exists at: {}".format(value))
+ else:
+ log.info("No {} option given, trying to find {} in PATH.".format(option_str, executable))
+ paths = find_glob_in_path(executable)
+ log.info("{} executables found in PATH: {}".format(executable, paths))
+ if not paths:
+ raise RuntimeError(
+ "No {} option was specified and no {} was found "
+ "in PATH.".format(option_str, executable))
+ else:
+ value = paths[0]
+ log.info("Using {} found in PATH: {}".format(executable, value))
+ log.info("")
+ return value
+
+
+QMAKE_PATH = find_executable_qmake()
+CMAKE_PATH = find_executable_cmake()
+
+
+def get_wheels_dir():
+ return os.path.join(setup_script_dir, "dist")
+
+
+def get_examples_dir():
+ return os.path.join(setup_script_dir, "examples")
+
+
+def package_prefix_names():
+ return ["shiboken2", "shiboken2_generator", "PySide2"]
+
+
+def clean_egg_info():
+ # After a successful bdist_wheel build, some .egg-info directories
+ # are left over, which confuse pip when invoking it via
+ # python -m pip, making pip think that the packages are already
+ # installed in the root source directory.
+ # Clean up the .egg-info directories to fix this, it should be
+ # safe to do so.
+ paths = find_files_using_glob(setup_script_dir, "*.egg-info")
+ for p in paths:
+ log.info("Removing {}".format(p))
+ rmtree(p)
+
+
+def install_wheel(wheel_path):
+ log.info("Installing wheel: {}".format(wheel_path))
+ exit_code = run_process([sys.executable, "-m", "pip", "install", wheel_path])
+ log.info("")
+ if exit_code:
+ raise RuntimeError("Error while installing wheel {}".format(wheel_path))
+
+
+def try_install_wheels(wheels_dir, py_version):
+ clean_egg_info()
+ all_wheels_pattern = "*.whl"
+ all_wheels = find_files_using_glob(wheels_dir, all_wheels_pattern)
+
+ if len(all_wheels) > 1:
+ log.info("Found the following wheels in {}: ".format(wheels_dir))
+ for wheel in all_wheels:
+ log.info(wheel)
+ else:
+ log.info("No wheels found in {}".format(wheels_dir))
+ log.info("")
+
+ for p in package_prefix_names():
+ pattern = "{}-*cp{}*.whl".format(p, py_version)
+ files = find_files_using_glob(wheels_dir, pattern)
+ if files and len(files) == 1:
+ wheel_path = files[0]
+ install_wheel(wheel_path)
+ elif len(files) > 1:
+ raise RuntimeError("More than one wheel found for specific package and version.")
+ else:
+ raise RuntimeError("No wheels compatible with Python {} found "
+ "for testing.".format(py_version))
+
+
+def is_unix():
+ if sys.platform.startswith("linux") or sys.platform == "darwin":
+ return True
+ return False
+
+
+def generate_build_cmake():
+ args = [CMAKE_PATH]
+ if is_unix():
+ args.extend(["-G", "Unix Makefiles"])
+ else:
+ args.extend(["-G", "NMake Makefiles"])
+ args.append("-DCMAKE_BUILD_TYPE=Release")
+ args.append("-Dpython_interpreter={}".format(sys.executable))
+
+ # Specify prefix path so find_package(Qt5) works.
+ qmake_dir = os.path.abspath(os.path.join(os.path.dirname(QMAKE_PATH), ".."))
+ args.append("-DCMAKE_PREFIX_PATH={}".format(qmake_dir))
+
+ args.append("..")
+
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failure while running cmake.")
+ log.info("")
+
+
+def generate_build_qmake():
+ exit_code = run_process([QMAKE_PATH, "..", "python_interpreter={}".format(sys.executable)])
+ if exit_code:
+ raise RuntimeError("Failure while running qmake.")
+ log.info("")
+
+
+def run_make():
+ args = []
+ if is_unix():
+ executable = "make"
+ else:
+ executable = "nmake"
+ args.append(executable)
+
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failure while running {}.".format(executable))
+ log.info("")
+
+
+def run_make_install():
+ args = []
+ if is_unix():
+ executable = "make"
+ else:
+ executable = "nmake"
+ args.append(executable)
+ args.append("install")
+
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failed while running {} install.".format(executable))
+ log.info("")
+
+
+def execute_script(script_path):
+ args = [sys.executable, script_path]
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failure while executing script: {}".format(script_path))
+ log.info("")
+
+
+def prepare_build_folder(src_path, build_folder_name):
+ build_path = os.path.join(src_path, build_folder_name)
+
+ # The script can be called for both Python 2 and Python 3 wheels, so
+ # preparing a build folder should clean any previous existing build.
+ if os.path.exists(build_path):
+ log.info("Removing {}".format(build_path))
+ rmtree(build_path)
+
+ log.info("Creating {}".format(build_path))
+ os.makedirs(build_path)
+ os.chdir(build_path)
+
+
+def try_build_examples():
+ examples_dir = get_examples_dir()
+
+ log.info("Attempting to build and run samplebinding using cmake.")
+ src_path = os.path.join(examples_dir, "samplebinding")
+ prepare_build_folder(src_path, "cmake")
+ generate_build_cmake()
+ run_make()
+ run_make_install()
+ execute_script(os.path.join(src_path, "main.py"))
+
+ log.info("Attempting to build scriptableapplication using cmake.")
+ src_path = os.path.join(examples_dir, "scriptableapplication")
+ prepare_build_folder(src_path, "cmake")
+ generate_build_cmake()
+ run_make()
+
+ log.info("Attempting to build scriptableapplication using qmake.")
+ src_path = os.path.join(examples_dir, "scriptableapplication")
+ prepare_build_folder(src_path, "qmake")
+ generate_build_qmake()
+ run_make()
+
+
+def run_wheel_tests():
+ wheels_dir = get_wheels_dir()
+ py_version = sys.version_info[0]
+
+ log.info("Attempting to install wheels.\n")
+ try_install_wheels(wheels_dir, py_version)
+
+ log.info("Attempting to build examples.\n")
+ try_build_examples()
+
+ log.info("All tests passed!")
+
+
+if __name__ == "__main__":
+ run_wheel_tests()